Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
89
drivers/Kconfig
Normal file
89
drivers/Kconfig
Normal file
@@ -0,0 +1,89 @@
|
||||
# drivers/Kconfig
|
||||
|
||||
menu "Device Drivers"
|
||||
|
||||
source "drivers/base/Kconfig"
|
||||
|
||||
source "drivers/connector/Kconfig"
|
||||
|
||||
source "drivers/mtd/Kconfig"
|
||||
|
||||
source "drivers/parport/Kconfig"
|
||||
|
||||
source "drivers/pnp/Kconfig"
|
||||
|
||||
source "drivers/block/Kconfig"
|
||||
|
||||
# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4
|
||||
|
||||
source "drivers/misc/Kconfig"
|
||||
|
||||
source "drivers/ide/Kconfig"
|
||||
|
||||
source "drivers/scsi/Kconfig"
|
||||
|
||||
source "drivers/ata/Kconfig"
|
||||
|
||||
source "drivers/cdrom/Kconfig"
|
||||
|
||||
source "drivers/md/Kconfig"
|
||||
|
||||
source "drivers/message/fusion/Kconfig"
|
||||
|
||||
source "drivers/ieee1394/Kconfig"
|
||||
|
||||
source "drivers/message/i2o/Kconfig"
|
||||
|
||||
source "drivers/macintosh/Kconfig"
|
||||
|
||||
source "drivers/net/Kconfig"
|
||||
|
||||
source "drivers/isdn/Kconfig"
|
||||
|
||||
source "drivers/telephony/Kconfig"
|
||||
|
||||
# input before char - char/joystick depends on it. As does USB.
|
||||
|
||||
source "drivers/input/Kconfig"
|
||||
|
||||
source "drivers/char/Kconfig"
|
||||
|
||||
source "drivers/i2c/Kconfig"
|
||||
|
||||
source "drivers/spi/Kconfig"
|
||||
|
||||
source "drivers/w1/Kconfig"
|
||||
|
||||
source "drivers/hwmon/Kconfig"
|
||||
|
||||
source "drivers/mfd/Kconfig"
|
||||
|
||||
source "drivers/media/Kconfig"
|
||||
|
||||
source "drivers/video/Kconfig"
|
||||
|
||||
source "sound/Kconfig"
|
||||
|
||||
source "drivers/hid/Kconfig"
|
||||
|
||||
source "drivers/usb/Kconfig"
|
||||
|
||||
source "drivers/mmc/Kconfig"
|
||||
|
||||
source "drivers/leds/Kconfig"
|
||||
|
||||
source "drivers/infiniband/Kconfig"
|
||||
|
||||
source "drivers/edac/Kconfig"
|
||||
|
||||
source "drivers/rtc/Kconfig"
|
||||
|
||||
source "drivers/pwm/Kconfig"
|
||||
|
||||
source "drivers/dma/Kconfig"
|
||||
|
||||
source "drivers/auxdisplay/Kconfig"
|
||||
|
||||
source "drivers/kvm/Kconfig"
|
||||
|
||||
endmenu
|
||||
86
drivers/Makefile
Normal file
86
drivers/Makefile
Normal file
@@ -0,0 +1,86 @@
|
||||
#
|
||||
# Makefile for the Linux kernel device drivers.
|
||||
#
|
||||
# 15 Sep 2000, Christoph Hellwig <hch@infradead.org>
|
||||
# Rewritten to use lists instead of if-statements.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_PCI) += pci/
|
||||
obj-$(CONFIG_PARISC) += parisc/
|
||||
obj-$(CONFIG_RAPIDIO) += rapidio/
|
||||
obj-y += video/
|
||||
obj-$(CONFIG_ACPI) += acpi/
|
||||
# PnP must come after ACPI since it will eventually need to check if acpi
|
||||
# was used and do nothing if so
|
||||
obj-$(CONFIG_PNP) += pnp/
|
||||
obj-$(CONFIG_ARM_AMBA) += amba/
|
||||
|
||||
# char/ comes before serial/ etc so that the VT console is the boot-time
|
||||
# default.
|
||||
obj-y += char/
|
||||
|
||||
obj-$(CONFIG_CONNECTOR) += connector/
|
||||
|
||||
# i810fb and intelfb depend on char/agp/
|
||||
obj-$(CONFIG_FB_I810) += video/i810/
|
||||
obj-$(CONFIG_FB_INTEL) += video/intelfb/
|
||||
|
||||
obj-y += serial/
|
||||
obj-$(CONFIG_PARPORT) += parport/
|
||||
obj-y += base/ block/ misc/ mfd/ net/ media/
|
||||
obj-$(CONFIG_NUBUS) += nubus/
|
||||
obj-$(CONFIG_ATM) += atm/
|
||||
obj-y += macintosh/
|
||||
obj-$(CONFIG_IDE) += ide/
|
||||
obj-$(CONFIG_FC4) += fc4/
|
||||
obj-$(CONFIG_SCSI) += scsi/
|
||||
obj-$(CONFIG_ATA) += ata/
|
||||
obj-$(CONFIG_FUSION) += message/
|
||||
obj-$(CONFIG_IEEE1394) += ieee1394/
|
||||
obj-y += cdrom/
|
||||
obj-y += auxdisplay/
|
||||
obj-$(CONFIG_MTD) += mtd/
|
||||
obj-$(CONFIG_SPI) += spi/
|
||||
obj-$(CONFIG_PCCARD) += pcmcia/
|
||||
obj-$(CONFIG_DIO) += dio/
|
||||
obj-$(CONFIG_SBUS) += sbus/
|
||||
obj-$(CONFIG_KVM) += kvm/
|
||||
obj-$(CONFIG_ZORRO) += zorro/
|
||||
obj-$(CONFIG_MAC) += macintosh/
|
||||
obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
|
||||
obj-$(CONFIG_PARIDE) += block/paride/
|
||||
obj-$(CONFIG_TC) += tc/
|
||||
obj-$(CONFIG_USB) += usb/
|
||||
obj-$(CONFIG_PCI) += usb/
|
||||
obj-$(CONFIG_USB_GADGET) += usb/gadget/
|
||||
obj-$(CONFIG_SERIO) += input/serio/
|
||||
obj-$(CONFIG_GAMEPORT) += input/gameport/
|
||||
obj-$(CONFIG_INPUT) += input/
|
||||
obj-$(CONFIG_I2O) += message/
|
||||
obj-$(CONFIG_RTC_LIB) += rtc/
|
||||
obj-$(CONFIG_PWM) += pwm/
|
||||
obj-$(CONFIG_I2C) += i2c/
|
||||
obj-$(CONFIG_W1) += w1/
|
||||
obj-$(CONFIG_HWMON) += hwmon/
|
||||
obj-$(CONFIG_PHONE) += telephony/
|
||||
obj-$(CONFIG_MD) += md/
|
||||
obj-$(CONFIG_BT) += bluetooth/
|
||||
obj-$(CONFIG_ISDN) += isdn/
|
||||
obj-$(CONFIG_EDAC) += edac/
|
||||
obj-$(CONFIG_MCA) += mca/
|
||||
obj-$(CONFIG_EISA) += eisa/
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
obj-$(CONFIG_MMC) += mmc/
|
||||
obj-$(CONFIG_NEW_LEDS) += leds/
|
||||
obj-$(CONFIG_INFINIBAND) += infiniband/
|
||||
obj-$(CONFIG_IPATH_CORE) += infiniband/
|
||||
obj-$(CONFIG_SGI_SN) += sn/
|
||||
obj-y += firmware/
|
||||
obj-$(CONFIG_CRYPTO) += crypto/
|
||||
obj-$(CONFIG_SUPERH) += sh/
|
||||
obj-$(CONFIG_GENERIC_TIME) += clocksource/
|
||||
obj-$(CONFIG_DMA_ENGINE) += dma/
|
||||
obj-$(CONFIG_HID) += hid/
|
||||
obj-$(CONFIG_PPC_PS3) += ps3/
|
||||
obj-$(CONFIG_L3) += l3/
|
||||
obj-$(CONFIG_G3D) += g3d/
|
||||
1
drivers/acorn/README
Normal file
1
drivers/acorn/README
Normal file
@@ -0,0 +1 @@
|
||||
Drivers for the ACORN "podule" ARM specific bus.
|
||||
36
drivers/acorn/block/Kconfig
Normal file
36
drivers/acorn/block/Kconfig
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Block device driver configuration
|
||||
#
|
||||
|
||||
menu "Acorn-specific block devices"
|
||||
depends on ARCH_ARC || ARCH_A5K
|
||||
|
||||
config BLK_DEV_FD1772
|
||||
tristate "Old Archimedes floppy (1772) support"
|
||||
depends on ARCH_ARC || ARCH_A5K
|
||||
help
|
||||
Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
|
||||
R140 and R260) series of computers; it supports only 720K floppies
|
||||
at the moment. If you don't have one of these machines just answer
|
||||
N.
|
||||
|
||||
config BLK_DEV_MFM
|
||||
tristate "MFM harddisk support"
|
||||
depends on ARCH_ARC || ARCH_A5K
|
||||
help
|
||||
Support the MFM hard drives on the Acorn Archimedes both
|
||||
on-board the A4x0 motherboards and via the Acorn MFM podules.
|
||||
Drives up to 64MB are supported. If you haven't got one of these
|
||||
machines or drives just say N.
|
||||
|
||||
config BLK_DEV_MFM_AUTODETECT
|
||||
bool "Autodetect hard drive geometry"
|
||||
depends on BLK_DEV_MFM
|
||||
help
|
||||
If you answer Y, the MFM code will attempt to automatically detect
|
||||
the cylinders/heads/sectors count on your hard drive. WARNING: This
|
||||
sometimes doesn't work and it also does some dodgy stuff which
|
||||
potentially might damage your drive.
|
||||
|
||||
endmenu
|
||||
|
||||
9
drivers/acorn/block/Makefile
Normal file
9
drivers/acorn/block/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for the Acorn block device drivers.
|
||||
#
|
||||
|
||||
fd1772_mod-objs := fd1772.o fd1772dma.o
|
||||
mfmhd_mod-objs := mfmhd.o mfm.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_FD1772) += fd1772_mod.o
|
||||
obj-$(CONFIG_BLK_DEV_MFM) += mfmhd_mod.o
|
||||
1604
drivers/acorn/block/fd1772.c
Normal file
1604
drivers/acorn/block/fd1772.c
Normal file
File diff suppressed because it is too large
Load Diff
100
drivers/acorn/block/fd1772dma.S
Normal file
100
drivers/acorn/block/fd1772dma.S
Normal file
@@ -0,0 +1,100 @@
|
||||
#include <asm/hardware.h>
|
||||
|
||||
@ Code for DMA with the 1772 fdc
|
||||
.text
|
||||
|
||||
|
||||
.global fdc1772_dataaddr
|
||||
fdc1772_fiqdata:
|
||||
@ Number of bytes left to DMA
|
||||
.global fdc1772_bytestogo
|
||||
fdc1772_bytestogo:
|
||||
.word 0
|
||||
@ Place to put/get data from in DMA
|
||||
.global fdc1772_dataaddr
|
||||
fdc1772_dataaddr:
|
||||
.word 0
|
||||
|
||||
.global fdc1772_fdc_int_done
|
||||
fdc1772_fdc_int_done:
|
||||
.word 0
|
||||
.global fdc1772_comendstatus
|
||||
fdc1772_comendstatus:
|
||||
.word 0
|
||||
|
||||
@ We hang this off DMA channel 1
|
||||
.global fdc1772_comendhandler
|
||||
fdc1772_comendhandler:
|
||||
mov r8,#IOC_BASE
|
||||
ldrb r9,[r8,#0x34] @ IOC FIQ status
|
||||
tst r9,#2
|
||||
subeqs pc,r14,#4 @ should I leave a space here
|
||||
orr r9,r8,#0x10000 @ FDC base
|
||||
adr r8,fdc1772_fdc_int_done
|
||||
ldrb r10,[r9,#0] @ FDC status
|
||||
mov r9,#1 @ Got a FIQ flag
|
||||
stmia r8,{r9,r10}
|
||||
subs pc,r14,#4
|
||||
|
||||
|
||||
.global fdc1772_dma_read
|
||||
fdc1772_dma_read:
|
||||
mov r8,#IOC_BASE
|
||||
ldrb r9,[r8,#0x34] @ IOC FIQ status
|
||||
tst r9,#1
|
||||
beq fdc1772_dma_read_notours
|
||||
orr r8,r8,#0x10000 @ FDC base
|
||||
ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt)
|
||||
ldmia r11,{r8,r9}
|
||||
subs r8,r8,#1 @ One less byte to go
|
||||
@ If there was somewhere for this data to go then store it and update pointers
|
||||
strplb r10,[r9],#1 @ Store the data and increment the pointer
|
||||
stmplia r11,{r8,r9} @ Update count/pointers
|
||||
@ Handle any other interrupts if there are any
|
||||
fdc1772_dma_read_notours:
|
||||
@ Cant branch because this code has been copied down to the FIQ vector
|
||||
ldr pc,[pc,#-4]
|
||||
.word fdc1772_comendhandler
|
||||
.global fdc1772_dma_read_end
|
||||
fdc1772_dma_read_end:
|
||||
|
||||
.global fdc1772_dma_write
|
||||
fdc1772_dma_write:
|
||||
mov r8,#IOC_BASE
|
||||
ldrb r9,[r8,#0x34] @ IOC FIQ status
|
||||
tst r9,#1
|
||||
beq fdc1772_dma_write_notours
|
||||
orr r8,r8,#0x10000 @ FDC base
|
||||
ldmia r11,{r9,r10}
|
||||
subs r9,r9,#1 @ One less byte to go
|
||||
@ If there really is some data then get it, store it and update count
|
||||
ldrplb r12,[r10],#1
|
||||
strplb r12,[r8,#0xc] @ write it to FDC data reg
|
||||
stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt
|
||||
@ Handle any other interrupts
|
||||
fdc1772_dma_write_notours:
|
||||
@ Cant branch because this code has been copied down to the FIQ vector
|
||||
ldr pc,[pc,#-4]
|
||||
.word fdc1772_comendhandler
|
||||
|
||||
.global fdc1772_dma_write_end
|
||||
fdc1772_dma_write_end:
|
||||
|
||||
|
||||
@ Setup the FIQ R11 to point to the data and store the count, address
|
||||
@ for this dma
|
||||
@ R0=count
|
||||
@ R1=address
|
||||
.global fdc1772_setupdma
|
||||
fdc1772_setupdma:
|
||||
@ The big job is flipping in and out of FIQ mode
|
||||
adr r2,fdc1772_fiqdata @ This is what we really came here for
|
||||
stmia r2,{r0,r1}
|
||||
mov r3, pc
|
||||
teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode
|
||||
mov r0,r0 @ NOP
|
||||
mov r11,r2
|
||||
teqp r3,#0 @ Normal mode
|
||||
mov r0,r0 @ NOP
|
||||
mov pc,r14
|
||||
|
||||
162
drivers/acorn/block/mfm.S
Normal file
162
drivers/acorn/block/mfm.S
Normal file
@@ -0,0 +1,162 @@
|
||||
@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
|
||||
@ motherboard and on ST506 expansion podules.
|
||||
@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999
|
||||
|
||||
#include <asm/assembler.h>
|
||||
|
||||
hdc63463_irqdata:
|
||||
@ Controller base address
|
||||
.global hdc63463_baseaddress
|
||||
hdc63463_baseaddress:
|
||||
.word 0
|
||||
|
||||
.global hdc63463_irqpolladdress
|
||||
hdc63463_irqpolladdress:
|
||||
.word 0
|
||||
|
||||
.global hdc63463_irqpollmask
|
||||
hdc63463_irqpollmask:
|
||||
.word 0
|
||||
|
||||
@ where to read/write data from the kernel data space
|
||||
.global hdc63463_dataptr
|
||||
hdc63463_dataptr:
|
||||
.word 0
|
||||
|
||||
@ Number of bytes left to transfer
|
||||
.global hdc63463_dataleft
|
||||
hdc63463_dataleft:
|
||||
.word 0
|
||||
|
||||
@ -------------------------------------------------------------------------
|
||||
@ hdc63463_writedma: DMA from host to controller
|
||||
@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
|
||||
@ r3=data ptr, r4=data left, r5,r6=temporary
|
||||
.global hdc63463_writedma
|
||||
hdc63463_writedma:
|
||||
stmfd sp!,{r4-r7}
|
||||
adr r5,hdc63463_irqdata
|
||||
ldmia r5,{r0,r1,r2,r3,r4}
|
||||
|
||||
writedma_again:
|
||||
|
||||
@ test number of remaining bytes to transfer
|
||||
cmp r4,#0
|
||||
beq writedma_end
|
||||
bmi writedma_end
|
||||
|
||||
@ Check the hdc is interrupting
|
||||
ldrb r5,[r1,#0]
|
||||
tst r5,r2
|
||||
beq writedma_end
|
||||
|
||||
@ Transfer a block of upto 256 bytes
|
||||
cmp r4,#256
|
||||
movlt r7,r4
|
||||
movge r7,#256
|
||||
|
||||
@ Check the hdc is still busy and command has not ended and no errors
|
||||
ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status
|
||||
@ think we should continue DMA until it drops busy - perhaps this was
|
||||
@ the main problem with corrected errors causing a hang
|
||||
@tst r5,#0x3c00 @ Test for things which should be off
|
||||
@bne writedma_end
|
||||
and r5,r5,#0x8000 @ This is test for things which should be on: Busy
|
||||
cmp r5,#0x8000
|
||||
bne writedma_end
|
||||
|
||||
@ Bytes remaining at end
|
||||
sub r4,r4,r7
|
||||
|
||||
@ HDC Write register location
|
||||
add r0,r0,#32+8
|
||||
|
||||
writedma_loop:
|
||||
@ OK - pretty sure we should be doing this
|
||||
|
||||
ldr r5,[r3],#4 @ Get a word to be written
|
||||
@ get bottom half to be sent first
|
||||
mov r6,r5,lsl#16 @ Separate the first 2 bytes
|
||||
orr r2,r6,r6,lsr #16 @ Duplicate them in the bottom half of the word
|
||||
@ now the top half
|
||||
mov r6,r5,lsr#16 @ Get 2nd 2 bytes
|
||||
orr r6,r6,r6,lsl#16 @ Duplicate
|
||||
@str r6,[r0] @ to hdc
|
||||
stmia r0,{r2,r6}
|
||||
subs r7,r7,#4 @ Dec. number of bytes left
|
||||
bne writedma_loop
|
||||
|
||||
@ If we were too slow we had better go through again - DAG - took out with new interrupt routine
|
||||
@ sub r0,r0,#32+8
|
||||
@ adr r2,hdc63463_irqdata
|
||||
@ ldr r2,[r2,#8]
|
||||
@ b writedma_again
|
||||
|
||||
writedma_end:
|
||||
adr r5,hdc63463_irqdata+12
|
||||
stmia r5,{r3,r4}
|
||||
ldmfd sp!,{r4-r7}
|
||||
RETINSTR(mov,pc,lr)
|
||||
|
||||
@ -------------------------------------------------------------------------
|
||||
@ hdc63463_readdma: DMA from controller to host
|
||||
@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
|
||||
@ r3=data ptr, r4=data left, r5,r6=temporary
|
||||
.global hdc63463_readdma
|
||||
hdc63463_readdma:
|
||||
stmfd sp!,{r4-r7}
|
||||
adr r5,hdc63463_irqdata
|
||||
ldmia r5,{r0,r1,r2,r3,r4}
|
||||
|
||||
readdma_again:
|
||||
@ test number of remaining bytes to transfer
|
||||
cmp r4,#0
|
||||
beq readdma_end
|
||||
bmi readdma_end
|
||||
|
||||
@ Check the hdc is interrupting
|
||||
ldrb r5,[r1,#0]
|
||||
tst r5,r2
|
||||
beq readdma_end
|
||||
|
||||
@ Check the hdc is still busy and command has not ended and no errors
|
||||
ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status
|
||||
@ think we should continue DMA until it drops busy - perhaps this was
|
||||
@ the main problem with corrected errors causing a hang
|
||||
@tst r5,#0x3c00 @ Test for things which should be off
|
||||
@bne readdma_end
|
||||
and r5,r5,#0x8000 @ This is test for things which should be on: Busy
|
||||
cmp r5,#0x8000
|
||||
bne readdma_end
|
||||
|
||||
@ Transfer a block of upto 256 bytes
|
||||
cmp r4,#256
|
||||
movlt r7,r4
|
||||
movge r7,#256
|
||||
|
||||
@ Bytes remaining at end
|
||||
sub r4,r4,r7
|
||||
|
||||
@ Set a pointer to the data register in the HDC
|
||||
add r0,r0,#8
|
||||
readdma_loop:
|
||||
@ OK - pretty sure we should be doing this
|
||||
ldmia r0,{r5,r6}
|
||||
mov r5,r5,lsl#16
|
||||
mov r6,r6,lsl#16
|
||||
orr r6,r6,r5,lsr #16
|
||||
str r6,[r3],#4
|
||||
subs r7,r7,#4 @ Decrement bytes to go
|
||||
bne readdma_loop
|
||||
|
||||
@ Try reading multiple blocks - if this was fast enough then I do not think
|
||||
@ this should help - NO taken out DAG - new interrupt handler has
|
||||
@ non-consecutive memory blocks
|
||||
@ sub r0,r0,#8
|
||||
@ b readdma_again
|
||||
|
||||
readdma_end:
|
||||
adr r5,hdc63463_irqdata+12
|
||||
stmia r5,{r3,r4}
|
||||
ldmfd sp!,{r4-r7}
|
||||
RETINSTR(mov,pc,lr)
|
||||
1392
drivers/acorn/block/mfmhd.c
Normal file
1392
drivers/acorn/block/mfmhd.c
Normal file
File diff suppressed because it is too large
Load Diff
5
drivers/acorn/char/Makefile
Normal file
5
drivers/acorn/char/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for the acorn character device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o
|
||||
386
drivers/acorn/char/defkeymap-l7200.c
Normal file
386
drivers/acorn/char/defkeymap-l7200.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* linux/drivers/acorn/char/defkeymap-l7200.c
|
||||
*
|
||||
* Default keyboard maps for LinkUp Systems L7200 board
|
||||
*
|
||||
* Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
|
||||
*
|
||||
* Changelog:
|
||||
* 08-04-2000 SJH Created file
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/keyboard.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
/* Normal (maps 1:1 with no processing) */
|
||||
#define KTn 0xF0
|
||||
/* Function keys */
|
||||
#define KTf 0xF1
|
||||
/* Special (Performs special house-keeping funcs) */
|
||||
#define KTs 0xF2
|
||||
#define KIGNORE K(KTs, 0) /* Ignore */
|
||||
#define KENTER K(KTs, 1) /* Enter */
|
||||
#define KREGS K(KTs, 2) /* Regs */
|
||||
#define KMEM K(KTs, 3) /* Mem */
|
||||
#define KSTAT K(KTs, 4) /* State */
|
||||
#define KINTR K(KTs, 5) /* Intr */
|
||||
#define Ksl 6 /* Last console */
|
||||
#define KCAPSLK K(KTs, 7) /* Caps lock */
|
||||
#define KNUMLK K(KTs, 8) /* Num-lock */
|
||||
#define KSCRLLK K(KTs, 9) /* Scroll-lock */
|
||||
#define KSCRLFOR K(KTs,10) /* Scroll forward */
|
||||
#define KSCRLBAK K(KTs,11) /* Scroll back */
|
||||
#define KREBOOT K(KTs,12) /* Reboot */
|
||||
#define KCAPSON K(KTs,13) /* Caps on */
|
||||
#define KCOMPOSE K(KTs,14) /* Compose */
|
||||
#define KSAK K(KTs,15) /* SAK */
|
||||
#define CONS_DEC K(KTs,16) /* Dec console */
|
||||
#define CONS_INC K(KTs,17) /* Incr console */
|
||||
#define KFLOPPY K(KTs,18) /* Floppy */
|
||||
/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
|
||||
#define KTp 0xF3
|
||||
#define KPAD_0 K(KTp, 0 )
|
||||
#define KPAD_1 K(KTp, 1 )
|
||||
#define KPAD_2 K(KTp, 2 )
|
||||
#define KPAD_3 K(KTp, 3 )
|
||||
#define KPAD_4 K(KTp, 4 )
|
||||
#define KPAD_5 K(KTp, 5 )
|
||||
#define KPAD_6 K(KTp, 6 )
|
||||
#define KPAD_7 K(KTp, 7 )
|
||||
#define KPAD_8 K(KTp, 8 )
|
||||
#define KPAD_9 K(KTp, 9 )
|
||||
#define KPAD_PL K(KTp,10 )
|
||||
#define KPAD_MI K(KTp,11 )
|
||||
#define KPAD_ML K(KTp,12 )
|
||||
#define KPAD_DV K(KTp,13 )
|
||||
#define KPAD_EN K(KTp,14 )
|
||||
#define KPAD_DT K(KTp,16 )
|
||||
#define KPAD_HS K(KTp,20 )
|
||||
/* Console switching */
|
||||
#define KCn 0xF5
|
||||
/* Cursor */
|
||||
#define KTc 0xF6
|
||||
#define Kcd 0 /* Cursor down */
|
||||
#define Kcl 1 /* Cursor left */
|
||||
#define Kcr 2 /* Cursor right */
|
||||
#define Kcu 3 /* Cursor up */
|
||||
/* Shift/alt modifiers etc */
|
||||
#define KMd 0xF7
|
||||
#define KSHIFT K(KMd, 0 )
|
||||
#define KALTGR K(KMd, 1 )
|
||||
#define KCTRL K(KMd, 2 )
|
||||
#define KALT K(KMd, 3 )
|
||||
/* Meta */
|
||||
#define KMt 0xF8
|
||||
#define KAs 0xF9
|
||||
#define KPADA_0 K(KAs, 0 )
|
||||
#define KPADA_1 K(KAs, 1 )
|
||||
#define KPADA_2 K(KAs, 2 )
|
||||
#define KPADA_3 K(KAs, 3 )
|
||||
#define KPADA_4 K(KAs, 4 )
|
||||
#define KPADA_5 K(KAs, 5 )
|
||||
#define KPADA_6 K(KAs, 6 )
|
||||
#define KPADA_7 K(KAs, 7 )
|
||||
#define KPADA_8 K(KAs, 8 )
|
||||
#define KPADA_9 K(KAs, 9 )
|
||||
#define KPADB_0 K(KAs,10 )
|
||||
#define KPADB_1 K(KAs,11 )
|
||||
#define KPADB_2 K(KAs,12 )
|
||||
#define KPADB_3 K(KAs,13 )
|
||||
#define KPADB_4 K(KAs,14 )
|
||||
#define KPADB_5 K(KAs,15 )
|
||||
#define KPADB_6 K(KAs,16 )
|
||||
#define KPADB_7 K(KAs,17 )
|
||||
#define KPADB_8 K(KAs,18 )
|
||||
#define KPADB_9 K(KAs,19 )
|
||||
/* Locking keys */
|
||||
#define KLk 0xFA
|
||||
/* Letters */
|
||||
#define KTl 0xFB
|
||||
|
||||
/*
|
||||
* Here is the layout of the keys for the Fujitsu QWERTY
|
||||
* style keyboard:
|
||||
*
|
||||
* static char Fujitsu_Key_Table[] =
|
||||
* {
|
||||
* KALT, '`' , KNUL, KCTL, KFUN, KESC, '1' , '2' ,
|
||||
* '9' , '0' , '-' , '=' , KNUL, KBSP, KNUL, KNUL,
|
||||
* KNUL, KBSL, KSHF, KNUL, KNUL, KDEL, KNUL, 't' ,
|
||||
* 'y' , 'u' , 'i' , KRET, KSHF, KPGD, KNUL, KNUL,
|
||||
* KNUL, KTAB, KNUL, KNUL, KNUL, 'q' , 'w' , 'e' ,
|
||||
* 'r' , 'o' , 'p' , '[' , KNUL, ']' , KNUL, KNUL,
|
||||
* KNUL, 'z' , KNUL, KNUL, KNUL, KSHL, KNUL, KNUL,
|
||||
* 'k' , 'l' , ';' , KSQT, KNUL, KPGU, KNUL, KNUL,
|
||||
* KNUL, 'a' , KNUL, KNUL, KNUL, 's' , 'd' , 'f' ,
|
||||
* 'g' , 'h' , 'j' , '/' , KNUL, KHME, KNUL, KNUL,
|
||||
* KNUL, 'x' , KNUL, KNUL, KNUL, 'c' , 'v' , 'b' ,
|
||||
* 'n' , 'm' , ',' , '.' , KNUL, ' ' , KNUL, KNUL,
|
||||
* KNUL, KNUL, KNUL, KNUL, KNUL, '3' , '4' , '5' ,
|
||||
* '6' , '7' , '8' , KNUL, KPRG, KNUL, KEND, KNUL,
|
||||
* };
|
||||
*/
|
||||
|
||||
u_short plain_map[NR_KEYS]=
|
||||
{
|
||||
0xf703, 0xf060, 0xf200, 0xf702, 0xf200, 0xf01b, 0xf031, 0xf032,
|
||||
0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f, 0xf200, 0xf200,
|
||||
0xf200, 0xf05c, 0xf700, 0xf200, 0xf200, 0xf116, 0xf000, 0xfb74,
|
||||
0xfb79, 0xfb75, 0xfb69, 0xf201, 0xf700, 0xf600, 0xf200, 0xf200,
|
||||
0xf200, 0xf009, 0xf200, 0xf200, 0xf200, 0xfb71, 0xfb77, 0xfb65,
|
||||
0xfb72, 0xfb6f, 0xfb70, 0xf05b, 0xf200, 0xf05d, 0xf200, 0xf200,
|
||||
0xf200, 0xfb7a, 0xf200, 0xf200, 0xf200, 0xf207, 0xf200, 0xf200,
|
||||
0xfb6b, 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf603, 0xf200, 0xf200,
|
||||
0xf200, 0xfb61, 0xf200, 0xf200, 0xf200, 0xfb73, 0xfb64, 0xfb66,
|
||||
0xfb67, 0xfb68, 0xfb6a, 0xf02f, 0xf200, 0xf601, 0xf200, 0xf200,
|
||||
0xf200, 0xfb78, 0xf200, 0xf200, 0xf200, 0xfb63, 0xfb76, 0xfb62,
|
||||
0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf200, 0xf020, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf033, 0xf034, 0xf035,
|
||||
0xf036, 0xf037, 0xf038, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short shift_map[NR_KEYS]=
|
||||
{
|
||||
0xf703, 0xf07e, 0xf200, 0xf702, 0xf200, 0xf01b, 0xf021, 0xf040,
|
||||
0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f, 0xf200, 0xf200,
|
||||
0xf200, 0xf07c, 0xf700, 0xf200, 0xf200, 0xf116, 0xf000, 0xfb54,
|
||||
0xfb59, 0xfb55, 0xfb49, 0xf201, 0xf700, 0xf600, 0xf200, 0xf200,
|
||||
0xf200, 0xf009, 0xf200, 0xf200, 0xf200, 0xfb51, 0xfb57, 0xfb45,
|
||||
0xfb52, 0xfb4f, 0xfb50, 0xf07b, 0xf200, 0xf07d, 0xf200, 0xf200,
|
||||
0xf200, 0xfb5a, 0xf200, 0xf200, 0xf200, 0xf207, 0xf200, 0xf200,
|
||||
0xfb4b, 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf603, 0xf200, 0xf200,
|
||||
0xf200, 0xfb41, 0xf200, 0xf200, 0xf200, 0xfb53, 0xfb44, 0xfb46,
|
||||
0xfb47, 0xfb48, 0xfb4a, 0xf03f, 0xf200, 0xf601, 0xf200, 0xf200,
|
||||
0xf200, 0xfb58, 0xf200, 0xf200, 0xf200, 0xfb43, 0xfb56, 0xfb42,
|
||||
0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf200, 0xf020, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf023, 0xf024, 0xf025,
|
||||
0xf05e, 0xf026, 0xf02a, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short altgr_map[NR_KEYS]=
|
||||
{
|
||||
KIGNORE ,K(KCn,12 ),K(KCn,13 ),K(KCn,14 ),K(KCn,15 ),K(KCn,16 ),K(KCn,17 ),K(KCn, 18),
|
||||
K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22 ),K(KCn,23 ),KIGNORE ,KREGS ,KINTR ,
|
||||
KIGNORE ,KIGNORE ,K(KTn,'@'),KIGNORE ,K(KTn,'$'),KIGNORE ,KIGNORE ,K(KTn,'{'),
|
||||
K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
|
||||
K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTl,'q'),
|
||||
K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
|
||||
K(KTl,'p'),KIGNORE ,K(KTn,'~'),KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADB_7 ,
|
||||
KPADB_8 ,KPADB_9 ,KPAD_MI ,KCTRL ,K(KAs,20 ),K(KTl,'s'),K(KAs,23 ),K(KAs,25 ),
|
||||
K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE ,KIGNORE ,KENTER ,
|
||||
KPADB_4 ,KPADB_5 ,KPADB_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'),
|
||||
K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KSHIFT ,K(KTc,Kcu),KPADB_1 ,KPADB_2 ,KPADB_3 ,KCAPSLK ,KALT ,KIGNORE ,
|
||||
KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0 ,KPAD_DT ,KPAD_EN ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
};
|
||||
|
||||
u_short ctrl_map[NR_KEYS]=
|
||||
{
|
||||
0xf703, 0xf200, 0xf200, 0xf702, 0xf200, 0xf200, 0xf001, 0xf002,
|
||||
0xf009, 0xf000, 0xf031, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf200,
|
||||
0xf200, 0xf01c, 0xf700, 0xf200, 0xf200, 0xf116, 0xf000, 0xf020,
|
||||
0xf019, 0xf015, 0xf009, 0xf201, 0xf700, 0xf600, 0xf200, 0xf200,
|
||||
0xf200, 0xf009, 0xf200, 0xf200, 0xf200, 0xf011, 0xf017, 0xf005,
|
||||
0xf012, 0xf00f, 0xf010, 0xf01b, 0xf200, 0xf01d, 0xf200, 0xf200,
|
||||
0xf200, 0xf01a, 0xf200, 0xf200, 0xf200, 0xf207, 0xf200, 0xf200,
|
||||
0xf00b, 0xf00c, 0xf200, 0xf007, 0xf200, 0xf603, 0xf200, 0xf200,
|
||||
0xf200, 0xf001, 0xf200, 0xf200, 0xf200, 0xf001, 0xf013, 0xf006,
|
||||
0xf007, 0xf008, 0xf00a, 0xf07f, 0xf200, 0xf601, 0xf200, 0xf200,
|
||||
0xf200, 0xf018, 0xf200, 0xf200, 0xf200, 0xf003, 0xf016, 0xf002,
|
||||
0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b, 0xf01c, 0xf01d,
|
||||
0xf036, 0xf037, 0xf038, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
|
||||
};
|
||||
|
||||
u_short shift_ctrl_map[NR_KEYS]=
|
||||
{
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KFLOPPY ,KINTR ,
|
||||
KIGNORE ,KIGNORE ,K(KTn, 0 ),KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,K(KTn,31 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
|
||||
K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ),
|
||||
K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ),
|
||||
K(KTn,16 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
|
||||
KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ),
|
||||
K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER ,
|
||||
KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ),
|
||||
K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ),
|
||||
KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
};
|
||||
|
||||
u_short alt_map[NR_KEYS]=
|
||||
{
|
||||
K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
|
||||
K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KSCRLLK ,KINTR ,
|
||||
K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
|
||||
K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'<EFBFBD>'),K(KMt,127 ),K(KTf,21 ),
|
||||
K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KMt, 9 ),K(KMt,'q'),
|
||||
K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
|
||||
K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADA_7 ,
|
||||
KPADA_8 ,KPADA_9 ,KPAD_MI ,KCTRL ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
|
||||
K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
|
||||
KPADA_4 ,KPADA_5 ,KPADA_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,'z' ),K(KMt,'x'),
|
||||
K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE ,
|
||||
KSHIFT ,K(KTc,Kcu),KPADA_1 ,KPADA_2 ,KPADA_3 ,KCAPSLK ,KALT ,K(KMt,' '),
|
||||
KALTGR ,KCTRL ,CONS_DEC ,K(KTc,Kcd ),CONS_INC ,KPADA_0 ,KPAD_DT ,KPAD_EN ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
};
|
||||
|
||||
u_short ctrl_alt_map[NR_KEYS]=
|
||||
{
|
||||
KIGNORE ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
|
||||
K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KIGNORE ,KINTR ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
|
||||
K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KMt,17 ),
|
||||
K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20 ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9 ),K(KMt,15 ),
|
||||
K(KMt,16 ),KIGNORE ,KIGNORE ,KIGNORE ,KREBOOT ,K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
|
||||
KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4 ),K(KMt, 6 ),
|
||||
K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11 ),K(KMt,12 ),KIGNORE ,KIGNORE ,KENTER ,
|
||||
KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,26 ),K(KMt,24 ),
|
||||
K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14 ),K(KMt,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,KIGNORE ,
|
||||
KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KREBOOT ,KPAD_EN ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
|
||||
};
|
||||
|
||||
ushort *key_maps[MAX_NR_KEYMAPS] = {
|
||||
plain_map, shift_map, altgr_map, 0,
|
||||
ctrl_map, shift_ctrl_map, 0, 0,
|
||||
alt_map, 0, 0, 0,
|
||||
ctrl_alt_map, 0
|
||||
};
|
||||
|
||||
unsigned int keymap_count = 7;
|
||||
|
||||
/*
|
||||
* Philosophy: most people do not define more strings, but they who do
|
||||
* often want quite a lot of string space. So, we statically allocate
|
||||
* the default and allocate dynamically in chunks of 512 bytes.
|
||||
*/
|
||||
|
||||
char func_buf[] = {
|
||||
'\033', '[', '[', 'A', 0,
|
||||
'\033', '[', '[', 'B', 0,
|
||||
'\033', '[', '[', 'C', 0,
|
||||
'\033', '[', '[', 'D', 0,
|
||||
'\033', '[', '[', 'E', 0,
|
||||
'\033', '[', '1', '7', '~', 0,
|
||||
'\033', '[', '1', '8', '~', 0,
|
||||
'\033', '[', '1', '9', '~', 0,
|
||||
'\033', '[', '2', '0', '~', 0,
|
||||
'\033', '[', '2', '1', '~', 0,
|
||||
'\033', '[', '2', '3', '~', 0,
|
||||
'\033', '[', '2', '4', '~', 0,
|
||||
'\033', '[', '2', '5', '~', 0,
|
||||
'\033', '[', '2', '6', '~', 0,
|
||||
'\033', '[', '2', '8', '~', 0,
|
||||
'\033', '[', '2', '9', '~', 0,
|
||||
'\033', '[', '3', '1', '~', 0,
|
||||
'\033', '[', '3', '2', '~', 0,
|
||||
'\033', '[', '3', '3', '~', 0,
|
||||
'\033', '[', '3', '4', '~', 0,
|
||||
'\033', '[', '1', '~', 0,
|
||||
'\033', '[', '2', '~', 0,
|
||||
'\033', '[', '3', '~', 0,
|
||||
'\033', '[', '4', '~', 0,
|
||||
'\033', '[', '5', '~', 0,
|
||||
'\033', '[', '6', '~', 0,
|
||||
'\033', '[', 'M', 0,
|
||||
'\033', '[', 'P', 0,
|
||||
};
|
||||
|
||||
char *funcbufptr = func_buf;
|
||||
int funcbufsize = sizeof(func_buf);
|
||||
int funcbufleft = 0; /* space left */
|
||||
|
||||
char *func_table[MAX_NR_FUNC] = {
|
||||
func_buf + 0,
|
||||
func_buf + 5,
|
||||
func_buf + 10,
|
||||
func_buf + 15,
|
||||
func_buf + 20,
|
||||
func_buf + 25,
|
||||
func_buf + 31,
|
||||
func_buf + 37,
|
||||
func_buf + 43,
|
||||
func_buf + 49,
|
||||
func_buf + 55,
|
||||
func_buf + 61,
|
||||
func_buf + 67,
|
||||
func_buf + 73,
|
||||
func_buf + 79,
|
||||
func_buf + 85,
|
||||
func_buf + 91,
|
||||
func_buf + 97,
|
||||
func_buf + 103,
|
||||
func_buf + 109,
|
||||
func_buf + 115,
|
||||
func_buf + 120,
|
||||
func_buf + 125,
|
||||
func_buf + 130,
|
||||
func_buf + 135,
|
||||
func_buf + 140,
|
||||
func_buf + 145,
|
||||
0,
|
||||
0,
|
||||
func_buf + 149,
|
||||
0,
|
||||
};
|
||||
|
||||
struct kbdiacr accent_table[MAX_DIACR] = {
|
||||
{'`', 'A', '\300'}, {'`', 'a', '\340'},
|
||||
{'\'', 'A', '\301'}, {'\'', 'a', '\341'},
|
||||
{'^', 'A', '\302'}, {'^', 'a', '\342'},
|
||||
{'~', 'A', '\303'}, {'~', 'a', '\343'},
|
||||
{'"', 'A', '\304'}, {'"', 'a', '\344'},
|
||||
{'O', 'A', '\305'}, {'o', 'a', '\345'},
|
||||
{'0', 'A', '\305'}, {'0', 'a', '\345'},
|
||||
{'A', 'A', '\305'}, {'a', 'a', '\345'},
|
||||
{'A', 'E', '\306'}, {'a', 'e', '\346'},
|
||||
{',', 'C', '\307'}, {',', 'c', '\347'},
|
||||
{'`', 'E', '\310'}, {'`', 'e', '\350'},
|
||||
{'\'', 'E', '\311'}, {'\'', 'e', '\351'},
|
||||
{'^', 'E', '\312'}, {'^', 'e', '\352'},
|
||||
{'"', 'E', '\313'}, {'"', 'e', '\353'},
|
||||
{'`', 'I', '\314'}, {'`', 'i', '\354'},
|
||||
{'\'', 'I', '\315'}, {'\'', 'i', '\355'},
|
||||
{'^', 'I', '\316'}, {'^', 'i', '\356'},
|
||||
{'"', 'I', '\317'}, {'"', 'i', '\357'},
|
||||
{'-', 'D', '\320'}, {'-', 'd', '\360'},
|
||||
{'~', 'N', '\321'}, {'~', 'n', '\361'},
|
||||
{'`', 'O', '\322'}, {'`', 'o', '\362'},
|
||||
{'\'', 'O', '\323'}, {'\'', 'o', '\363'},
|
||||
{'^', 'O', '\324'}, {'^', 'o', '\364'},
|
||||
{'~', 'O', '\325'}, {'~', 'o', '\365'},
|
||||
{'"', 'O', '\326'}, {'"', 'o', '\366'},
|
||||
{'/', 'O', '\330'}, {'/', 'o', '\370'},
|
||||
{'`', 'U', '\331'}, {'`', 'u', '\371'},
|
||||
{'\'', 'U', '\332'}, {'\'', 'u', '\372'},
|
||||
{'^', 'U', '\333'}, {'^', 'u', '\373'},
|
||||
{'"', 'U', '\334'}, {'"', 'u', '\374'},
|
||||
{'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
|
||||
{'T', 'H', '\336'}, {'t', 'h', '\376'},
|
||||
{'s', 's', '\337'}, {'"', 'y', '\377'},
|
||||
{'s', 'z', '\337'}, {'i', 'j', '\377'},
|
||||
};
|
||||
|
||||
unsigned int accent_table_size = 68;
|
||||
401
drivers/acpi/Kconfig
Normal file
401
drivers/acpi/Kconfig
Normal file
@@ -0,0 +1,401 @@
|
||||
#
|
||||
# ACPI Configuration
|
||||
#
|
||||
|
||||
menu "ACPI (Advanced Configuration and Power Interface) Support"
|
||||
depends on !X86_NUMAQ
|
||||
depends on !X86_VISWS
|
||||
depends on !IA64_HP_SIM
|
||||
depends on IA64 || X86
|
||||
depends on PM
|
||||
|
||||
config ACPI
|
||||
bool "ACPI Support"
|
||||
depends on IA64 || X86
|
||||
depends on PCI
|
||||
depends on PM
|
||||
select PNP
|
||||
default y
|
||||
---help---
|
||||
Advanced Configuration and Power Interface (ACPI) support for
|
||||
Linux requires an ACPI compliant platform (hardware/firmware),
|
||||
and assumes the presence of OS-directed configuration and power
|
||||
management (OSPM) software. This option will enlarge your
|
||||
kernel by about 70K.
|
||||
|
||||
Linux ACPI provides a robust functional replacement for several
|
||||
legacy configuration and power management interfaces, including
|
||||
the Plug-and-Play BIOS specification (PnP BIOS), the
|
||||
MultiProcessor Specification (MPS), and the Advanced Power
|
||||
Management (APM) specification. If both ACPI and APM support
|
||||
are configured, whichever is loaded first shall be used.
|
||||
|
||||
The ACPI SourceForge project contains the latest source code,
|
||||
documentation, tools, mailing list subscription, and other
|
||||
information. This project is available at:
|
||||
<http://sourceforge.net/projects/acpi>
|
||||
|
||||
Linux support for ACPI is based on Intel Corporation's ACPI
|
||||
Component Architecture (ACPI CA). For more information see:
|
||||
<http://developer.intel.com/technology/iapc/acpi>
|
||||
|
||||
ACPI is an open industry specification co-developed by Compaq,
|
||||
Intel, Microsoft, Phoenix, and Toshiba. The specification is
|
||||
available at:
|
||||
<http://www.acpi.info>
|
||||
|
||||
if ACPI
|
||||
|
||||
config ACPI_SLEEP
|
||||
bool "Sleep States"
|
||||
depends on X86 && (!SMP || SUSPEND_SMP)
|
||||
depends on PM
|
||||
default y
|
||||
---help---
|
||||
This option adds support for ACPI suspend states.
|
||||
|
||||
With this option, you will be able to put the system "to sleep".
|
||||
Sleep states are low power states for the system and devices. All
|
||||
of the system operating state is saved to either memory or disk
|
||||
(depending on the state), to allow the system to resume operation
|
||||
quickly at your request.
|
||||
|
||||
Although this option sounds really nifty, barely any of the device
|
||||
drivers have been converted to the new driver model and hence few
|
||||
have proper power management support.
|
||||
|
||||
This option is not recommended for anyone except those doing driver
|
||||
power management development.
|
||||
|
||||
config ACPI_SLEEP_PROC_FS
|
||||
bool
|
||||
depends on ACPI_SLEEP && PROC_FS
|
||||
default y
|
||||
|
||||
config ACPI_SLEEP_PROC_SLEEP
|
||||
bool "/proc/acpi/sleep (deprecated)"
|
||||
depends on ACPI_SLEEP_PROC_FS
|
||||
default n
|
||||
---help---
|
||||
Create /proc/acpi/sleep
|
||||
Deprecated by /sys/power/state
|
||||
|
||||
config ACPI_PROCFS
|
||||
bool "Procfs interface (deprecated)"
|
||||
depends on ACPI
|
||||
default y
|
||||
---help---
|
||||
Procfs interface for ACPI is made optional for back-compatible.
|
||||
As the same functions are duplicated in sysfs interface
|
||||
and this proc interface will be removed some time later,
|
||||
it's marked as deprecated.
|
||||
( /proc/acpi/debug_layer && debug_level are deprecated by
|
||||
/sys/module/acpi/parameters/debug_layer && debug_level.
|
||||
/proc/acpi/info is deprecated by
|
||||
/sys/module/acpi/parameters/acpica_version )
|
||||
|
||||
config ACPI_AC
|
||||
tristate "AC Adapter"
|
||||
depends on X86
|
||||
default y
|
||||
help
|
||||
This driver adds support for the AC Adapter object, which indicates
|
||||
whether a system is on AC, or not. If you have a system that can
|
||||
switch between A/C and battery, say Y.
|
||||
|
||||
config ACPI_BATTERY
|
||||
tristate "Battery"
|
||||
depends on X86
|
||||
default y
|
||||
help
|
||||
This driver adds support for battery information through
|
||||
/proc/acpi/battery. If you have a mobile system with a battery,
|
||||
say Y.
|
||||
|
||||
config ACPI_BUTTON
|
||||
tristate "Button"
|
||||
depends on INPUT
|
||||
default y
|
||||
help
|
||||
This driver handles events on the power, sleep and lid buttons.
|
||||
A daemon reads /proc/acpi/event and perform user-defined actions
|
||||
such as shutting down the system. This is necessary for
|
||||
software controlled poweroff.
|
||||
|
||||
config ACPI_VIDEO
|
||||
tristate "Video"
|
||||
depends on X86 && BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
This driver implement the ACPI Extensions For Display Adapters
|
||||
for integrated graphics devices on motherboard, as specified in
|
||||
ACPI 2.0 Specification, Appendix B, allowing to perform some basic
|
||||
control like defining the video POST device, retrieving EDID information
|
||||
or to setup a video output, etc.
|
||||
Note that this is an ref. implementation only. It may or may not work
|
||||
for your integrated video device.
|
||||
|
||||
config ACPI_FAN
|
||||
tristate "Fan"
|
||||
default y
|
||||
help
|
||||
This driver adds support for ACPI fan devices, allowing user-mode
|
||||
applications to perform basic fan control (on, off, status).
|
||||
|
||||
config ACPI_DOCK
|
||||
tristate "Dock"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
This driver adds support for ACPI controlled docking stations
|
||||
|
||||
config ACPI_BAY
|
||||
tristate "Removable Drive Bay (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
depends on ACPI_DOCK
|
||||
help
|
||||
This driver adds support for ACPI controlled removable drive
|
||||
bays such as the IBM ultrabay or the Dell Module Bay.
|
||||
|
||||
config ACPI_PROCESSOR
|
||||
tristate "Processor"
|
||||
default y
|
||||
help
|
||||
This driver installs ACPI as the idle handler for Linux, and uses
|
||||
ACPI C2 and C3 processor states to save power, on systems that
|
||||
support it. It is required by several flavors of cpufreq
|
||||
Performance-state drivers.
|
||||
|
||||
config ACPI_HOTPLUG_CPU
|
||||
bool
|
||||
depends on ACPI_PROCESSOR && HOTPLUG_CPU
|
||||
select ACPI_CONTAINER
|
||||
default y
|
||||
|
||||
config ACPI_THERMAL
|
||||
tristate "Thermal Zone"
|
||||
depends on ACPI_PROCESSOR
|
||||
default y
|
||||
help
|
||||
This driver adds support for ACPI thermal zones. Most mobile and
|
||||
some desktop systems support ACPI thermal zones. It is HIGHLY
|
||||
recommended that this option be enabled, as your processor(s)
|
||||
may be damaged without it.
|
||||
|
||||
config ACPI_NUMA
|
||||
bool "NUMA support"
|
||||
depends on NUMA
|
||||
depends on (X86 || IA64)
|
||||
default y if IA64_GENERIC || IA64_SGI_SN2
|
||||
|
||||
config ACPI_ASUS
|
||||
tristate "ASUS/Medion Laptop Extras"
|
||||
depends on X86
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver provides support for extra features of ACPI-compatible
|
||||
ASUS laptops. As some of Medion laptops are made by ASUS, it may also
|
||||
support some Medion laptops (such as 9675 for example). It makes all
|
||||
the extra buttons generate standard ACPI events that go through
|
||||
/proc/acpi/events, and (on some models) adds support for changing the
|
||||
display brightness and output, switching the LCD backlight on and off,
|
||||
and most importantly, allows you to blink those fancy LEDs intended
|
||||
for reporting mail and wireless status.
|
||||
|
||||
Note: display switching code is currently considered EXPERIMENTAL,
|
||||
toying with these values may even lock your machine.
|
||||
|
||||
All settings are changed via /proc/acpi/asus directory entries. Owner
|
||||
and group for these entries can be set with asus_uid and asus_gid
|
||||
parameters.
|
||||
|
||||
More information and a userspace daemon for handling the extra buttons
|
||||
at <http://sourceforge.net/projects/acpi4asus/>.
|
||||
|
||||
If you have an ACPI-compatible ASUS laptop, say Y or M here. This
|
||||
driver is still under development, so if your laptop is unsupported or
|
||||
something works not quite as expected, please use the mailing list
|
||||
available on the above page (acpi4asus-user@lists.sourceforge.net).
|
||||
|
||||
NOTE: This driver is deprecated and will probably be removed soon,
|
||||
use asus-laptop instead.
|
||||
|
||||
config ACPI_IBM
|
||||
tristate "IBM ThinkPad Laptop Extras"
|
||||
depends on X86
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
|
||||
support for Fn-Fx key combinations, Bluetooth control, video
|
||||
output switching, ThinkLight control, UltraBay eject and more.
|
||||
For more information about this driver see <file:Documentation/ibm-acpi.txt>
|
||||
and <http://ibm-acpi.sf.net/> .
|
||||
|
||||
If you have an IBM ThinkPad laptop, say Y or M here.
|
||||
|
||||
config ACPI_IBM_DOCK
|
||||
bool "Legacy Docking Station Support"
|
||||
depends on ACPI_IBM
|
||||
depends on ACPI_DOCK=n
|
||||
default n
|
||||
---help---
|
||||
Allows the ibm_acpi driver to handle docking station events.
|
||||
This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI. It will
|
||||
allow locking and removing the laptop from the docking station,
|
||||
but will not properly connect PCI devices.
|
||||
|
||||
If you are not sure, say N here.
|
||||
|
||||
config ACPI_IBM_BAY
|
||||
bool "Legacy Removable Bay Support"
|
||||
depends on ACPI_IBM
|
||||
default y
|
||||
---help---
|
||||
Allows the ibm_acpi driver to handle removable bays. It will allow
|
||||
disabling the device in the bay, and also generate notifications when
|
||||
the bay lever is ejected or inserted.
|
||||
|
||||
If you are not sure, say Y here.
|
||||
|
||||
config ACPI_TOSHIBA
|
||||
tristate "Toshiba Laptop Extras"
|
||||
depends on X86
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver adds support for access to certain system settings
|
||||
on "legacy free" Toshiba laptops. These laptops can be recognized by
|
||||
their lack of a BIOS setup menu and APM support.
|
||||
|
||||
On these machines, all system configuration is handled through the
|
||||
ACPI. This driver is required for access to controls not covered
|
||||
by the general ACPI drivers, such as LCD brightness, video output,
|
||||
etc.
|
||||
|
||||
This driver differs from the non-ACPI Toshiba laptop driver (located
|
||||
under "Processor type and features") in several aspects.
|
||||
Configuration is accessed by reading and writing text files in the
|
||||
/proc tree instead of by program interface to /dev. Furthermore, no
|
||||
power management functions are exposed, as those are handled by the
|
||||
general ACPI drivers.
|
||||
|
||||
More information about this driver is available at
|
||||
<http://memebeam.org/toys/ToshibaAcpiDriver>.
|
||||
|
||||
If you have a legacy free Toshiba laptop (such as the Libretto L1
|
||||
series), say Y.
|
||||
|
||||
config ACPI_CUSTOM_DSDT
|
||||
bool "Include Custom DSDT"
|
||||
depends on !STANDALONE
|
||||
default n
|
||||
help
|
||||
This option is to load a custom ACPI DSDT
|
||||
If you don't know what that is, say N.
|
||||
|
||||
config ACPI_CUSTOM_DSDT_FILE
|
||||
string "Custom DSDT Table file to include"
|
||||
depends on ACPI_CUSTOM_DSDT
|
||||
default ""
|
||||
help
|
||||
Enter the full path name to the file which includes the AmlCode
|
||||
declaration.
|
||||
|
||||
config ACPI_BLACKLIST_YEAR
|
||||
int "Disable ACPI for systems before Jan 1st this year" if X86_32
|
||||
default 0
|
||||
help
|
||||
enter a 4-digit year, eg. 2001 to disable ACPI by default
|
||||
on platforms with DMI BIOS date before January 1st that year.
|
||||
"acpi=force" can be used to override this mechanism.
|
||||
|
||||
Enter 0 to disable this mechanism and allow ACPI to
|
||||
run by default no matter what the year. (default)
|
||||
|
||||
config ACPI_DEBUG
|
||||
bool "Debug Statements"
|
||||
default n
|
||||
help
|
||||
The ACPI driver can optionally report errors with a great deal
|
||||
of verbosity. Saying Y enables these statements. This will increase
|
||||
your kernel size by around 50K.
|
||||
|
||||
config ACPI_EC
|
||||
bool
|
||||
default y
|
||||
help
|
||||
This driver is required on some systems for the proper operation of
|
||||
the battery and thermal drivers. If you are compiling for a
|
||||
mobile system, say Y.
|
||||
|
||||
config ACPI_POWER
|
||||
bool
|
||||
default y
|
||||
|
||||
config ACPI_SYSTEM
|
||||
bool
|
||||
default y
|
||||
help
|
||||
This driver will enable your system to shut down using ACPI, and
|
||||
dump your ACPI DSDT table using /proc/acpi/dsdt.
|
||||
|
||||
config X86_PM_TIMER
|
||||
bool "Power Management Timer Support" if EMBEDDED
|
||||
depends on X86
|
||||
default y
|
||||
help
|
||||
The Power Management Timer is available on all ACPI-capable,
|
||||
in most cases even if ACPI is unusable or blacklisted.
|
||||
|
||||
This timing source is not affected by power management features
|
||||
like aggressive processor idling, throttling, frequency and/or
|
||||
voltage scaling, unlike the commonly used Time Stamp Counter
|
||||
(TSC) timing source.
|
||||
|
||||
You should nearly always say Y here because many modern
|
||||
systems require this timer.
|
||||
|
||||
config ACPI_CONTAINER
|
||||
tristate "ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
|
||||
---help---
|
||||
This allows _physical_ insertion and removal of CPUs and memory.
|
||||
This can be useful, for example, on NUMA machines that support
|
||||
ACPI based physical hotplug of nodes, or non-NUMA machines that
|
||||
support physical cpu/memory hot-plug.
|
||||
|
||||
If one selects "m", this driver can be loaded with
|
||||
"modprobe acpi_container".
|
||||
|
||||
config ACPI_HOTPLUG_MEMORY
|
||||
tristate "Memory Hotplug"
|
||||
depends on ACPI
|
||||
depends on MEMORY_HOTPLUG
|
||||
default n
|
||||
help
|
||||
This driver adds supports for ACPI Memory Hotplug. This driver
|
||||
provides support for fielding notifications on ACPI memory
|
||||
devices (PNP0C80) which represent memory ranges that may be
|
||||
onlined or offlined during runtime.
|
||||
|
||||
Enabling this driver assumes that your platform hardware
|
||||
and firmware have support for hot-plugging physical memory. If
|
||||
your system does not support physically adding or ripping out
|
||||
memory DIMMs at some platform defined granularity (individually
|
||||
or as a bank) at runtime, then you need not enable this driver.
|
||||
|
||||
If one selects "m," this driver can be loaded using the following
|
||||
command:
|
||||
$>modprobe acpi_memhotplug
|
||||
|
||||
config ACPI_SBS
|
||||
tristate "Smart Battery System (EXPERIMENTAL)"
|
||||
depends on X86 && I2C
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
This driver adds support for the Smart Battery System.
|
||||
Depends on I2C (Device Drivers ---> I2C support)
|
||||
A "Smart Battery" is quite old and quite rare compared
|
||||
to today's ACPI "Control Method" battery.
|
||||
|
||||
endif # ACPI
|
||||
|
||||
endmenu
|
||||
62
drivers/acpi/Makefile
Normal file
62
drivers/acpi/Makefile
Normal file
@@ -0,0 +1,62 @@
|
||||
#
|
||||
# Makefile for the Linux ACPI interpreter
|
||||
#
|
||||
|
||||
export ACPI_CFLAGS
|
||||
|
||||
ACPI_CFLAGS := -Os
|
||||
|
||||
ifdef CONFIG_ACPI_DEBUG
|
||||
ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS += $(ACPI_CFLAGS)
|
||||
|
||||
#
|
||||
# ACPI Boot-Time Table Parsing
|
||||
#
|
||||
obj-y += tables.o
|
||||
obj-$(CONFIG_X86) += blacklist.o
|
||||
|
||||
#
|
||||
# ACPI Core Subsystem (Interpreter)
|
||||
#
|
||||
obj-y += osl.o utils.o \
|
||||
dispatcher/ events/ executer/ hardware/ \
|
||||
namespace/ parser/ resources/ tables/ \
|
||||
utilities/
|
||||
|
||||
#
|
||||
# ACPI Bus and Device Drivers
|
||||
#
|
||||
processor-objs += processor_core.o processor_throttling.o \
|
||||
processor_idle.o processor_thermal.o
|
||||
ifdef CONFIG_CPU_FREQ
|
||||
processor-objs += processor_perflib.o
|
||||
endif
|
||||
|
||||
obj-y += sleep/
|
||||
obj-y += bus.o glue.o
|
||||
obj-y += scan.o
|
||||
obj-$(CONFIG_ACPI_AC) += ac.o
|
||||
obj-$(CONFIG_ACPI_BATTERY) += battery.o
|
||||
obj-$(CONFIG_ACPI_BUTTON) += button.o
|
||||
obj-$(CONFIG_ACPI_EC) += ec.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
obj-$(CONFIG_ACPI_DOCK) += dock.o
|
||||
obj-$(CONFIG_ACPI_BAY) += bay.o
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
|
||||
obj-$(CONFIG_ACPI_POWER) += power.o
|
||||
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
|
||||
obj-$(CONFIG_ACPI_CONTAINER) += container.o
|
||||
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
|
||||
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
|
||||
obj-$(CONFIG_ACPI_DEBUG) += debug.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += numa.o
|
||||
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
|
||||
obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
|
||||
obj-y += cm_sbs.o
|
||||
obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
|
||||
313
drivers/acpi/ac.c
Normal file
313
drivers/acpi/ac.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* acpi_ac.c - ACPI AC Adapter Driver ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||
* 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.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define ACPI_AC_COMPONENT 0x00020000
|
||||
#define ACPI_AC_CLASS "ac_adapter"
|
||||
#define ACPI_AC_HID "ACPI0003"
|
||||
#define ACPI_AC_DEVICE_NAME "AC Adapter"
|
||||
#define ACPI_AC_FILE_STATE "state"
|
||||
#define ACPI_AC_NOTIFY_STATUS 0x80
|
||||
#define ACPI_AC_STATUS_OFFLINE 0x00
|
||||
#define ACPI_AC_STATUS_ONLINE 0x01
|
||||
#define ACPI_AC_STATUS_UNKNOWN 0xFF
|
||||
|
||||
#define _COMPONENT ACPI_AC_COMPONENT
|
||||
ACPI_MODULE_NAME("ac");
|
||||
|
||||
MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
|
||||
extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
|
||||
|
||||
static int acpi_ac_add(struct acpi_device *device);
|
||||
static int acpi_ac_remove(struct acpi_device *device, int type);
|
||||
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
|
||||
|
||||
static struct acpi_driver acpi_ac_driver = {
|
||||
.name = "ac",
|
||||
.class = ACPI_AC_CLASS,
|
||||
.ids = ACPI_AC_HID,
|
||||
.ops = {
|
||||
.add = acpi_ac_add,
|
||||
.remove = acpi_ac_remove,
|
||||
},
|
||||
};
|
||||
|
||||
struct acpi_ac {
|
||||
struct acpi_device * device;
|
||||
unsigned long state;
|
||||
};
|
||||
|
||||
static const struct file_operations acpi_ac_fops = {
|
||||
.open = acpi_ac_open_fs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
AC Adapter Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static int acpi_ac_get_state(struct acpi_ac *ac)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
|
||||
if (!ac)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, &ac->state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Error reading AC Adapter state"));
|
||||
ac->state = ACPI_AC_STATUS_UNKNOWN;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static struct proc_dir_entry *acpi_ac_dir;
|
||||
|
||||
static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_ac *ac = seq->private;
|
||||
|
||||
|
||||
if (!ac)
|
||||
return 0;
|
||||
|
||||
if (acpi_ac_get_state(ac)) {
|
||||
seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_puts(seq, "state: ");
|
||||
switch (ac->state) {
|
||||
case ACPI_AC_STATUS_OFFLINE:
|
||||
seq_puts(seq, "off-line\n");
|
||||
break;
|
||||
case ACPI_AC_STATUS_ONLINE:
|
||||
seq_puts(seq, "on-line\n");
|
||||
break;
|
||||
default:
|
||||
seq_puts(seq, "unknown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_ac_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_ac_seq_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static int acpi_ac_add_fs(struct acpi_device *device)
|
||||
{
|
||||
struct proc_dir_entry *entry = NULL;
|
||||
|
||||
|
||||
if (!acpi_device_dir(device)) {
|
||||
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
|
||||
acpi_ac_dir);
|
||||
if (!acpi_device_dir(device))
|
||||
return -ENODEV;
|
||||
acpi_device_dir(device)->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
/* 'state' [R] */
|
||||
entry = create_proc_entry(ACPI_AC_FILE_STATE,
|
||||
S_IRUGO, acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_ac_fops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_ac_remove_fs(struct acpi_device *device)
|
||||
{
|
||||
|
||||
if (acpi_device_dir(device)) {
|
||||
remove_proc_entry(ACPI_AC_FILE_STATE, acpi_device_dir(device));
|
||||
|
||||
remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
|
||||
acpi_device_dir(device) = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Driver Model
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_ac *ac = data;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
|
||||
if (!ac)
|
||||
return;
|
||||
|
||||
device = ac->device;
|
||||
switch (event) {
|
||||
case ACPI_AC_NOTIFY_STATUS:
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
acpi_ac_get_state(ac);
|
||||
acpi_bus_generate_event(device, event, (u32) ac->state);
|
||||
break;
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Unsupported event [0x%x]\n", event));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int acpi_ac_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_ac *ac = NULL;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL);
|
||||
if (!ac)
|
||||
return -ENOMEM;
|
||||
|
||||
ac->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_AC_CLASS);
|
||||
acpi_driver_data(device) = ac;
|
||||
|
||||
result = acpi_ac_get_state(ac);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
result = acpi_ac_add_fs(device);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY, acpi_ac_notify,
|
||||
ac);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
|
||||
acpi_device_name(device), acpi_device_bid(device),
|
||||
ac->state ? "on-line" : "off-line");
|
||||
|
||||
end:
|
||||
if (result) {
|
||||
acpi_ac_remove_fs(device);
|
||||
kfree(ac);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_ac_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_ac *ac = NULL;
|
||||
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
ac = acpi_driver_data(device);
|
||||
|
||||
status = acpi_remove_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY, acpi_ac_notify);
|
||||
|
||||
acpi_ac_remove_fs(device);
|
||||
|
||||
kfree(ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init acpi_ac_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
acpi_ac_dir = acpi_lock_ac_dir();
|
||||
if (!acpi_ac_dir)
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_ac_driver);
|
||||
if (result < 0) {
|
||||
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_ac_exit(void)
|
||||
{
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_ac_driver);
|
||||
|
||||
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acpi_ac_init);
|
||||
module_exit(acpi_ac_exit);
|
||||
576
drivers/acpi/acpi_memhotplug.c
Normal file
576
drivers/acpi/acpi_memhotplug.c
Normal file
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*
|
||||
* ACPI based HotPlug driver that supports Memory Hotplug
|
||||
* This driver fields notifications from firmare for memory add
|
||||
* and remove operations and alerts the VM of the affected memory
|
||||
* ranges.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/memory_hotplug.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000UL
|
||||
#define ACPI_MEMORY_DEVICE_CLASS "memory"
|
||||
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
|
||||
#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
|
||||
|
||||
#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
|
||||
|
||||
ACPI_MODULE_NAME("acpi_memhotplug");
|
||||
MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
|
||||
MODULE_DESCRIPTION("Hotplug Mem Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* ACPI _STA method values */
|
||||
#define ACPI_MEMORY_STA_PRESENT (0x00000001UL)
|
||||
#define ACPI_MEMORY_STA_ENABLED (0x00000002UL)
|
||||
#define ACPI_MEMORY_STA_FUNCTIONAL (0x00000008UL)
|
||||
|
||||
/* Memory Device States */
|
||||
#define MEMORY_INVALID_STATE 0
|
||||
#define MEMORY_POWER_ON_STATE 1
|
||||
#define MEMORY_POWER_OFF_STATE 2
|
||||
|
||||
static int acpi_memory_device_add(struct acpi_device *device);
|
||||
static int acpi_memory_device_remove(struct acpi_device *device, int type);
|
||||
static int acpi_memory_device_start(struct acpi_device *device);
|
||||
|
||||
static struct acpi_driver acpi_memory_device_driver = {
|
||||
.name = "acpi_memhotplug",
|
||||
.class = ACPI_MEMORY_DEVICE_CLASS,
|
||||
.ids = ACPI_MEMORY_DEVICE_HID,
|
||||
.ops = {
|
||||
.add = acpi_memory_device_add,
|
||||
.remove = acpi_memory_device_remove,
|
||||
.start = acpi_memory_device_start,
|
||||
},
|
||||
};
|
||||
|
||||
struct acpi_memory_info {
|
||||
struct list_head list;
|
||||
u64 start_addr; /* Memory Range start physical addr */
|
||||
u64 length; /* Memory Range length */
|
||||
unsigned short caching; /* memory cache attribute */
|
||||
unsigned short write_protect; /* memory read/write attribute */
|
||||
unsigned int enabled:1;
|
||||
};
|
||||
|
||||
struct acpi_memory_device {
|
||||
struct acpi_device * device;
|
||||
unsigned int state; /* State of the memory device */
|
||||
struct list_head res_list;
|
||||
};
|
||||
|
||||
static int acpi_hotmem_initialized;
|
||||
|
||||
static acpi_status
|
||||
acpi_memory_get_resource(struct acpi_resource *resource, void *context)
|
||||
{
|
||||
struct acpi_memory_device *mem_device = context;
|
||||
struct acpi_resource_address64 address64;
|
||||
struct acpi_memory_info *info, *new;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_resource_to_address64(resource, &address64);
|
||||
if (ACPI_FAILURE(status) ||
|
||||
(address64.resource_type != ACPI_MEMORY_RANGE))
|
||||
return AE_OK;
|
||||
|
||||
list_for_each_entry(info, &mem_device->res_list, list) {
|
||||
/* Can we combine the resource range information? */
|
||||
if ((info->caching == address64.info.mem.caching) &&
|
||||
(info->write_protect == address64.info.mem.write_protect) &&
|
||||
(info->start_addr + info->length == address64.minimum)) {
|
||||
info->length += address64.address_length;
|
||||
return AE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
|
||||
if (!new)
|
||||
return AE_ERROR;
|
||||
|
||||
INIT_LIST_HEAD(&new->list);
|
||||
new->caching = address64.info.mem.caching;
|
||||
new->write_protect = address64.info.mem.write_protect;
|
||||
new->start_addr = address64.minimum;
|
||||
new->length = address64.address_length;
|
||||
list_add_tail(&new->list, &mem_device->res_list);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_memory_info *info, *n;
|
||||
|
||||
|
||||
if (!list_empty(&mem_device->res_list))
|
||||
return 0;
|
||||
|
||||
status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
|
||||
acpi_memory_get_resource, mem_device);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
list_for_each_entry_safe(info, n, &mem_device->res_list, list)
|
||||
kfree(info);
|
||||
INIT_LIST_HEAD(&mem_device->res_list);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_memory_get_device(acpi_handle handle,
|
||||
struct acpi_memory_device **mem_device)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle phandle;
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_device *pdevice = NULL;
|
||||
|
||||
|
||||
if (!acpi_bus_get_device(handle, &device) && device)
|
||||
goto end;
|
||||
|
||||
status = acpi_get_parent(handle, &phandle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the parent device */
|
||||
status = acpi_bus_get_device(phandle, &pdevice);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Cannot get acpi bus device"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now add the notified device. This creates the acpi_device
|
||||
* and invokes .add function
|
||||
*/
|
||||
status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Cannot add acpi bus"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end:
|
||||
*mem_device = acpi_driver_data(device);
|
||||
if (!(*mem_device)) {
|
||||
printk(KERN_ERR "\n driver data not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
unsigned long current_status;
|
||||
|
||||
|
||||
/* Get device present/absent information from the _STA */
|
||||
if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
|
||||
NULL, ¤t_status)))
|
||||
return -ENODEV;
|
||||
/*
|
||||
* Check for device status. Device should be
|
||||
* present/enabled/functioning.
|
||||
*/
|
||||
if (!((current_status & ACPI_MEMORY_STA_PRESENT)
|
||||
&& (current_status & ACPI_MEMORY_STA_ENABLED)
|
||||
&& (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
int result, num_enabled = 0;
|
||||
struct acpi_memory_info *info;
|
||||
int node;
|
||||
|
||||
|
||||
/* Get the range from the _CRS */
|
||||
result = acpi_memory_get_device_resources(mem_device);
|
||||
if (result) {
|
||||
printk(KERN_ERR PREFIX "get_device_resources failed\n");
|
||||
mem_device->state = MEMORY_INVALID_STATE;
|
||||
return result;
|
||||
}
|
||||
|
||||
node = acpi_get_node(mem_device->device->handle);
|
||||
/*
|
||||
* Tell the VM there is more memory here...
|
||||
* Note: Assume that this function returns zero on success
|
||||
* We don't have memory-hot-add rollback function,now.
|
||||
* (i.e. memory-hot-remove function)
|
||||
*/
|
||||
list_for_each_entry(info, &mem_device->res_list, list) {
|
||||
if (info->enabled) { /* just sanity check...*/
|
||||
num_enabled++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node < 0)
|
||||
node = memory_add_physaddr_to_nid(info->start_addr);
|
||||
|
||||
result = add_memory(node, info->start_addr, info->length);
|
||||
if (result)
|
||||
continue;
|
||||
info->enabled = 1;
|
||||
num_enabled++;
|
||||
}
|
||||
if (!num_enabled) {
|
||||
printk(KERN_ERR PREFIX "add_memory failed\n");
|
||||
mem_device->state = MEMORY_INVALID_STATE;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
unsigned long current_status;
|
||||
|
||||
|
||||
/* Issue the _EJ0 command */
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = 1;
|
||||
status = acpi_evaluate_object(mem_device->device->handle,
|
||||
"_EJ0", &arg_list, NULL);
|
||||
/* Return on _EJ0 failure */
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Evalute _STA to check if the device is disabled */
|
||||
status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
|
||||
NULL, ¤t_status);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
/* Check for device status. Device should be disabled */
|
||||
if (current_status & ACPI_MEMORY_STA_ENABLED)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
int result;
|
||||
struct acpi_memory_info *info, *n;
|
||||
|
||||
|
||||
/*
|
||||
* Ask the VM to offline this memory range.
|
||||
* Note: Assume that this function returns zero on success
|
||||
*/
|
||||
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
|
||||
if (info->enabled) {
|
||||
result = remove_memory(info->start_addr, info->length);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
/* Power-off and eject the device */
|
||||
result = acpi_memory_powerdown_device(mem_device);
|
||||
if (result) {
|
||||
/* Set the status of the device to invalid */
|
||||
mem_device->state = MEMORY_INVALID_STATE;
|
||||
return result;
|
||||
}
|
||||
|
||||
mem_device->state = MEMORY_POWER_OFF_STATE;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_memory_device *mem_device;
|
||||
struct acpi_device *device;
|
||||
|
||||
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"\nReceived BUS CHECK notification for device\n"));
|
||||
/* Fall Through */
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
if (event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"\nReceived DEVICE CHECK notification for device\n"));
|
||||
if (acpi_memory_get_device(handle, &mem_device)) {
|
||||
printk(KERN_ERR PREFIX "Cannot find driver data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!acpi_memory_check_device(mem_device)) {
|
||||
if (acpi_memory_enable_device(mem_device))
|
||||
printk(KERN_ERR PREFIX
|
||||
"Cannot enable memory device\n");
|
||||
}
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"\nReceived EJECT REQUEST notification for device\n"));
|
||||
|
||||
if (acpi_bus_get_device(handle, &device)) {
|
||||
printk(KERN_ERR PREFIX "Device doesn't exist\n");
|
||||
break;
|
||||
}
|
||||
mem_device = acpi_driver_data(device);
|
||||
if (!mem_device) {
|
||||
printk(KERN_ERR PREFIX "Driver Data is NULL\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently disabling memory device from kernel mode
|
||||
* TBD: Can also be disabled from user mode scripts
|
||||
* TBD: Can also be disabled by Callback registration
|
||||
* with generic sysfs driver
|
||||
*/
|
||||
if (acpi_memory_disable_device(mem_device))
|
||||
printk(KERN_ERR PREFIX
|
||||
"Disable memory device\n");
|
||||
/*
|
||||
* TBD: Invoke acpi_bus_remove to cleanup data structures
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Unsupported event [0x%x]\n", event));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int acpi_memory_device_add(struct acpi_device *device)
|
||||
{
|
||||
int result;
|
||||
struct acpi_memory_device *mem_device = NULL;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
|
||||
if (!mem_device)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&mem_device->res_list);
|
||||
mem_device->device = device;
|
||||
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
|
||||
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
|
||||
acpi_driver_data(device) = mem_device;
|
||||
|
||||
/* Get the range from the _CRS */
|
||||
result = acpi_memory_get_device_resources(mem_device);
|
||||
if (result) {
|
||||
kfree(mem_device);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Set the device state */
|
||||
mem_device->state = MEMORY_POWER_ON_STATE;
|
||||
|
||||
printk(KERN_DEBUG "%s \n", acpi_device_name(device));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_memory_device_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct acpi_memory_device *mem_device = NULL;
|
||||
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
mem_device = acpi_driver_data(device);
|
||||
kfree(mem_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_memory_device_start (struct acpi_device *device)
|
||||
{
|
||||
struct acpi_memory_device *mem_device;
|
||||
int result = 0;
|
||||
|
||||
/*
|
||||
* Early boot code has recognized memory area by EFI/E820.
|
||||
* If DSDT shows these memory devices on boot, hotplug is not necessary
|
||||
* for them. So, it just returns until completion of this driver's
|
||||
* start up.
|
||||
*/
|
||||
if (!acpi_hotmem_initialized)
|
||||
return 0;
|
||||
|
||||
mem_device = acpi_driver_data(device);
|
||||
|
||||
if (!acpi_memory_check_device(mem_device)) {
|
||||
/* call add_memory func */
|
||||
result = acpi_memory_enable_device(mem_device);
|
||||
if (result)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error in acpi_memory_enable_device\n"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to check for memory device
|
||||
*/
|
||||
static acpi_status is_memory_device(acpi_handle handle)
|
||||
{
|
||||
char *hardware_id;
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_device_info *info;
|
||||
|
||||
|
||||
status = acpi_get_object_info(handle, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
info = buffer.pointer;
|
||||
if (!(info->valid & ACPI_VALID_HID)) {
|
||||
kfree(buffer.pointer);
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
hardware_id = info->hardware_id.value;
|
||||
if ((hardware_id == NULL) ||
|
||||
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
|
||||
status = AE_ERROR;
|
||||
|
||||
kfree(buffer.pointer);
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_memory_register_notify_handler(acpi_handle handle,
|
||||
u32 level, void *ctxt, void **retv)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
|
||||
status = is_memory_device(handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
return AE_OK; /* continue */
|
||||
|
||||
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
acpi_memory_device_notify, NULL);
|
||||
/* continue */
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_memory_deregister_notify_handler(acpi_handle handle,
|
||||
u32 level, void *ctxt, void **retv)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
|
||||
status = is_memory_device(handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
return AE_OK; /* continue */
|
||||
|
||||
status = acpi_remove_notify_handler(handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
acpi_memory_device_notify);
|
||||
|
||||
return AE_OK; /* continue */
|
||||
}
|
||||
|
||||
static int __init acpi_memory_device_init(void)
|
||||
{
|
||||
int result;
|
||||
acpi_status status;
|
||||
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_memory_device_driver);
|
||||
|
||||
if (result < 0)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX,
|
||||
acpi_memory_register_notify_handler,
|
||||
NULL, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
|
||||
acpi_bus_unregister_driver(&acpi_memory_device_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
acpi_hotmem_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_memory_device_exit(void)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
|
||||
/*
|
||||
* Adding this to un-install notification handlers for all the device
|
||||
* handles.
|
||||
*/
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX,
|
||||
acpi_memory_deregister_notify_handler,
|
||||
NULL, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_memory_device_driver);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acpi_memory_device_init);
|
||||
module_exit(acpi_memory_device_exit);
|
||||
1417
drivers/acpi/asus_acpi.c
Normal file
1417
drivers/acpi/asus_acpi.c
Normal file
File diff suppressed because it is too large
Load Diff
812
drivers/acpi/battery.c
Normal file
812
drivers/acpi/battery.c
Normal file
@@ -0,0 +1,812 @@
|
||||
/*
|
||||
* acpi_battery.c - ACPI Battery Driver ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||
* 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.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
|
||||
#define ACPI_BATTERY_FORMAT_BST "NNNN"
|
||||
|
||||
#define ACPI_BATTERY_COMPONENT 0x00040000
|
||||
#define ACPI_BATTERY_CLASS "battery"
|
||||
#define ACPI_BATTERY_HID "PNP0C0A"
|
||||
#define ACPI_BATTERY_DEVICE_NAME "Battery"
|
||||
#define ACPI_BATTERY_FILE_INFO "info"
|
||||
#define ACPI_BATTERY_FILE_STATUS "state"
|
||||
#define ACPI_BATTERY_FILE_ALARM "alarm"
|
||||
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
|
||||
#define ACPI_BATTERY_NOTIFY_INFO 0x81
|
||||
#define ACPI_BATTERY_UNITS_WATTS "mW"
|
||||
#define ACPI_BATTERY_UNITS_AMPS "mA"
|
||||
|
||||
#define _COMPONENT ACPI_BATTERY_COMPONENT
|
||||
ACPI_MODULE_NAME("battery");
|
||||
|
||||
MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_DESCRIPTION("ACPI Battery Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
|
||||
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
|
||||
|
||||
static int acpi_battery_add(struct acpi_device *device);
|
||||
static int acpi_battery_remove(struct acpi_device *device, int type);
|
||||
static int acpi_battery_resume(struct acpi_device *device);
|
||||
|
||||
static struct acpi_driver acpi_battery_driver = {
|
||||
.name = "battery",
|
||||
.class = ACPI_BATTERY_CLASS,
|
||||
.ids = ACPI_BATTERY_HID,
|
||||
.ops = {
|
||||
.add = acpi_battery_add,
|
||||
.resume = acpi_battery_resume,
|
||||
.remove = acpi_battery_remove,
|
||||
},
|
||||
};
|
||||
|
||||
struct acpi_battery_status {
|
||||
acpi_integer state;
|
||||
acpi_integer present_rate;
|
||||
acpi_integer remaining_capacity;
|
||||
acpi_integer present_voltage;
|
||||
};
|
||||
|
||||
struct acpi_battery_info {
|
||||
acpi_integer power_unit;
|
||||
acpi_integer design_capacity;
|
||||
acpi_integer last_full_capacity;
|
||||
acpi_integer battery_technology;
|
||||
acpi_integer design_voltage;
|
||||
acpi_integer design_capacity_warning;
|
||||
acpi_integer design_capacity_low;
|
||||
acpi_integer battery_capacity_granularity_1;
|
||||
acpi_integer battery_capacity_granularity_2;
|
||||
acpi_string model_number;
|
||||
acpi_string serial_number;
|
||||
acpi_string battery_type;
|
||||
acpi_string oem_info;
|
||||
};
|
||||
|
||||
struct acpi_battery_flags {
|
||||
u8 present:1; /* Bay occupied? */
|
||||
u8 power_unit:1; /* 0=watts, 1=apms */
|
||||
u8 alarm:1; /* _BTP present? */
|
||||
u8 reserved:5;
|
||||
};
|
||||
|
||||
struct acpi_battery_trips {
|
||||
unsigned long warning;
|
||||
unsigned long low;
|
||||
};
|
||||
|
||||
struct acpi_battery {
|
||||
struct acpi_device * device;
|
||||
struct acpi_battery_flags flags;
|
||||
struct acpi_battery_trips trips;
|
||||
unsigned long alarm;
|
||||
struct acpi_battery_info *info;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Battery Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
acpi_battery_get_info(struct acpi_battery *battery,
|
||||
struct acpi_battery_info **bif)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
|
||||
ACPI_BATTERY_FORMAT_BIF
|
||||
};
|
||||
struct acpi_buffer data = { 0, NULL };
|
||||
union acpi_object *package = NULL;
|
||||
|
||||
|
||||
if (!battery || !bif)
|
||||
return -EINVAL;
|
||||
|
||||
/* Evalute _BIF */
|
||||
|
||||
status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
package = buffer.pointer;
|
||||
|
||||
/* Extract Package Data */
|
||||
|
||||
status = acpi_extract_package(package, &format, &data);
|
||||
if (status != AE_BUFFER_OVERFLOW) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data.pointer = kzalloc(data.length, GFP_KERNEL);
|
||||
if (!data.pointer) {
|
||||
result = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
status = acpi_extract_package(package, &format, &data);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
|
||||
kfree(data.pointer);
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
if (!result)
|
||||
(*bif) = data.pointer;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_battery_get_status(struct acpi_battery *battery,
|
||||
struct acpi_battery_status **bst)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
|
||||
ACPI_BATTERY_FORMAT_BST
|
||||
};
|
||||
struct acpi_buffer data = { 0, NULL };
|
||||
union acpi_object *package = NULL;
|
||||
|
||||
|
||||
if (!battery || !bst)
|
||||
return -EINVAL;
|
||||
|
||||
/* Evalute _BST */
|
||||
|
||||
status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
package = buffer.pointer;
|
||||
|
||||
/* Extract Package Data */
|
||||
|
||||
status = acpi_extract_package(package, &format, &data);
|
||||
if (status != AE_BUFFER_OVERFLOW) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data.pointer = kzalloc(data.length, GFP_KERNEL);
|
||||
if (!data.pointer) {
|
||||
result = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
status = acpi_extract_package(package, &format, &data);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
|
||||
kfree(data.pointer);
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
if (!result)
|
||||
(*bst) = data.pointer;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
|
||||
struct acpi_object_list arg_list = { 1, &arg0 };
|
||||
|
||||
|
||||
if (!battery)
|
||||
return -EINVAL;
|
||||
|
||||
if (!battery->flags.alarm)
|
||||
return -ENODEV;
|
||||
|
||||
arg0.integer.value = alarm;
|
||||
|
||||
status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
|
||||
|
||||
battery->alarm = alarm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_battery_check(struct acpi_battery *battery)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
acpi_handle handle = NULL;
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_battery_info *bif = NULL;
|
||||
|
||||
|
||||
if (!battery)
|
||||
return -EINVAL;
|
||||
|
||||
device = battery->device;
|
||||
|
||||
result = acpi_bus_get_status(device);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Insertion? */
|
||||
|
||||
if (!battery->flags.present && device->status.battery_present) {
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
|
||||
|
||||
/* Evalute _BIF to get certain static information */
|
||||
|
||||
result = acpi_battery_get_info(battery, &bif);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
battery->flags.power_unit = bif->power_unit;
|
||||
battery->trips.warning = bif->design_capacity_warning;
|
||||
battery->trips.low = bif->design_capacity_low;
|
||||
kfree(bif);
|
||||
|
||||
/* See if alarms are supported, and if so, set default */
|
||||
|
||||
status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
battery->flags.alarm = 1;
|
||||
acpi_battery_set_alarm(battery, battery->trips.warning);
|
||||
}
|
||||
}
|
||||
|
||||
/* Removal? */
|
||||
|
||||
else if (battery->flags.present && !device->status.battery_present) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
|
||||
}
|
||||
|
||||
battery->flags.present = device->status.battery_present;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void acpi_battery_check_present(struct acpi_battery *battery)
|
||||
{
|
||||
if (!battery->flags.present) {
|
||||
acpi_battery_check(battery);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static struct proc_dir_entry *acpi_battery_dir;
|
||||
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_battery *battery = seq->private;
|
||||
struct acpi_battery_info *bif = NULL;
|
||||
char *units = "?";
|
||||
|
||||
|
||||
if (!battery)
|
||||
goto end;
|
||||
|
||||
acpi_battery_check_present(battery);
|
||||
|
||||
if (battery->flags.present)
|
||||
seq_printf(seq, "present: yes\n");
|
||||
else {
|
||||
seq_printf(seq, "present: no\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Battery Info (_BIF) */
|
||||
|
||||
result = acpi_battery_get_info(battery, &bif);
|
||||
if (result || !bif) {
|
||||
seq_printf(seq, "ERROR: Unable to read battery information\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
units =
|
||||
bif->
|
||||
power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
|
||||
|
||||
if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
|
||||
seq_printf(seq, "design capacity: unknown\n");
|
||||
else
|
||||
seq_printf(seq, "design capacity: %d %sh\n",
|
||||
(u32) bif->design_capacity, units);
|
||||
|
||||
if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
|
||||
seq_printf(seq, "last full capacity: unknown\n");
|
||||
else
|
||||
seq_printf(seq, "last full capacity: %d %sh\n",
|
||||
(u32) bif->last_full_capacity, units);
|
||||
|
||||
switch ((u32) bif->battery_technology) {
|
||||
case 0:
|
||||
seq_printf(seq, "battery technology: non-rechargeable\n");
|
||||
break;
|
||||
case 1:
|
||||
seq_printf(seq, "battery technology: rechargeable\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(seq, "battery technology: unknown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
|
||||
seq_printf(seq, "design voltage: unknown\n");
|
||||
else
|
||||
seq_printf(seq, "design voltage: %d mV\n",
|
||||
(u32) bif->design_voltage);
|
||||
|
||||
seq_printf(seq, "design capacity warning: %d %sh\n",
|
||||
(u32) bif->design_capacity_warning, units);
|
||||
seq_printf(seq, "design capacity low: %d %sh\n",
|
||||
(u32) bif->design_capacity_low, units);
|
||||
seq_printf(seq, "capacity granularity 1: %d %sh\n",
|
||||
(u32) bif->battery_capacity_granularity_1, units);
|
||||
seq_printf(seq, "capacity granularity 2: %d %sh\n",
|
||||
(u32) bif->battery_capacity_granularity_2, units);
|
||||
seq_printf(seq, "model number: %s\n", bif->model_number);
|
||||
seq_printf(seq, "serial number: %s\n", bif->serial_number);
|
||||
seq_printf(seq, "battery type: %s\n", bif->battery_type);
|
||||
seq_printf(seq, "OEM info: %s\n", bif->oem_info);
|
||||
|
||||
end:
|
||||
kfree(bif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_battery_read_info, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static int acpi_battery_read_state(struct seq_file *seq, void *offset)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_battery *battery = seq->private;
|
||||
struct acpi_battery_status *bst = NULL;
|
||||
char *units = "?";
|
||||
|
||||
|
||||
if (!battery)
|
||||
goto end;
|
||||
|
||||
acpi_battery_check_present(battery);
|
||||
|
||||
if (battery->flags.present)
|
||||
seq_printf(seq, "present: yes\n");
|
||||
else {
|
||||
seq_printf(seq, "present: no\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Battery Units */
|
||||
|
||||
units =
|
||||
battery->flags.
|
||||
power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
|
||||
|
||||
/* Battery Status (_BST) */
|
||||
|
||||
result = acpi_battery_get_status(battery, &bst);
|
||||
if (result || !bst) {
|
||||
seq_printf(seq, "ERROR: Unable to read battery status\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(bst->state & 0x04))
|
||||
seq_printf(seq, "capacity state: ok\n");
|
||||
else
|
||||
seq_printf(seq, "capacity state: critical\n");
|
||||
|
||||
if ((bst->state & 0x01) && (bst->state & 0x02)) {
|
||||
seq_printf(seq,
|
||||
"charging state: charging/discharging\n");
|
||||
} else if (bst->state & 0x01)
|
||||
seq_printf(seq, "charging state: discharging\n");
|
||||
else if (bst->state & 0x02)
|
||||
seq_printf(seq, "charging state: charging\n");
|
||||
else {
|
||||
seq_printf(seq, "charging state: charged\n");
|
||||
}
|
||||
|
||||
if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
|
||||
seq_printf(seq, "present rate: unknown\n");
|
||||
else
|
||||
seq_printf(seq, "present rate: %d %s\n",
|
||||
(u32) bst->present_rate, units);
|
||||
|
||||
if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
|
||||
seq_printf(seq, "remaining capacity: unknown\n");
|
||||
else
|
||||
seq_printf(seq, "remaining capacity: %d %sh\n",
|
||||
(u32) bst->remaining_capacity, units);
|
||||
|
||||
if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
|
||||
seq_printf(seq, "present voltage: unknown\n");
|
||||
else
|
||||
seq_printf(seq, "present voltage: %d mV\n",
|
||||
(u32) bst->present_voltage);
|
||||
|
||||
end:
|
||||
kfree(bst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_battery_read_state, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_battery *battery = seq->private;
|
||||
char *units = "?";
|
||||
|
||||
|
||||
if (!battery)
|
||||
goto end;
|
||||
|
||||
acpi_battery_check_present(battery);
|
||||
|
||||
if (!battery->flags.present) {
|
||||
seq_printf(seq, "present: no\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Battery Units */
|
||||
|
||||
units =
|
||||
battery->flags.
|
||||
power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
|
||||
|
||||
/* Battery Alarm */
|
||||
|
||||
seq_printf(seq, "alarm: ");
|
||||
if (!battery->alarm)
|
||||
seq_printf(seq, "unsupported\n");
|
||||
else
|
||||
seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
|
||||
|
||||
end:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
acpi_battery_write_alarm(struct file *file,
|
||||
const char __user * buffer,
|
||||
size_t count, loff_t * ppos)
|
||||
{
|
||||
int result = 0;
|
||||
char alarm_string[12] = { '\0' };
|
||||
struct seq_file *m = file->private_data;
|
||||
struct acpi_battery *battery = m->private;
|
||||
|
||||
|
||||
if (!battery || (count > sizeof(alarm_string) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
acpi_battery_check_present(battery);
|
||||
|
||||
if (!battery->flags.present)
|
||||
return -ENODEV;
|
||||
|
||||
if (copy_from_user(alarm_string, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
alarm_string[count] = '\0';
|
||||
|
||||
result = acpi_battery_set_alarm(battery,
|
||||
simple_strtoul(alarm_string, NULL, 0));
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static const struct file_operations acpi_battery_info_ops = {
|
||||
.open = acpi_battery_info_open_fs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct file_operations acpi_battery_state_ops = {
|
||||
.open = acpi_battery_state_open_fs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct file_operations acpi_battery_alarm_ops = {
|
||||
.open = acpi_battery_alarm_open_fs,
|
||||
.read = seq_read,
|
||||
.write = acpi_battery_write_alarm,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int acpi_battery_add_fs(struct acpi_device *device)
|
||||
{
|
||||
struct proc_dir_entry *entry = NULL;
|
||||
|
||||
|
||||
if (!acpi_device_dir(device)) {
|
||||
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
|
||||
acpi_battery_dir);
|
||||
if (!acpi_device_dir(device))
|
||||
return -ENODEV;
|
||||
acpi_device_dir(device)->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
/* 'info' [R] */
|
||||
entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
|
||||
S_IRUGO, acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_battery_info_ops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
/* 'status' [R] */
|
||||
entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
|
||||
S_IRUGO, acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_battery_state_ops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
/* 'alarm' [R/W] */
|
||||
entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
|
||||
S_IFREG | S_IRUGO | S_IWUSR,
|
||||
acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_battery_alarm_ops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_battery_remove_fs(struct acpi_device *device)
|
||||
{
|
||||
|
||||
if (acpi_device_dir(device)) {
|
||||
remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
|
||||
acpi_device_dir(device));
|
||||
remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
|
||||
acpi_device_dir(device));
|
||||
remove_proc_entry(ACPI_BATTERY_FILE_INFO,
|
||||
acpi_device_dir(device));
|
||||
|
||||
remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
|
||||
acpi_device_dir(device) = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Driver Interface
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_battery *battery = data;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
|
||||
if (!battery)
|
||||
return;
|
||||
|
||||
device = battery->device;
|
||||
|
||||
switch (event) {
|
||||
case ACPI_BATTERY_NOTIFY_STATUS:
|
||||
case ACPI_BATTERY_NOTIFY_INFO:
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
acpi_battery_check(battery);
|
||||
acpi_bus_generate_event(device, event, battery->flags.present);
|
||||
break;
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Unsupported event [0x%x]\n", event));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int acpi_battery_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_battery *battery = NULL;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
|
||||
if (!battery)
|
||||
return -ENOMEM;
|
||||
|
||||
battery->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
|
||||
acpi_driver_data(device) = battery;
|
||||
|
||||
result = acpi_battery_check(battery);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
result = acpi_battery_add_fs(device);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY,
|
||||
acpi_battery_notify, battery);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
|
||||
ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
|
||||
device->status.battery_present ? "present" : "absent");
|
||||
|
||||
end:
|
||||
if (result) {
|
||||
acpi_battery_remove_fs(device);
|
||||
kfree(battery);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_battery_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
struct acpi_battery *battery = NULL;
|
||||
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
battery = acpi_driver_data(device);
|
||||
|
||||
status = acpi_remove_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY,
|
||||
acpi_battery_notify);
|
||||
|
||||
acpi_battery_remove_fs(device);
|
||||
|
||||
kfree(battery);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this is needed to learn about changes made in suspended state */
|
||||
static int acpi_battery_resume(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_battery *battery;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
battery = device->driver_data;
|
||||
return acpi_battery_check(battery);
|
||||
}
|
||||
|
||||
static int __init acpi_battery_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
acpi_battery_dir = acpi_lock_battery_dir();
|
||||
if (!acpi_battery_dir)
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_battery_driver);
|
||||
if (result < 0) {
|
||||
acpi_unlock_battery_dir(acpi_battery_dir);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_battery_exit(void)
|
||||
{
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_battery_driver);
|
||||
|
||||
acpi_unlock_battery_dir(acpi_battery_dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acpi_battery_init);
|
||||
module_exit(acpi_battery_exit);
|
||||
397
drivers/acpi/bay.c
Normal file
397
drivers/acpi/bay.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* bay.c - ACPI removable drive bay driver
|
||||
*
|
||||
* Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
ACPI_MODULE_NAME("bay");
|
||||
MODULE_AUTHOR("Kristen Carlson Accardi");
|
||||
MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
#define ACPI_BAY_CLASS "bay"
|
||||
#define ACPI_BAY_COMPONENT 0x10000000
|
||||
#define _COMPONENT ACPI_BAY_COMPONENT
|
||||
#define bay_dprintk(h,s) {\
|
||||
char prefix[80] = {'\0'};\
|
||||
struct acpi_buffer buffer = {sizeof(prefix), prefix};\
|
||||
acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
|
||||
printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
|
||||
static void bay_notify(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
struct bay {
|
||||
acpi_handle handle;
|
||||
char *name;
|
||||
struct list_head list;
|
||||
struct platform_device *pdev;
|
||||
};
|
||||
|
||||
static LIST_HEAD(drive_bays);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Drive Bay functions *
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* is_ejectable - see if a device is ejectable
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If an acpi object has a _EJ0 method, then it is ejectable
|
||||
*/
|
||||
static int is_ejectable(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle tmp;
|
||||
|
||||
status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* bay_present - see if the bay device is present
|
||||
* @bay: the drive bay
|
||||
*
|
||||
* execute the _STA method.
|
||||
*/
|
||||
static int bay_present(struct bay *bay)
|
||||
{
|
||||
unsigned long sta;
|
||||
acpi_status status;
|
||||
|
||||
if (bay) {
|
||||
status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
|
||||
if (ACPI_SUCCESS(status) && sta)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* eject_device - respond to an eject request
|
||||
* @handle - the device to eject
|
||||
*
|
||||
* Call this devices _EJ0 method.
|
||||
*/
|
||||
static void eject_device(acpi_handle handle)
|
||||
{
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
|
||||
bay_dprintk(handle, "Ejecting device");
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = 1;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
&arg_list, NULL)))
|
||||
pr_debug("Failed to evaluate _EJ0!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* show_present - read method for "present" file in sysfs
|
||||
*/
|
||||
static ssize_t show_present(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bay *bay = dev_get_drvdata(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
|
||||
|
||||
}
|
||||
DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
|
||||
|
||||
/*
|
||||
* write_eject - write method for "eject" file in sysfs
|
||||
*/
|
||||
static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct bay *bay = dev_get_drvdata(dev);
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
eject_device(bay->handle);
|
||||
return count;
|
||||
}
|
||||
DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
|
||||
|
||||
/**
|
||||
* is_ata - see if a device is an ata device
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If an acpi object has one of 4 ATA ACPI methods defined,
|
||||
* then it is an ATA device
|
||||
*/
|
||||
static int is_ata(acpi_handle handle)
|
||||
{
|
||||
acpi_handle tmp;
|
||||
|
||||
if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* parent_is_ata(acpi_handle handle)
|
||||
*
|
||||
*/
|
||||
static int parent_is_ata(acpi_handle handle)
|
||||
{
|
||||
acpi_handle phandle;
|
||||
|
||||
if (acpi_get_parent(handle, &phandle))
|
||||
return 0;
|
||||
|
||||
return is_ata(phandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* is_ejectable_bay - see if a device is an ejectable drive bay
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If an acpi object is ejectable and has one of the ACPI ATA
|
||||
* methods defined, then we can safely call it an ejectable
|
||||
* drive bay
|
||||
*/
|
||||
static int is_ejectable_bay(acpi_handle handle)
|
||||
{
|
||||
if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* eject_removable_drive - try to eject this drive
|
||||
* @dev : the device structure of the drive
|
||||
*
|
||||
* If a device is a removable drive that requires an _EJ0 method
|
||||
* to be executed in order to safely remove from the system, do
|
||||
* it. ATM - always returns success
|
||||
*/
|
||||
int eject_removable_drive(struct device *dev)
|
||||
{
|
||||
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
|
||||
|
||||
if (handle) {
|
||||
bay_dprintk(handle, "Got device handle");
|
||||
if (is_ejectable_bay(handle))
|
||||
eject_device(handle);
|
||||
} else {
|
||||
printk("No acpi handle for device\n");
|
||||
}
|
||||
|
||||
/* should I return an error code? */
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eject_removable_drive);
|
||||
|
||||
static int acpi_bay_add_fs(struct bay *bay)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &bay->pdev->dev;
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_present);
|
||||
if (ret)
|
||||
goto add_fs_err;
|
||||
ret = device_create_file(dev, &dev_attr_eject);
|
||||
if (ret) {
|
||||
device_remove_file(dev, &dev_attr_present);
|
||||
goto add_fs_err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
add_fs_err:
|
||||
bay_dprintk(bay->handle, "Error adding sysfs files\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_bay_remove_fs(struct bay *bay)
|
||||
{
|
||||
struct device *dev = &bay->pdev->dev;
|
||||
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(dev, &dev_attr_present);
|
||||
device_remove_file(dev, &dev_attr_eject);
|
||||
}
|
||||
|
||||
static int bay_is_dock_device(acpi_handle handle)
|
||||
{
|
||||
acpi_handle parent;
|
||||
|
||||
acpi_get_parent(handle, &parent);
|
||||
|
||||
/* if the device or it's parent is dependent on the
|
||||
* dock, then we are a dock device
|
||||
*/
|
||||
return (is_dock_device(handle) || is_dock_device(parent));
|
||||
}
|
||||
|
||||
static int bay_add(acpi_handle handle, int id)
|
||||
{
|
||||
acpi_status status;
|
||||
struct bay *new_bay;
|
||||
struct platform_device *pdev;
|
||||
struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
|
||||
|
||||
bay_dprintk(handle, "Adding notify handler");
|
||||
|
||||
/*
|
||||
* Initialize bay device structure
|
||||
*/
|
||||
new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
|
||||
INIT_LIST_HEAD(&new_bay->list);
|
||||
new_bay->handle = handle;
|
||||
new_bay->name = (char *)nbuffer.pointer;
|
||||
|
||||
/* initialize platform device stuff */
|
||||
pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
printk(KERN_ERR PREFIX "Error registering bay device\n");
|
||||
goto bay_add_err;
|
||||
}
|
||||
new_bay->pdev = pdev;
|
||||
platform_set_drvdata(pdev, new_bay);
|
||||
|
||||
if (acpi_bay_add_fs(new_bay)) {
|
||||
platform_device_unregister(new_bay->pdev);
|
||||
goto bay_add_err;
|
||||
}
|
||||
|
||||
/* register for events on this device */
|
||||
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
bay_notify, new_bay);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
|
||||
}
|
||||
|
||||
/* if we are on a dock station, we should register for dock
|
||||
* notifications.
|
||||
*/
|
||||
if (bay_is_dock_device(handle)) {
|
||||
bay_dprintk(handle, "Is dependent on dock\n");
|
||||
register_hotplug_dock_device(handle, bay_notify, new_bay);
|
||||
}
|
||||
list_add(&new_bay->list, &drive_bays);
|
||||
printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
|
||||
return 0;
|
||||
|
||||
bay_add_err:
|
||||
kfree(new_bay->name);
|
||||
kfree(new_bay);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* bay_notify - act upon an acpi bay notification
|
||||
* @handle: the bay handle
|
||||
* @event: the acpi event
|
||||
* @data: our driver data struct
|
||||
*
|
||||
*/
|
||||
static void bay_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct bay *bay_dev = (struct bay *)data;
|
||||
struct device *dev = &bay_dev->pdev->dev;
|
||||
|
||||
bay_dprintk(handle, "Bay event");
|
||||
|
||||
switch(event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
|
||||
}
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
int *count = (int *)context;
|
||||
|
||||
/*
|
||||
* there could be more than one ejectable bay.
|
||||
* so, just return AE_OK always so that every object
|
||||
* will be checked.
|
||||
*/
|
||||
if (is_ejectable_bay(handle)) {
|
||||
bay_dprintk(handle, "found ejectable bay");
|
||||
if (!bay_add(handle, *count))
|
||||
(*count)++;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int __init bay_init(void)
|
||||
{
|
||||
int bays = 0;
|
||||
|
||||
INIT_LIST_HEAD(&drive_bays);
|
||||
|
||||
/* look for dockable drive bays */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, find_bay, &bays, NULL);
|
||||
|
||||
if (!bays)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit bay_exit(void)
|
||||
{
|
||||
struct bay *bay, *tmp;
|
||||
|
||||
list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
|
||||
if (is_dock_device(bay->handle))
|
||||
unregister_hotplug_dock_device(bay->handle);
|
||||
acpi_bay_remove_fs(bay);
|
||||
acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
|
||||
bay_notify);
|
||||
platform_device_unregister(bay->pdev);
|
||||
kfree(bay->name);
|
||||
kfree(bay);
|
||||
}
|
||||
}
|
||||
|
||||
postcore_initcall(bay_init);
|
||||
module_exit(bay_exit);
|
||||
|
||||
169
drivers/acpi/blacklist.c
Normal file
169
drivers/acpi/blacklist.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* blacklist.c
|
||||
*
|
||||
* Check to see if the given machine has a known bad ACPI BIOS
|
||||
* or if the BIOS is too old.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <linux/dmi.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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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},
|
||||
{"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
|
||||
"Bogus PCI routing", 1},
|
||||
|
||||
{""}
|
||||
};
|
||||
|
||||
#if CONFIG_ACPI_BLACKLIST_YEAR
|
||||
|
||||
static int __init blacklist_by_year(void)
|
||||
{
|
||||
int year = dmi_get_year(DMI_BIOS_DATE);
|
||||
/* Doesn't exist? Likely an old system */
|
||||
if (year == -1) {
|
||||
printk(KERN_ERR PREFIX "no DMI BIOS year, "
|
||||
"acpi=force is required to enable ACPI\n" );
|
||||
return 1;
|
||||
}
|
||||
/* 0? Likely a buggy new BIOS */
|
||||
if (year == 0) {
|
||||
printk(KERN_ERR PREFIX "DMI BIOS year==0, "
|
||||
"assuming ACPI-capable machine\n" );
|
||||
return 0;
|
||||
}
|
||||
if (year < CONFIG_ACPI_BLACKLIST_YEAR) {
|
||||
printk(KERN_ERR PREFIX "BIOS age (%d) fails cutoff (%d), "
|
||||
"acpi=force is required to enable ACPI\n",
|
||||
year, CONFIG_ACPI_BLACKLIST_YEAR);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int blacklist_by_year(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
blacklisted += blacklist_by_year();
|
||||
|
||||
return blacklisted;
|
||||
}
|
||||
772
drivers/acpi/bus.c
Normal file
772
drivers/acpi/bus.c
Normal file
@@ -0,0 +1,772 @@
|
||||
/*
|
||||
* acpi_bus.c - ACPI Bus Driver ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_legacy.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/mpspec.h>
|
||||
#endif
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define _COMPONENT ACPI_BUS_COMPONENT
|
||||
ACPI_MODULE_NAME("bus");
|
||||
#ifdef CONFIG_X86
|
||||
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
|
||||
#endif
|
||||
|
||||
struct acpi_device *acpi_root;
|
||||
struct proc_dir_entry *acpi_root_dir;
|
||||
EXPORT_SYMBOL(acpi_root_dir);
|
||||
|
||||
#define STRUCT_TO_INT(s) (*((int*)&s))
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Device Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
/* TBD: Support fixed-feature devices */
|
||||
|
||||
status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
|
||||
if (ACPI_FAILURE(status) || !*device) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
|
||||
handle));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_get_device);
|
||||
|
||||
int acpi_bus_get_status(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
unsigned long sta = 0;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Evaluate _STA if present.
|
||||
*/
|
||||
if (device->flags.dynamic_status) {
|
||||
status =
|
||||
acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
STRUCT_TO_INT(device->status) = (int)sta;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we assume the status of our parent (unless we don't
|
||||
* have one, in which case status is implied).
|
||||
*/
|
||||
else if (device->parent)
|
||||
device->status = device->parent->status;
|
||||
else
|
||||
STRUCT_TO_INT(device->status) = 0x0F;
|
||||
|
||||
if (device->status.functional && !device->status.present) {
|
||||
printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
|
||||
"functional but not present; setting present\n",
|
||||
device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
|
||||
device->status.present = 1;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
|
||||
device->pnp.bus_id,
|
||||
(u32) STRUCT_TO_INT(device->status)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_get_status);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Power Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
int acpi_bus_get_power(acpi_handle handle, int *state)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_device *device = NULL;
|
||||
unsigned long psc = 0;
|
||||
|
||||
|
||||
result = acpi_bus_get_device(handle, &device);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
*state = ACPI_STATE_UNKNOWN;
|
||||
|
||||
if (!device->flags.power_manageable) {
|
||||
/* TBD: Non-recursive algorithm for walking up hierarchy */
|
||||
if (device->parent)
|
||||
*state = device->parent->power.state;
|
||||
else
|
||||
*state = ACPI_STATE_D0;
|
||||
} else {
|
||||
/*
|
||||
* Get the device's power state either directly (via _PSC) or
|
||||
* indirectly (via power resources).
|
||||
*/
|
||||
if (device->power.flags.explicit_get) {
|
||||
status = acpi_evaluate_integer(device->handle, "_PSC",
|
||||
NULL, &psc);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
device->power.state = (int)psc;
|
||||
} else if (device->power.flags.power_resources) {
|
||||
result = acpi_power_get_inferred_state(device);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
*state = device->power.state;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
|
||||
device->pnp.bus_id, device->power.state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_get_power);
|
||||
|
||||
int acpi_bus_set_power(acpi_handle handle, int state)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_device *device = NULL;
|
||||
char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
|
||||
|
||||
|
||||
result = acpi_bus_get_device(handle, &device);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure this is a valid target state */
|
||||
|
||||
if (!device->flags.power_manageable) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
|
||||
device->dev.kobj.name));
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* Get device's current power state if it's unknown
|
||||
* This means device power state isn't initialized or previous setting failed
|
||||
*/
|
||||
if ((device->power.state == ACPI_STATE_UNKNOWN) || device->flags.force_power_state)
|
||||
acpi_bus_get_power(device->handle, &device->power.state);
|
||||
if ((state == device->power.state) && !device->flags.force_power_state) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
|
||||
state));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!device->power.states[state].flags.valid) {
|
||||
printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (device->parent && (state < device->parent->power.state)) {
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Cannot set device to a higher-powered"
|
||||
" state than parent\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transition Power
|
||||
* ----------------
|
||||
* On transitions to a high-powered state we first apply power (via
|
||||
* power resources) then evalute _PSx. Conversly for transitions to
|
||||
* a lower-powered state.
|
||||
*/
|
||||
if (state < device->power.state) {
|
||||
if (device->power.flags.power_resources) {
|
||||
result = acpi_power_transition(device, state);
|
||||
if (result)
|
||||
goto end;
|
||||
}
|
||||
if (device->power.states[state].flags.explicit_set) {
|
||||
status = acpi_evaluate_object(device->handle,
|
||||
object_name, NULL, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (device->power.states[state].flags.explicit_set) {
|
||||
status = acpi_evaluate_object(device->handle,
|
||||
object_name, NULL, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (device->power.flags.power_resources) {
|
||||
result = acpi_power_transition(device, state);
|
||||
if (result)
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (result)
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Transitioning device [%s] to D%d\n",
|
||||
device->pnp.bus_id, state);
|
||||
else
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Device [%s] transitioned to D%d\n",
|
||||
device->pnp.bus_id, state));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_set_power);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Event Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static DEFINE_SPINLOCK(acpi_bus_event_lock);
|
||||
|
||||
LIST_HEAD(acpi_bus_event_list);
|
||||
DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
|
||||
|
||||
extern int event_is_open;
|
||||
|
||||
int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
|
||||
{
|
||||
struct acpi_bus_event *event = NULL;
|
||||
unsigned long flags = 0;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
/* drop event on the floor if no one's listening */
|
||||
if (!event_is_open)
|
||||
return 0;
|
||||
|
||||
event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
|
||||
if (!event)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(event->device_class, device->pnp.device_class);
|
||||
strcpy(event->bus_id, device->pnp.bus_id);
|
||||
event->type = type;
|
||||
event->data = data;
|
||||
|
||||
spin_lock_irqsave(&acpi_bus_event_lock, flags);
|
||||
list_add_tail(&event->node, &acpi_bus_event_list);
|
||||
spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
|
||||
|
||||
wake_up_interruptible(&acpi_bus_event_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_generate_event);
|
||||
|
||||
int acpi_bus_receive_event(struct acpi_bus_event *event)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
struct acpi_bus_event *entry = NULL;
|
||||
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
|
||||
if (!event)
|
||||
return -EINVAL;
|
||||
|
||||
if (list_empty(&acpi_bus_event_list)) {
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&acpi_bus_event_queue, &wait);
|
||||
|
||||
if (list_empty(&acpi_bus_event_list))
|
||||
schedule();
|
||||
|
||||
remove_wait_queue(&acpi_bus_event_queue, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&acpi_bus_event_lock, flags);
|
||||
entry =
|
||||
list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node);
|
||||
if (entry)
|
||||
list_del(&entry->node);
|
||||
spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
|
||||
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
|
||||
memcpy(event, entry, sizeof(struct acpi_bus_event));
|
||||
|
||||
kfree(entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_receive_event);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Notification Handling
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
acpi_bus_check_device(struct acpi_device *device, int *status_changed)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
struct acpi_device_status old_status;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
if (status_changed)
|
||||
*status_changed = 0;
|
||||
|
||||
old_status = device->status;
|
||||
|
||||
/*
|
||||
* Make sure this device's parent is present before we go about
|
||||
* messing with the device.
|
||||
*/
|
||||
if (device->parent && !device->parent->status.present) {
|
||||
device->status = device->parent->status;
|
||||
if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) {
|
||||
if (status_changed)
|
||||
*status_changed = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = acpi_bus_get_status(device);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
|
||||
return 0;
|
||||
|
||||
if (status_changed)
|
||||
*status_changed = 1;
|
||||
|
||||
/*
|
||||
* Device Insertion/Removal
|
||||
*/
|
||||
if ((device->status.present) && !(old_status.present)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
|
||||
/* TBD: Handle device insertion */
|
||||
} else if (!(device->status.present) && (old_status.present)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
|
||||
/* TBD: Handle device removal */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_bus_check_scope(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
int status_changed = 0;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
/* Status Change? */
|
||||
result = acpi_bus_check_device(device, &status_changed);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (!status_changed)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* TBD: Enumerate child devices within this device's scope and
|
||||
* run acpi_bus_check_device()'s on them.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_bus_notify
|
||||
* ---------------
|
||||
* Callback for all 'system-level' device notifications (values 0x00-0x7F).
|
||||
*/
|
||||
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
|
||||
if (acpi_bus_get_device(handle, &device))
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received BUS CHECK notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
result = acpi_bus_check_scope(device);
|
||||
/*
|
||||
* TBD: We'll need to outsource certain events to non-ACPI
|
||||
* drivers via the device manager (device.c).
|
||||
*/
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received DEVICE CHECK notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
result = acpi_bus_check_device(device, NULL);
|
||||
/*
|
||||
* TBD: We'll need to outsource certain events to non-ACPI
|
||||
* drivers via the device manager (device.c).
|
||||
*/
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_DEVICE_WAKE:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received DEVICE WAKE notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
/* TBD */
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received EJECT REQUEST notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
/* TBD */
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received DEVICE CHECK LIGHT notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
/* TBD: Exactly what does 'light' mean? */
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received FREQUENCY MISMATCH notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
/* TBD */
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received BUS MODE MISMATCH notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
/* TBD */
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_POWER_FAULT:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received POWER FAULT notification for device [%s]\n",
|
||||
device->pnp.bus_id));
|
||||
/* TBD */
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Received unknown/unsupported notification [%08x]\n",
|
||||
type));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Initialization/Cleanup
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static int __init acpi_bus_init_irq(void)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
union acpi_object arg = { ACPI_TYPE_INTEGER };
|
||||
struct acpi_object_list arg_list = { 1, &arg };
|
||||
char *message = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Let the system know what interrupt model we are using by
|
||||
* evaluating the \_PIC object, if exists.
|
||||
*/
|
||||
|
||||
switch (acpi_irq_model) {
|
||||
case ACPI_IRQ_MODEL_PIC:
|
||||
message = "PIC";
|
||||
break;
|
||||
case ACPI_IRQ_MODEL_IOAPIC:
|
||||
message = "IOAPIC";
|
||||
break;
|
||||
case ACPI_IRQ_MODEL_IOSAPIC:
|
||||
message = "IOSAPIC";
|
||||
break;
|
||||
case ACPI_IRQ_MODEL_PLATFORM:
|
||||
message = "platform specific model";
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
|
||||
|
||||
arg.integer.value = acpi_irq_model;
|
||||
|
||||
status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
acpi_native_uint acpi_gbl_permanent_mmap;
|
||||
|
||||
|
||||
void __init acpi_early_init(void)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
|
||||
|
||||
/* enable workarounds, unless strict ACPI spec. compliance */
|
||||
if (!acpi_strict)
|
||||
acpi_gbl_enable_interpreter_slack = TRUE;
|
||||
|
||||
acpi_gbl_permanent_mmap = 1;
|
||||
|
||||
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) {
|
||||
extern u8 acpi_sci_flags;
|
||||
|
||||
/* 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 {
|
||||
extern int acpi_sci_override_gsi;
|
||||
/*
|
||||
* 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
|
||||
|
||||
status =
|
||||
acpi_enable_subsystem(~
|
||||
(ACPI_NO_HARDWARE_INIT |
|
||||
ACPI_NO_ACPI_ENABLE));
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
|
||||
goto error0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error0:
|
||||
disable_acpi();
|
||||
return;
|
||||
}
|
||||
|
||||
static int __init acpi_bus_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
extern acpi_status acpi_os_initialize1(void);
|
||||
|
||||
|
||||
status = acpi_os_initialize1();
|
||||
|
||||
status =
|
||||
acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Unable to start the ACPI Interpreter\n");
|
||||
goto error1;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Unable to initialize ACPI OS objects\n");
|
||||
goto error1;
|
||||
}
|
||||
#ifdef CONFIG_ACPI_EC
|
||||
/*
|
||||
* ACPI 2.0 requires the EC driver to be loaded and work before
|
||||
* the EC device is found in the namespace (i.e. before acpi_initialize_objects()
|
||||
* is called).
|
||||
*
|
||||
* This is accomplished by looking for the ECDT table, and getting
|
||||
* the EC parameters out of that.
|
||||
*/
|
||||
status = acpi_ec_ecdt_probe();
|
||||
/* Ignore result. Not having an ECDT is not fatal. */
|
||||
#endif
|
||||
|
||||
status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
|
||||
goto error1;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "Interpreter enabled\n");
|
||||
|
||||
/* Initialize sleep structures */
|
||||
acpi_sleep_init();
|
||||
|
||||
/*
|
||||
* Get the system interrupt model and evaluate \_PIC.
|
||||
*/
|
||||
result = acpi_bus_init_irq();
|
||||
if (result)
|
||||
goto error1;
|
||||
|
||||
/*
|
||||
* Register the for all standard device notifications.
|
||||
*/
|
||||
status =
|
||||
acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
|
||||
&acpi_bus_notify, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Unable to register for device notifications\n");
|
||||
goto error1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the top ACPI proc directory
|
||||
*/
|
||||
acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
/* Mimic structured exception handling */
|
||||
error1:
|
||||
acpi_terminate();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
decl_subsys(acpi, NULL, NULL);
|
||||
|
||||
static int __init acpi_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
|
||||
if (acpi_disabled) {
|
||||
printk(KERN_INFO PREFIX "Interpreter disabled.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = firmware_register(&acpi_subsys);
|
||||
if (result < 0)
|
||||
printk(KERN_WARNING "%s: firmware_register error: %d\n",
|
||||
__FUNCTION__, result);
|
||||
|
||||
result = acpi_bus_init();
|
||||
|
||||
if (!result) {
|
||||
#ifdef CONFIG_PM_LEGACY
|
||||
if (!PM_IS_ACTIVE())
|
||||
pm_active = 1;
|
||||
else {
|
||||
printk(KERN_INFO PREFIX
|
||||
"APM is already active, exiting\n");
|
||||
disable_acpi();
|
||||
result = -ENODEV;
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
disable_acpi();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_init);
|
||||
521
drivers/acpi/button.c
Normal file
521
drivers/acpi/button.c
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* acpi_button.c - ACPI Button Driver ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||
* 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.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/input.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define ACPI_BUTTON_COMPONENT 0x00080000
|
||||
#define ACPI_BUTTON_CLASS "button"
|
||||
#define ACPI_BUTTON_FILE_INFO "info"
|
||||
#define ACPI_BUTTON_FILE_STATE "state"
|
||||
#define ACPI_BUTTON_TYPE_UNKNOWN 0x00
|
||||
#define ACPI_BUTTON_NOTIFY_STATUS 0x80
|
||||
|
||||
#define ACPI_BUTTON_SUBCLASS_POWER "power"
|
||||
#define ACPI_BUTTON_HID_POWER "PNP0C0C"
|
||||
#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)"
|
||||
#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)"
|
||||
#define ACPI_BUTTON_TYPE_POWER 0x01
|
||||
#define ACPI_BUTTON_TYPE_POWERF 0x02
|
||||
|
||||
#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep"
|
||||
#define ACPI_BUTTON_HID_SLEEP "PNP0C0E"
|
||||
#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)"
|
||||
#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)"
|
||||
#define ACPI_BUTTON_TYPE_SLEEP 0x03
|
||||
#define ACPI_BUTTON_TYPE_SLEEPF 0x04
|
||||
|
||||
#define ACPI_BUTTON_SUBCLASS_LID "lid"
|
||||
#define ACPI_BUTTON_HID_LID "PNP0C0D"
|
||||
#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
|
||||
#define ACPI_BUTTON_TYPE_LID 0x05
|
||||
|
||||
#define _COMPONENT ACPI_BUTTON_COMPONENT
|
||||
ACPI_MODULE_NAME("button");
|
||||
|
||||
MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_DESCRIPTION("ACPI Button Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int acpi_button_add(struct acpi_device *device);
|
||||
static int acpi_button_remove(struct acpi_device *device, int type);
|
||||
static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
|
||||
static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
|
||||
|
||||
static struct acpi_driver acpi_button_driver = {
|
||||
.name = "button",
|
||||
.class = ACPI_BUTTON_CLASS,
|
||||
.ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
|
||||
.ops = {
|
||||
.add = acpi_button_add,
|
||||
.remove = acpi_button_remove,
|
||||
},
|
||||
};
|
||||
|
||||
struct acpi_button {
|
||||
struct acpi_device *device; /* Fixed button kludge */
|
||||
unsigned int type;
|
||||
struct input_dev *input;
|
||||
char phys[32]; /* for input device */
|
||||
unsigned long pushed;
|
||||
};
|
||||
|
||||
static const struct file_operations acpi_button_info_fops = {
|
||||
.open = acpi_button_info_open_fs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct file_operations acpi_button_state_fops = {
|
||||
.open = acpi_button_state_open_fs,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static struct proc_dir_entry *acpi_button_dir;
|
||||
|
||||
static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_button *button = seq->private;
|
||||
|
||||
if (!button || !button->device)
|
||||
return 0;
|
||||
|
||||
seq_printf(seq, "type: %s\n",
|
||||
acpi_device_name(button->device));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_button *button = seq->private;
|
||||
acpi_status status;
|
||||
unsigned long state;
|
||||
|
||||
if (!button || !button->device)
|
||||
return 0;
|
||||
|
||||
status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
|
||||
seq_printf(seq, "state: %s\n",
|
||||
ACPI_FAILURE(status) ? "unsupported" :
|
||||
(state ? "open" : "closed"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static struct proc_dir_entry *acpi_power_dir;
|
||||
static struct proc_dir_entry *acpi_sleep_dir;
|
||||
static struct proc_dir_entry *acpi_lid_dir;
|
||||
|
||||
static int acpi_button_add_fs(struct acpi_device *device)
|
||||
{
|
||||
struct proc_dir_entry *entry = NULL;
|
||||
struct acpi_button *button;
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
button = acpi_driver_data(device);
|
||||
|
||||
switch (button->type) {
|
||||
case ACPI_BUTTON_TYPE_POWER:
|
||||
case ACPI_BUTTON_TYPE_POWERF:
|
||||
if (!acpi_power_dir)
|
||||
acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
|
||||
acpi_button_dir);
|
||||
entry = acpi_power_dir;
|
||||
break;
|
||||
case ACPI_BUTTON_TYPE_SLEEP:
|
||||
case ACPI_BUTTON_TYPE_SLEEPF:
|
||||
if (!acpi_sleep_dir)
|
||||
acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
|
||||
acpi_button_dir);
|
||||
entry = acpi_sleep_dir;
|
||||
break;
|
||||
case ACPI_BUTTON_TYPE_LID:
|
||||
if (!acpi_lid_dir)
|
||||
acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
|
||||
acpi_button_dir);
|
||||
entry = acpi_lid_dir;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
entry->owner = THIS_MODULE;
|
||||
|
||||
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
|
||||
if (!acpi_device_dir(device))
|
||||
return -ENODEV;
|
||||
acpi_device_dir(device)->owner = THIS_MODULE;
|
||||
|
||||
/* 'info' [R] */
|
||||
entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
|
||||
S_IRUGO, acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_button_info_fops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
/* show lid state [R] */
|
||||
if (button->type == ACPI_BUTTON_TYPE_LID) {
|
||||
entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
|
||||
S_IRUGO, acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_button_state_fops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_button_remove_fs(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_button *button = acpi_driver_data(device);
|
||||
|
||||
if (acpi_device_dir(device)) {
|
||||
if (button->type == ACPI_BUTTON_TYPE_LID)
|
||||
remove_proc_entry(ACPI_BUTTON_FILE_STATE,
|
||||
acpi_device_dir(device));
|
||||
remove_proc_entry(ACPI_BUTTON_FILE_INFO,
|
||||
acpi_device_dir(device));
|
||||
|
||||
remove_proc_entry(acpi_device_bid(device),
|
||||
acpi_device_dir(device)->parent);
|
||||
acpi_device_dir(device) = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Driver Interface
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_button *button = data;
|
||||
struct input_dev *input;
|
||||
|
||||
if (!button || !button->device)
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
case ACPI_BUTTON_NOTIFY_STATUS:
|
||||
input = button->input;
|
||||
|
||||
if (button->type == ACPI_BUTTON_TYPE_LID) {
|
||||
struct acpi_handle *handle = button->device->handle;
|
||||
unsigned long state;
|
||||
|
||||
if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
|
||||
NULL, &state)))
|
||||
input_report_switch(input, SW_LID, !state);
|
||||
|
||||
} else {
|
||||
int keycode = test_bit(KEY_SLEEP, input->keybit) ?
|
||||
KEY_SLEEP : KEY_POWER;
|
||||
|
||||
input_report_key(input, keycode, 1);
|
||||
input_sync(input);
|
||||
input_report_key(input, keycode, 0);
|
||||
}
|
||||
input_sync(input);
|
||||
|
||||
acpi_bus_generate_event(button->device, event,
|
||||
++button->pushed);
|
||||
break;
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Unsupported event [0x%x]\n", event));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static acpi_status acpi_button_notify_fixed(void *data)
|
||||
{
|
||||
struct acpi_button *button = data;
|
||||
|
||||
if (!button)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
acpi_button_notify(button->device->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int acpi_button_install_notify_handlers(struct acpi_button *button)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
switch (button->type) {
|
||||
case ACPI_BUTTON_TYPE_POWERF:
|
||||
status =
|
||||
acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
|
||||
acpi_button_notify_fixed,
|
||||
button);
|
||||
break;
|
||||
case ACPI_BUTTON_TYPE_SLEEPF:
|
||||
status =
|
||||
acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
|
||||
acpi_button_notify_fixed,
|
||||
button);
|
||||
break;
|
||||
default:
|
||||
status = acpi_install_notify_handler(button->device->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_button_notify,
|
||||
button);
|
||||
break;
|
||||
}
|
||||
|
||||
return ACPI_FAILURE(status) ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static void acpi_button_remove_notify_handlers(struct acpi_button *button)
|
||||
{
|
||||
switch (button->type) {
|
||||
case ACPI_BUTTON_TYPE_POWERF:
|
||||
acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
|
||||
acpi_button_notify_fixed);
|
||||
break;
|
||||
case ACPI_BUTTON_TYPE_SLEEPF:
|
||||
acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
|
||||
acpi_button_notify_fixed);
|
||||
break;
|
||||
default:
|
||||
acpi_remove_notify_handler(button->device->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_button_notify);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_button_add(struct acpi_device *device)
|
||||
{
|
||||
int error;
|
||||
struct acpi_button *button;
|
||||
struct input_dev *input;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
|
||||
if (!button)
|
||||
return -ENOMEM;
|
||||
|
||||
button->device = device;
|
||||
acpi_driver_data(device) = button;
|
||||
|
||||
button->input = input = input_allocate_device();
|
||||
if (!input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_button;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the button type (via hid), as fixed-feature buttons
|
||||
* need to be handled a bit differently than generic-space.
|
||||
*/
|
||||
if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
|
||||
button->type = ACPI_BUTTON_TYPE_POWER;
|
||||
strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_POWER);
|
||||
sprintf(acpi_device_class(device), "%s/%s",
|
||||
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
|
||||
} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
|
||||
button->type = ACPI_BUTTON_TYPE_POWERF;
|
||||
strcpy(acpi_device_name(device),
|
||||
ACPI_BUTTON_DEVICE_NAME_POWERF);
|
||||
sprintf(acpi_device_class(device), "%s/%s",
|
||||
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
|
||||
} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
|
||||
button->type = ACPI_BUTTON_TYPE_SLEEP;
|
||||
strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_SLEEP);
|
||||
sprintf(acpi_device_class(device), "%s/%s",
|
||||
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
|
||||
} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
|
||||
button->type = ACPI_BUTTON_TYPE_SLEEPF;
|
||||
strcpy(acpi_device_name(device),
|
||||
ACPI_BUTTON_DEVICE_NAME_SLEEPF);
|
||||
sprintf(acpi_device_class(device), "%s/%s",
|
||||
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
|
||||
} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
|
||||
button->type = ACPI_BUTTON_TYPE_LID;
|
||||
strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_LID);
|
||||
sprintf(acpi_device_class(device), "%s/%s",
|
||||
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
|
||||
} else {
|
||||
printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
|
||||
acpi_device_hid(device));
|
||||
error = -ENODEV;
|
||||
goto err_free_input;
|
||||
}
|
||||
|
||||
error = acpi_button_add_fs(device);
|
||||
if (error)
|
||||
goto err_free_input;
|
||||
|
||||
error = acpi_button_install_notify_handlers(button);
|
||||
if (error)
|
||||
goto err_remove_fs;
|
||||
|
||||
snprintf(button->phys, sizeof(button->phys),
|
||||
"%s/button/input0", acpi_device_hid(device));
|
||||
|
||||
input->name = acpi_device_name(device);
|
||||
input->phys = button->phys;
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.product = button->type;
|
||||
|
||||
switch (button->type) {
|
||||
case ACPI_BUTTON_TYPE_POWER:
|
||||
case ACPI_BUTTON_TYPE_POWERF:
|
||||
input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_POWER, input->keybit);
|
||||
break;
|
||||
|
||||
case ACPI_BUTTON_TYPE_SLEEP:
|
||||
case ACPI_BUTTON_TYPE_SLEEPF:
|
||||
input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_SLEEP, input->keybit);
|
||||
break;
|
||||
|
||||
case ACPI_BUTTON_TYPE_LID:
|
||||
input->evbit[0] = BIT(EV_SW);
|
||||
set_bit(SW_LID, input->swbit);
|
||||
break;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error)
|
||||
goto err_remove_handlers;
|
||||
|
||||
if (device->wakeup.flags.valid) {
|
||||
/* Button's GPE is run-wake GPE */
|
||||
acpi_set_gpe_type(device->wakeup.gpe_device,
|
||||
device->wakeup.gpe_number,
|
||||
ACPI_GPE_TYPE_WAKE_RUN);
|
||||
acpi_enable_gpe(device->wakeup.gpe_device,
|
||||
device->wakeup.gpe_number, ACPI_NOT_ISR);
|
||||
device->wakeup.state.enabled = 1;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "%s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_handlers:
|
||||
acpi_button_remove_notify_handlers(button);
|
||||
err_remove_fs:
|
||||
acpi_button_remove_fs(device);
|
||||
err_free_input:
|
||||
input_free_device(input);
|
||||
err_free_button:
|
||||
kfree(button);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int acpi_button_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct acpi_button *button;
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
button = acpi_driver_data(device);
|
||||
|
||||
acpi_button_remove_notify_handlers(button);
|
||||
acpi_button_remove_fs(device);
|
||||
input_unregister_device(button->input);
|
||||
kfree(button);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init acpi_button_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
|
||||
if (!acpi_button_dir)
|
||||
return -ENODEV;
|
||||
acpi_button_dir->owner = THIS_MODULE;
|
||||
result = acpi_bus_register_driver(&acpi_button_driver);
|
||||
if (result < 0) {
|
||||
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_button_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_button_driver);
|
||||
|
||||
if (acpi_power_dir)
|
||||
remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir);
|
||||
if (acpi_sleep_dir)
|
||||
remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir);
|
||||
if (acpi_lid_dir)
|
||||
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
|
||||
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
|
||||
}
|
||||
|
||||
module_init(acpi_button_init);
|
||||
module_exit(acpi_button_exit);
|
||||
113
drivers/acpi/cm_sbs.c
Normal file
113
drivers/acpi/cm_sbs.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acmacros.h>
|
||||
#include <acpi/actypes.h>
|
||||
#include <acpi/acutils.h>
|
||||
|
||||
ACPI_MODULE_NAME("cm_sbs");
|
||||
#define ACPI_AC_CLASS "ac_adapter"
|
||||
#define ACPI_BATTERY_CLASS "battery"
|
||||
#define ACPI_SBS_COMPONENT 0x00080000
|
||||
#define _COMPONENT ACPI_SBS_COMPONENT
|
||||
static struct proc_dir_entry *acpi_ac_dir;
|
||||
static struct proc_dir_entry *acpi_battery_dir;
|
||||
|
||||
static DEFINE_MUTEX(cm_sbs_mutex);
|
||||
|
||||
static int lock_ac_dir_cnt;
|
||||
static int lock_battery_dir_cnt;
|
||||
|
||||
struct proc_dir_entry *acpi_lock_ac_dir(void)
|
||||
{
|
||||
mutex_lock(&cm_sbs_mutex);
|
||||
if (!acpi_ac_dir)
|
||||
acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
|
||||
if (acpi_ac_dir) {
|
||||
lock_ac_dir_cnt++;
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Cannot create %s\n", ACPI_AC_CLASS));
|
||||
}
|
||||
mutex_unlock(&cm_sbs_mutex);
|
||||
return acpi_ac_dir;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_lock_ac_dir);
|
||||
|
||||
void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)
|
||||
{
|
||||
mutex_lock(&cm_sbs_mutex);
|
||||
if (acpi_ac_dir_param)
|
||||
lock_ac_dir_cnt--;
|
||||
if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
|
||||
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
|
||||
acpi_ac_dir = NULL;
|
||||
}
|
||||
mutex_unlock(&cm_sbs_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_unlock_ac_dir);
|
||||
|
||||
struct proc_dir_entry *acpi_lock_battery_dir(void)
|
||||
{
|
||||
mutex_lock(&cm_sbs_mutex);
|
||||
if (!acpi_battery_dir) {
|
||||
acpi_battery_dir =
|
||||
proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
|
||||
}
|
||||
if (acpi_battery_dir) {
|
||||
lock_battery_dir_cnt++;
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Cannot create %s\n", ACPI_BATTERY_CLASS));
|
||||
}
|
||||
mutex_unlock(&cm_sbs_mutex);
|
||||
return acpi_battery_dir;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_lock_battery_dir);
|
||||
|
||||
void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)
|
||||
{
|
||||
mutex_lock(&cm_sbs_mutex);
|
||||
if (acpi_battery_dir_param)
|
||||
lock_battery_dir_cnt--;
|
||||
if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
|
||||
&& acpi_battery_dir) {
|
||||
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
|
||||
acpi_battery_dir = NULL;
|
||||
}
|
||||
mutex_unlock(&cm_sbs_mutex);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_unlock_battery_dir);
|
||||
|
||||
static int __init acpi_cm_sbs_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(acpi_cm_sbs_init);
|
||||
277
drivers/acpi/container.c
Normal file
277
drivers/acpi/container.c
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* acpi_container.c - ACPI Generic Container Driver
|
||||
* ($Revision: )
|
||||
*
|
||||
* Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
|
||||
* Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
|
||||
* Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
|
||||
* Copyright (C) 2004 Intel Corp.
|
||||
* Copyright (C) 2004 FUJITSU LIMITED
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/container.h>
|
||||
|
||||
#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
|
||||
#define ACPI_CONTAINER_CLASS "container"
|
||||
|
||||
#define INSTALL_NOTIFY_HANDLER 1
|
||||
#define UNINSTALL_NOTIFY_HANDLER 2
|
||||
|
||||
#define ACPI_CONTAINER_COMPONENT 0x01000000
|
||||
#define _COMPONENT ACPI_CONTAINER_COMPONENT
|
||||
ACPI_MODULE_NAME("container");
|
||||
|
||||
MODULE_AUTHOR("Anil S Keshavamurthy");
|
||||
MODULE_DESCRIPTION("ACPI container driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define ACPI_STA_PRESENT (0x00000001)
|
||||
|
||||
static int acpi_container_add(struct acpi_device *device);
|
||||
static int acpi_container_remove(struct acpi_device *device, int type);
|
||||
|
||||
static struct acpi_driver acpi_container_driver = {
|
||||
.name = "container",
|
||||
.class = ACPI_CONTAINER_CLASS,
|
||||
.ids = "ACPI0004,PNP0A05,PNP0A06",
|
||||
.ops = {
|
||||
.add = acpi_container_add,
|
||||
.remove = acpi_container_remove,
|
||||
},
|
||||
};
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static int is_device_present(acpi_handle handle)
|
||||
{
|
||||
acpi_handle temp;
|
||||
acpi_status status;
|
||||
unsigned long sta;
|
||||
|
||||
|
||||
status = acpi_get_handle(handle, "_STA", &temp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 1; /* _STA not found, assmue device present */
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0; /* Firmware error */
|
||||
|
||||
return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
static int acpi_container_add(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_container *container;
|
||||
|
||||
|
||||
if (!device) {
|
||||
printk(KERN_ERR PREFIX "device is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
|
||||
if (!container)
|
||||
return -ENOMEM;
|
||||
|
||||
container->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
|
||||
acpi_driver_data(device) = container;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
|
||||
acpi_device_name(device), acpi_device_bid(device)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_container_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_container *pc = NULL;
|
||||
|
||||
pc = acpi_driver_data(device);
|
||||
kfree(pc);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int container_device_add(struct acpi_device **device, acpi_handle handle)
|
||||
{
|
||||
acpi_handle phandle;
|
||||
struct acpi_device *pdev;
|
||||
int result;
|
||||
|
||||
|
||||
if (acpi_get_parent(handle, &phandle)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (acpi_bus_get_device(phandle, &pdev)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = acpi_bus_start(*device);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
int result;
|
||||
int present;
|
||||
acpi_status status;
|
||||
|
||||
|
||||
present = is_device_present(handle);
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
/* Fall through */
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
printk("Container driver received %s event\n",
|
||||
(type == ACPI_NOTIFY_BUS_CHECK) ?
|
||||
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
|
||||
status = acpi_bus_get_device(handle, &device);
|
||||
if (present) {
|
||||
if (ACPI_FAILURE(status) || !device) {
|
||||
result = container_device_add(&device, handle);
|
||||
if (!result)
|
||||
kobject_uevent(&device->dev.kobj,
|
||||
KOBJ_ONLINE);
|
||||
else
|
||||
printk("Failed to add container\n");
|
||||
}
|
||||
} else {
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
/* device exist and this is a remove request */
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
if (!acpi_bus_get_device(handle, &device) && device) {
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
container_walk_namespace_cb(acpi_handle handle,
|
||||
u32 lvl, void *context, void **rv)
|
||||
{
|
||||
char *hid = NULL;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_device_info *info;
|
||||
acpi_status status;
|
||||
int *action = context;
|
||||
|
||||
|
||||
status = acpi_get_object_info(handle, &buffer);
|
||||
if (ACPI_FAILURE(status) || !buffer.pointer) {
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
info = buffer.pointer;
|
||||
if (info->valid & ACPI_VALID_HID)
|
||||
hid = info->hardware_id.value;
|
||||
|
||||
if (hid == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
|
||||
strcmp(hid, "PNP0A06")) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch (*action) {
|
||||
case INSTALL_NOTIFY_HANDLER:
|
||||
acpi_install_notify_handler(handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
container_notify_cb, NULL);
|
||||
break;
|
||||
case UNINSTALL_NOTIFY_HANDLER:
|
||||
acpi_remove_notify_handler(handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
container_notify_cb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int __init acpi_container_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
int action = INSTALL_NOTIFY_HANDLER;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_container_driver);
|
||||
if (result < 0) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* register notify handler to every container device */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE,
|
||||
ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX,
|
||||
container_walk_namespace_cb, &action, NULL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void __exit acpi_container_exit(void)
|
||||
{
|
||||
int action = UNINSTALL_NOTIFY_HANDLER;
|
||||
|
||||
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE,
|
||||
ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX,
|
||||
container_walk_namespace_cb, &action, NULL);
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_container_driver);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acpi_container_init);
|
||||
module_exit(acpi_container_exit);
|
||||
275
drivers/acpi/debug.c
Normal file
275
drivers/acpi/debug.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* debug.c - ACPI debug interface to userspace.
|
||||
*/
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acglobal.h>
|
||||
|
||||
#define _COMPONENT ACPI_SYSTEM_COMPONENT
|
||||
ACPI_MODULE_NAME("debug");
|
||||
|
||||
#ifdef MODULE_PARAM_PREFIX
|
||||
#undef MODULE_PARAM_PREFIX
|
||||
#endif
|
||||
#define MODULE_PARAM_PREFIX "acpi."
|
||||
|
||||
struct acpi_dlayer {
|
||||
const char *name;
|
||||
unsigned long value;
|
||||
};
|
||||
struct acpi_dlevel {
|
||||
const char *name;
|
||||
unsigned long value;
|
||||
};
|
||||
#define ACPI_DEBUG_INIT(v) { .name = #v, .value = v }
|
||||
|
||||
static const struct acpi_dlayer acpi_debug_layers[] = {
|
||||
ACPI_DEBUG_INIT(ACPI_UTILITIES),
|
||||
ACPI_DEBUG_INIT(ACPI_HARDWARE),
|
||||
ACPI_DEBUG_INIT(ACPI_EVENTS),
|
||||
ACPI_DEBUG_INIT(ACPI_TABLES),
|
||||
ACPI_DEBUG_INIT(ACPI_NAMESPACE),
|
||||
ACPI_DEBUG_INIT(ACPI_PARSER),
|
||||
ACPI_DEBUG_INIT(ACPI_DISPATCHER),
|
||||
ACPI_DEBUG_INIT(ACPI_EXECUTER),
|
||||
ACPI_DEBUG_INIT(ACPI_RESOURCES),
|
||||
ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER),
|
||||
ACPI_DEBUG_INIT(ACPI_OS_SERVICES),
|
||||
ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER),
|
||||
ACPI_DEBUG_INIT(ACPI_COMPILER),
|
||||
ACPI_DEBUG_INIT(ACPI_TOOLS),
|
||||
};
|
||||
|
||||
static const struct acpi_dlevel acpi_debug_levels[] = {
|
||||
ACPI_DEBUG_INIT(ACPI_LV_ERROR),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_WARN),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_INIT),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_INFO),
|
||||
|
||||
ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_PARSE),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_LOAD),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_DISPATCH),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_EXEC),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_NAMES),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_OPREGION),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_BFIELD),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_TABLES),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_VALUES),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_OBJECTS),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_RESOURCES),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_PACKAGE),
|
||||
|
||||
ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS),
|
||||
|
||||
ACPI_DEBUG_INIT(ACPI_LV_MUTEX),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_THREADS),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_IO),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS),
|
||||
|
||||
ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/sys)
|
||||
-------------------------------------------------------------------------- */
|
||||
static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
|
||||
|
||||
for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) {
|
||||
result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
|
||||
acpi_debug_layers[i].name,
|
||||
acpi_debug_layers[i].value,
|
||||
(acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' ');
|
||||
}
|
||||
result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
|
||||
ACPI_ALL_DRIVERS,
|
||||
(acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
|
||||
ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
|
||||
ACPI_ALL_DRIVERS) == 0 ? ' ' : '-');
|
||||
result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
|
||||
result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
|
||||
acpi_debug_levels[i].name,
|
||||
acpi_debug_levels[i].value,
|
||||
(acpi_dbg_level & acpi_debug_levels[i].
|
||||
value) ? '*' : ' ');
|
||||
}
|
||||
result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n",
|
||||
acpi_dbg_level);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
|
||||
module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
|
||||
#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
|
||||
|
||||
static int
|
||||
acpi_system_read_debug(char *page,
|
||||
char **start, off_t off, int count, int *eof, void *data)
|
||||
{
|
||||
char *p = page;
|
||||
int size = 0;
|
||||
unsigned int i;
|
||||
|
||||
if (off != 0)
|
||||
goto end;
|
||||
|
||||
p += sprintf(p, "%-25s\tHex SET\n", "Description");
|
||||
|
||||
switch ((unsigned long)data) {
|
||||
case 0:
|
||||
for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
|
||||
p += sprintf(p, "%-25s\t0x%08lX [%c]\n",
|
||||
acpi_debug_layers[i].name,
|
||||
acpi_debug_layers[i].value,
|
||||
(acpi_dbg_layer & acpi_debug_layers[i].
|
||||
value) ? '*' : ' ');
|
||||
}
|
||||
p += sprintf(p, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
|
||||
ACPI_ALL_DRIVERS,
|
||||
(acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
|
||||
ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
|
||||
ACPI_ALL_DRIVERS) ==
|
||||
0 ? ' ' : '-');
|
||||
p += sprintf(p,
|
||||
"--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n",
|
||||
acpi_dbg_layer);
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
|
||||
p += sprintf(p, "%-25s\t0x%08lX [%c]\n",
|
||||
acpi_debug_levels[i].name,
|
||||
acpi_debug_levels[i].value,
|
||||
(acpi_dbg_level & acpi_debug_levels[i].
|
||||
value) ? '*' : ' ');
|
||||
}
|
||||
p += sprintf(p, "--\ndebug_level = 0x%08X (* = enabled)\n",
|
||||
acpi_dbg_level);
|
||||
break;
|
||||
default:
|
||||
p += sprintf(p, "Invalid debug option\n");
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
size = (p - page);
|
||||
if (size <= off + count)
|
||||
*eof = 1;
|
||||
*start = page + off;
|
||||
size -= off;
|
||||
if (size > count)
|
||||
size = count;
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_system_write_debug(struct file *file,
|
||||
const char __user * buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
char debug_string[12] = { '\0' };
|
||||
|
||||
|
||||
if (count > sizeof(debug_string) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(debug_string, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
debug_string[count] = '\0';
|
||||
|
||||
switch ((unsigned long)data) {
|
||||
case 0:
|
||||
acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0);
|
||||
break;
|
||||
case 1:
|
||||
acpi_dbg_level = simple_strtoul(debug_string, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int __init acpi_debug_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
int error = 0;
|
||||
char *name;
|
||||
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
/* 'debug_layer' [R/W] */
|
||||
name = ACPI_SYSTEM_FILE_DEBUG_LAYER;
|
||||
entry =
|
||||
create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
|
||||
acpi_root_dir, acpi_system_read_debug,
|
||||
(void *)0);
|
||||
if (entry)
|
||||
entry->write_proc = acpi_system_write_debug;
|
||||
else
|
||||
goto Error;
|
||||
|
||||
/* 'debug_level' [R/W] */
|
||||
name = ACPI_SYSTEM_FILE_DEBUG_LEVEL;
|
||||
entry =
|
||||
create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
|
||||
acpi_root_dir, acpi_system_read_debug,
|
||||
(void *)1);
|
||||
if (entry)
|
||||
entry->write_proc = acpi_system_write_debug;
|
||||
else
|
||||
goto Error;
|
||||
|
||||
Done:
|
||||
return error;
|
||||
|
||||
Error:
|
||||
remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir);
|
||||
remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir);
|
||||
error = -ENODEV;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_debug_init);
|
||||
#endif
|
||||
9
drivers/acpi/dispatcher/Makefile
Normal file
9
drivers/acpi/dispatcher/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for all Linux ACPI interpreter subdirectories
|
||||
#
|
||||
|
||||
obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
|
||||
dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \
|
||||
dsinit.o
|
||||
|
||||
EXTRA_CFLAGS += $(ACPI_CFLAGS)
|
||||
625
drivers/acpi/dispatcher/dsfield.c
Normal file
625
drivers/acpi/dispatcher/dsfield.c
Normal file
@@ -0,0 +1,625 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: dsfield - Dispatcher field routines
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/amlcode.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
|
||||
#define _COMPONENT ACPI_DISPATCHER
|
||||
ACPI_MODULE_NAME("dsfield")
|
||||
|
||||
/* Local prototypes */
|
||||
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);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 */
|
||||
|
||||
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
|
||||
arg = acpi_ps_get_arg(op, 3);
|
||||
} else {
|
||||
/* Create Bit/Byte/Word/Dword field */
|
||||
|
||||
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 {
|
||||
/*
|
||||
* During the load phase, we want to enter the name of the field into
|
||||
* the namespace. During the execute phase (when we evaluate the size
|
||||
* operand), we want to lookup the name
|
||||
*/
|
||||
if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
|
||||
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
|
||||
} else {
|
||||
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
|
||||
ACPI_NS_ERROR_IF_FOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
acpi_integer position;
|
||||
|
||||
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) {
|
||||
/*
|
||||
* Three types of field elements are handled:
|
||||
* 1) Offset - specifies a bit offset
|
||||
* 2) access_as - changes the access mode
|
||||
* 3) Name - Enters a new named field into the namespace
|
||||
*/
|
||||
switch (arg->common.aml_opcode) {
|
||||
case AML_INT_RESERVEDFIELD_OP:
|
||||
|
||||
position = (acpi_integer) info->field_bit_position
|
||||
+ (acpi_integer) 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:
|
||||
|
||||
/*
|
||||
* Get a new access_type and access_attribute -- to be used for all
|
||||
* field units that follow, until field end or another access_as
|
||||
* keyword.
|
||||
*
|
||||
* In field_flags, preserve the flag bits other than the
|
||||
* ACCESS_TYPE bits
|
||||
*/
|
||||
info->field_flags = (u8)
|
||||
((info->
|
||||
field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
|
||||
((u8) ((u32) arg->common.value.integer >> 8)));
|
||||
|
||||
info->attribute = (u8) (arg->common.value.integer);
|
||||
break;
|
||||
|
||||
case AML_INT_NAMEDFIELD_OP:
|
||||
|
||||
/* Lookup the name */
|
||||
|
||||
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);
|
||||
if (status != AE_ALREADY_EXISTS) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Already exists, ignore error */
|
||||
} else {
|
||||
arg->common.node = info->field_node;
|
||||
info->field_bit_length = arg->common.value.size;
|
||||
|
||||
/* Create and initialize an object for the new 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 = (acpi_integer) info->field_bit_position
|
||||
+ (acpi_integer) 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;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Invalid opcode in field list: %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);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the list of entries in the field_list
|
||||
*/
|
||||
while (arg) {
|
||||
|
||||
/* Ignore OFFSET and ACCESSAS terms here */
|
||||
|
||||
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,
|
||||
ACPI_NS_NO_UPSEARCH |
|
||||
ACPI_NS_DONT_OPEN_SCOPE |
|
||||
ACPI_NS_ERROR_IF_FOUND,
|
||||
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;
|
||||
}
|
||||
|
||||
/* Move to next field 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);
|
||||
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 */
|
||||
|
||||
/* TBD: This arg is a term_arg, not a constant, and must be evaluated */
|
||||
|
||||
arg = arg->common.next;
|
||||
|
||||
/* Currently, only the following constants are supported */
|
||||
|
||||
switch (arg->common.aml_opcode) {
|
||||
case AML_ZERO_OP:
|
||||
info.bank_value = 0;
|
||||
break;
|
||||
|
||||
case AML_ONE_OP:
|
||||
info.bank_value = 1;
|
||||
break;
|
||||
|
||||
case AML_BYTE_OP:
|
||||
case AML_WORD_OP:
|
||||
case AML_DWORD_OP:
|
||||
case AML_QWORD_OP:
|
||||
info.bank_value = (u32) arg->common.value.integer;
|
||||
break;
|
||||
|
||||
default:
|
||||
info.bank_value = 0;
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Non-constant BankValue for BankField is not implemented"));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
204
drivers/acpi/dispatcher/dsinit.c
Normal file
204
drivers/acpi/dispatcher/dsinit.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: dsinit - Object initialization namespace walk
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acdispat.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/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_object_type type;
|
||||
acpi_status status;
|
||||
|
||||
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 */
|
||||
|
||||
type = acpi_ns_get_type(obj_handle);
|
||||
|
||||
switch (type) {
|
||||
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:
|
||||
|
||||
info->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(acpi_native_uint 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"));
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
|
||||
|
||||
info.method_count = 0;
|
||||
info.op_region_count = 0;
|
||||
info.object_count = 0;
|
||||
info.device_count = 0;
|
||||
info.table_index = table_index;
|
||||
info.owner_id = owner_id;
|
||||
|
||||
/* Walk entire namespace from the supplied root */
|
||||
|
||||
status = acpi_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
|
||||
acpi_ds_init_one_object, &info, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
|
||||
}
|
||||
|
||||
status = acpi_get_table_by_index(table_index, &table);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
|
||||
"\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
|
||||
table->signature, owner_id, info.object_count,
|
||||
info.device_count, info.method_count,
|
||||
info.op_region_count));
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
|
||||
"%hd Methods, %hd Regions\n", info.method_count,
|
||||
info.op_region_count));
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
630
drivers/acpi/dispatcher/dsmethod.c
Normal file
630
drivers/acpi/dispatcher/dsmethod.c
Normal file
@@ -0,0 +1,630 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: dsmethod - Parser/Interpreter interface - control method parsing
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acparser.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acdisasm.h>
|
||||
|
||||
#define _COMPONENT ACPI_DISPATCHER
|
||||
ACPI_MODULE_NAME("dsmethod")
|
||||
|
||||
/* Local prototypes */
|
||||
static acpi_status
|
||||
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 disassembler 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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
status = acpi_gbl_exception_handler(status,
|
||||
walk_state->method_node ?
|
||||
walk_state->method_node->
|
||||
name.integer : 0,
|
||||
walk_state->opcode,
|
||||
walk_state->aml_offset,
|
||||
NULL);
|
||||
(void)acpi_ex_enter_interpreter();
|
||||
}
|
||||
#ifdef ACPI_DISASSEMBLER
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
||||
/* Display method locals/args if disassembler is present */
|
||||
|
||||
acpi_dm_dump_method_info(status, walk_state, walk_state->op);
|
||||
}
|
||||
#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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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.method_flags & AML_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
|
||||
*
|
||||
* Top-level method invocation has no walk state at this point
|
||||
*/
|
||||
if (walk_state &&
|
||||
(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 (%d)",
|
||||
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 (acpi_os_get_thread_id() !=
|
||||
obj_desc->method.mutex->mutex.owner_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 */
|
||||
obj_desc->method.mutex->mutex.owner_thread_id =
|
||||
acpi_os_get_thread_id();
|
||||
|
||||
if (walk_state) {
|
||||
obj_desc->method.mutex->mutex.
|
||||
original_sync_level =
|
||||
walk_state->thread->current_sync_level;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
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) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
info->parameters = &this_walk_state->operands[0];
|
||||
info->parameter_type = ACPI_PARAM_ARGS;
|
||||
|
||||
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.method_flags & AML_METHOD_INTERNAL_ONLY) {
|
||||
status = obj_desc->method.implementation(next_walk_state);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
|
||||
cleanup:
|
||||
|
||||
/* On error, we must terminate the method properly */
|
||||
|
||||
acpi_ds_terminate_control_method(obj_desc, next_walk_state);
|
||||
if (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)
|
||||
{
|
||||
struct acpi_namespace_node *method_node;
|
||||
acpi_status status;
|
||||
|
||||
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.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
|
||||
}
|
||||
}
|
||||
|
||||
if (walk_state) {
|
||||
/*
|
||||
* Delete any objects created by this method during execution.
|
||||
* The method Node is stored in the walk state
|
||||
*/
|
||||
method_node = walk_state->method_node;
|
||||
|
||||
/*
|
||||
* Delete any namespace objects created anywhere within
|
||||
* the namespace by the execution of this method
|
||||
*/
|
||||
acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
|
||||
}
|
||||
|
||||
/* 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, %d 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 creating the synchronization semaphore.
|
||||
*/
|
||||
if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
|
||||
&& (!method_desc->method.mutex)) {
|
||||
status = acpi_ds_create_method_mutex(method_desc);
|
||||
}
|
||||
|
||||
/* No more threads, we can free the owner_id */
|
||||
|
||||
acpi_ut_release_owner_id(&method_desc->method.owner_id);
|
||||
}
|
||||
|
||||
return_VOID;
|
||||
}
|
||||
714
drivers/acpi/dispatcher/dsmthdat.c
Normal file
714
drivers/acpi/dispatcher/dsmthdat.c
Normal file
@@ -0,0 +1,714 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: dsmthdat - control method arguments and local variables
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acdispat.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acinterp.h>
|
||||
|
||||
#define _COMPONENT ACPI_DISPATCHER
|
||||
ACPI_MODULE_NAME("dsmthdat")
|
||||
|
||||
/* Local prototypes */
|
||||
static void
|
||||
acpi_ds_method_data_delete_value(u16 opcode,
|
||||
u32 index, struct acpi_walk_state *walk_state);
|
||||
|
||||
static acpi_status
|
||||
acpi_ds_method_data_set_value(u16 opcode,
|
||||
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_END_OF_PEER_LIST | 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_END_OF_PEER_LIST | 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%d=%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%d=%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(AML_ARG_OP, index,
|
||||
params[index],
|
||||
walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%d args passed to method\n", index));
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_get_node
|
||||
*
|
||||
* 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
|
||||
* 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(u16 opcode,
|
||||
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 (opcode) {
|
||||
case AML_LOCAL_OP:
|
||||
|
||||
if (index > ACPI_METHOD_MAX_LOCAL) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Local index %d is invalid (max %d)",
|
||||
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 AML_ARG_OP:
|
||||
|
||||
if (index > ACPI_METHOD_MAX_ARG) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Arg index %d is invalid (max %d)",
|
||||
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, "Opcode %d is invalid", opcode));
|
||||
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_set_value
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* 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(u16 opcode,
|
||||
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 Opcode %X, Refs=%d [%s]\n", object,
|
||||
opcode, 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(opcode, 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.0_c)
|
||||
*/
|
||||
acpi_ut_add_reference(object);
|
||||
|
||||
/* Install the object */
|
||||
|
||||
node->object = object;
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_get_value
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* Index - Which local_var 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(u16 opcode,
|
||||
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(opcode, 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_internal_object(ACPI_TYPE_INTEGER);
|
||||
if (!object) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
object->integer.value = 0;
|
||||
node->object = object;
|
||||
}
|
||||
|
||||
/* Otherwise, return the error */
|
||||
|
||||
else
|
||||
switch (opcode) {
|
||||
case AML_ARG_OP:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Uninitialized Arg[%d] at node %p",
|
||||
index, node));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
|
||||
|
||||
case AML_LOCAL_OP:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Uninitialized Local[%d] at node %p",
|
||||
index, node));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Not a Arg/Local opcode: %X",
|
||||
opcode));
|
||||
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: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* Index - Which local_var 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(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_delete_value);
|
||||
|
||||
/* 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_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: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* 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(u16 opcode,
|
||||
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, "Opcode=%X Index=%d Obj=%p\n",
|
||||
opcode, 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(opcode, 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 (opcode == AML_ARG_OP) {
|
||||
/*
|
||||
* 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.opcode ==
|
||||
AML_REF_OF_OP)) {
|
||||
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(opcode, 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(opcode, 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(ACPI_GET_OBJECT_TYPE(object));
|
||||
}
|
||||
#endif
|
||||
662
drivers/acpi/dispatcher/dsobject.c
Normal file
662
drivers/acpi/dispatcher/dsobject.c
Normal file
@@ -0,0 +1,662 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: dsobject - Dispatcher object management routines
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acparser.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/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_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
*obj_desc_ptr = obj_desc;
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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, got AML opcode %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) {
|
||||
ACPI_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;
|
||||
acpi_native_uint i;
|
||||
|
||||
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) {
|
||||
|
||||
/* 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]);
|
||||
}
|
||||
arg = arg->common.next;
|
||||
}
|
||||
|
||||
if (!arg) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Package List length larger than NumElements count (%X), truncated\n",
|
||||
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 = ACPI_GET_OBJECT_TYPE(obj_desc);
|
||||
|
||||
/* 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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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_INTEGER_MAX;
|
||||
|
||||
/* Truncate value if we are executing from a 32-bit ACPI table */
|
||||
|
||||
#ifndef ACPI_NO_METHOD_EXECUTION
|
||||
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 %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
|
||||
acpi_ex_truncate_for32bit_table(obj_desc);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO, "Unknown Integer type %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) ACPI_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:
|
||||
|
||||
/* Split the opcode into a base opcode + offset */
|
||||
|
||||
obj_desc->reference.opcode = AML_LOCAL_OP;
|
||||
obj_desc->reference.offset = opcode - AML_LOCAL_OP;
|
||||
|
||||
#ifndef ACPI_NO_METHOD_EXECUTION
|
||||
status = acpi_ds_method_data_get_node(AML_LOCAL_OP,
|
||||
obj_desc->
|
||||
reference.offset,
|
||||
walk_state,
|
||||
(struct
|
||||
acpi_namespace_node
|
||||
**)&obj_desc->
|
||||
reference.object);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case AML_TYPE_METHOD_ARGUMENT:
|
||||
|
||||
/* Split the opcode into a base opcode + offset */
|
||||
|
||||
obj_desc->reference.opcode = AML_ARG_OP;
|
||||
obj_desc->reference.offset = opcode - AML_ARG_OP;
|
||||
|
||||
#ifndef ACPI_NO_METHOD_EXECUTION
|
||||
status = acpi_ds_method_data_get_node(AML_ARG_OP,
|
||||
obj_desc->
|
||||
reference.offset,
|
||||
walk_state,
|
||||
(struct
|
||||
acpi_namespace_node
|
||||
**)&obj_desc->
|
||||
reference.object);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default: /* Other literals, etc.. */
|
||||
|
||||
if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
|
||||
|
||||
/* Node was saved in Op */
|
||||
|
||||
obj_desc->reference.node = op->common.node;
|
||||
}
|
||||
|
||||
obj_desc->reference.opcode = opcode;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Unimplemented data type: %X",
|
||||
ACPI_GET_OBJECT_TYPE(obj_desc)));
|
||||
|
||||
status = AE_AML_OPERAND_TYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
1192
drivers/acpi/dispatcher/dsopcode.c
Normal file
1192
drivers/acpi/dispatcher/dsopcode.c
Normal file
File diff suppressed because it is too large
Load Diff
738
drivers/acpi/dispatcher/dsutils.c
Normal file
738
drivers/acpi/dispatcher/dsutils.c
Normal file
@@ -0,0 +1,738 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: dsutils - Dispatcher utilities
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acparser.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/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)) {
|
||||
/*
|
||||
* 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)) {
|
||||
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 {
|
||||
/*
|
||||
* 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) {
|
||||
/*
|
||||
* 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) {
|
||||
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_from_bottom(&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;
|
||||
u32 arg_count = 0;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
|
||||
|
||||
/* For all arguments in the list... */
|
||||
|
||||
arg = first_arg;
|
||||
while (arg) {
|
||||
status = acpi_ds_create_operand(walk_state, arg, arg_count);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
|
||||
"Arg #%d (%p) done, Arg1=%p\n", arg_count,
|
||||
arg, first_arg));
|
||||
|
||||
/* Move on to next argument, if any */
|
||||
|
||||
arg = arg->common.next;
|
||||
arg_count++;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
(void)acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
|
||||
|
||||
ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d",
|
||||
(arg_count + 1)));
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
759
drivers/acpi/dispatcher/dswexec.c
Normal file
759
drivers/acpi/dispatcher/dswexec.c
Normal file
@@ -0,0 +1,759 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: dswexec - Dispatcher method execution callbacks;
|
||||
* dispatch to interpreter.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acparser.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/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 (ACPI_GET_OBJECT_TYPE(local_obj_desc) != ACPI_TYPE_INTEGER) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Bad predicate (not an integer) ObjDesc=%p State=%p Type=%X",
|
||||
obj_desc, walk_state,
|
||||
ACPI_GET_OBJECT_TYPE(obj_desc)));
|
||||
|
||||
status = AE_AML_OPERAND_TYPE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Truncate the predicate to 32-bits if necessary */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_result_stack_push(walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
status = acpi_ds_load2_begin_op(walk_state, NULL);
|
||||
}
|
||||
|
||||
if (op->common.aml_opcode == AML_REGION_OP) {
|
||||
status = acpi_ds_result_stack_push(walk_state);
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_CLASS_EXECUTE:
|
||||
case AML_CLASS_CREATE:
|
||||
/*
|
||||
* Most operators with arguments (except create_xxx_field operators)
|
||||
* Start a new result/operand state
|
||||
*/
|
||||
if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) {
|
||||
status = acpi_ds_result_stack_push(walk_state);
|
||||
}
|
||||
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 %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->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. - do nothing */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Done with this result state (Now that operand stack is built) */
|
||||
|
||||
status = acpi_ds_result_stack_pop(walk_state);
|
||||
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)) {
|
||||
ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS,
|
||||
ACPI_IMODE_EXECUTE,
|
||||
acpi_ps_get_opcode_name
|
||||
(walk_state->opcode),
|
||||
walk_state->num_operands,
|
||||
"after ExResolveOperands");
|
||||
}
|
||||
}
|
||||
|
||||
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.opcode ==
|
||||
walk_state->operands[1]->reference.opcode)
|
||||
&& (walk_state->operands[0]->reference.offset ==
|
||||
walk_state->operands[1]->reference.offset)) {
|
||||
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);
|
||||
|
||||
/* Make sure to properly pop the result stack */
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
status = acpi_ds_result_stack_pop(walk_state);
|
||||
} else if (status == AE_CTRL_PENDING) {
|
||||
status = acpi_ds_result_stack_pop(walk_state);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
status = AE_CTRL_PENDING;
|
||||
}
|
||||
}
|
||||
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->object;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Done with result state (Now that operand stack is built) */
|
||||
|
||||
status = acpi_ds_result_stack_pop(walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
status = acpi_ds_result_stack_pop(walk_state);
|
||||
}
|
||||
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=%X type=%X Opcode=%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
|
||||
*/
|
||||
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);
|
||||
}
|
||||
1185
drivers/acpi/dispatcher/dswload.c
Normal file
1185
drivers/acpi/dispatcher/dswload.c
Normal file
File diff suppressed because it is too large
Load Diff
213
drivers/acpi/dispatcher/dswscope.c
Normal file
213
drivers/acpi/dispatcher/dswscope.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: dswscope - Scope stack manipulation
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/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);
|
||||
}
|
||||
1052
drivers/acpi/dispatcher/dswstate.c
Normal file
1052
drivers/acpi/dispatcher/dswstate.c
Normal file
File diff suppressed because it is too large
Load Diff
837
drivers/acpi/dock.c
Normal file
837
drivers/acpi/dock.c
Normal file
@@ -0,0 +1,837 @@
|
||||
/*
|
||||
* dock.c - ACPI dock station driver
|
||||
*
|
||||
* Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
|
||||
|
||||
ACPI_MODULE_NAME("dock");
|
||||
MODULE_AUTHOR("Kristen Carlson Accardi");
|
||||
MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct atomic_notifier_head dock_notifier_list;
|
||||
static struct platform_device dock_device;
|
||||
static char dock_device_name[] = "dock";
|
||||
|
||||
struct dock_station {
|
||||
acpi_handle handle;
|
||||
unsigned long last_dock_time;
|
||||
u32 flags;
|
||||
spinlock_t dd_lock;
|
||||
struct mutex hp_lock;
|
||||
struct list_head dependent_devices;
|
||||
struct list_head hotplug_devices;
|
||||
};
|
||||
|
||||
struct dock_dependent_device {
|
||||
struct list_head list;
|
||||
struct list_head hotplug_list;
|
||||
acpi_handle handle;
|
||||
acpi_notify_handler handler;
|
||||
void *context;
|
||||
};
|
||||
|
||||
#define DOCK_DOCKING 0x00000001
|
||||
#define DOCK_EVENT 3
|
||||
#define UNDOCK_EVENT 2
|
||||
|
||||
static struct dock_station *dock_station;
|
||||
|
||||
/*****************************************************************************
|
||||
* Dock Dependent device functions *
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* alloc_dock_dependent_device - allocate and init a dependent device
|
||||
* @handle: the acpi_handle of the dependent device
|
||||
*
|
||||
* Allocate memory for a dependent device structure for a device referenced
|
||||
* by the acpi handle
|
||||
*/
|
||||
static struct dock_dependent_device *
|
||||
alloc_dock_dependent_device(acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
|
||||
if (dd) {
|
||||
dd->handle = handle;
|
||||
INIT_LIST_HEAD(&dd->list);
|
||||
INIT_LIST_HEAD(&dd->hotplug_list);
|
||||
}
|
||||
return dd;
|
||||
}
|
||||
|
||||
/**
|
||||
* add_dock_dependent_device - associate a device with the dock station
|
||||
* @ds: The dock station
|
||||
* @dd: The dependent device
|
||||
*
|
||||
* Add the dependent device to the dock's dependent device list.
|
||||
*/
|
||||
static void
|
||||
add_dock_dependent_device(struct dock_station *ds,
|
||||
struct dock_dependent_device *dd)
|
||||
{
|
||||
spin_lock(&ds->dd_lock);
|
||||
list_add_tail(&dd->list, &ds->dependent_devices);
|
||||
spin_unlock(&ds->dd_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_add_hotplug_device - associate a hotplug handler with the dock station
|
||||
* @ds: The dock station
|
||||
* @dd: The dependent device struct
|
||||
*
|
||||
* Add the dependent device to the dock's hotplug device list
|
||||
*/
|
||||
static void
|
||||
dock_add_hotplug_device(struct dock_station *ds,
|
||||
struct dock_dependent_device *dd)
|
||||
{
|
||||
mutex_lock(&ds->hp_lock);
|
||||
list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
|
||||
mutex_unlock(&ds->hp_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_del_hotplug_device - remove a hotplug handler from the dock station
|
||||
* @ds: The dock station
|
||||
* @dd: the dependent device struct
|
||||
*
|
||||
* Delete the dependent device from the dock's hotplug device list
|
||||
*/
|
||||
static void
|
||||
dock_del_hotplug_device(struct dock_station *ds,
|
||||
struct dock_dependent_device *dd)
|
||||
{
|
||||
mutex_lock(&ds->hp_lock);
|
||||
list_del(&dd->hotplug_list);
|
||||
mutex_unlock(&ds->hp_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* find_dock_dependent_device - get a device dependent on this dock
|
||||
* @ds: the dock station
|
||||
* @handle: the acpi_handle of the device we want
|
||||
*
|
||||
* iterate over the dependent device list for this dock. If the
|
||||
* dependent device matches the handle, return.
|
||||
*/
|
||||
static struct dock_dependent_device *
|
||||
find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
spin_lock(&ds->dd_lock);
|
||||
list_for_each_entry(dd, &ds->dependent_devices, list) {
|
||||
if (handle == dd->handle) {
|
||||
spin_unlock(&ds->dd_lock);
|
||||
return dd;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ds->dd_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Dock functions *
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* is_dock - see if a device is a dock station
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If an acpi object has a _DCK method, then it is by definition a dock
|
||||
* station, so return true.
|
||||
*/
|
||||
static int is_dock(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle tmp;
|
||||
|
||||
status = acpi_get_handle(handle, "_DCK", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_dock_device - see if a device is on a dock station
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If this device is either the dock station itself,
|
||||
* or is a device dependent on the dock station, then it
|
||||
* is a dock device
|
||||
*/
|
||||
int is_dock_device(acpi_handle handle)
|
||||
{
|
||||
if (!dock_station)
|
||||
return 0;
|
||||
|
||||
if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(is_dock_device);
|
||||
|
||||
/**
|
||||
* dock_present - see if the dock station is present.
|
||||
* @ds: the dock station
|
||||
*
|
||||
* execute the _STA method. note that present does not
|
||||
* imply that we are docked.
|
||||
*/
|
||||
static int dock_present(struct dock_station *ds)
|
||||
{
|
||||
unsigned long sta;
|
||||
acpi_status status;
|
||||
|
||||
if (ds) {
|
||||
status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
|
||||
if (ACPI_SUCCESS(status) && sta)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dock_create_acpi_device - add new devices to acpi
|
||||
* @handle - handle of the device to add
|
||||
*
|
||||
* This function will create a new acpi_device for the given
|
||||
* handle if one does not exist already. This should cause
|
||||
* acpi to scan for drivers for the given devices, and call
|
||||
* matching driver's add routine.
|
||||
*
|
||||
* Returns a pointer to the acpi_device corresponding to the handle.
|
||||
*/
|
||||
static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_device *parent_device;
|
||||
acpi_handle parent;
|
||||
int ret;
|
||||
|
||||
if (acpi_bus_get_device(handle, &device)) {
|
||||
/*
|
||||
* no device created for this object,
|
||||
* so we should create one.
|
||||
*/
|
||||
acpi_get_parent(handle, &parent);
|
||||
if (acpi_bus_get_device(parent, &parent_device))
|
||||
parent_device = NULL;
|
||||
|
||||
ret = acpi_bus_add(&device, parent_device, handle,
|
||||
ACPI_BUS_TYPE_DEVICE);
|
||||
if (ret) {
|
||||
pr_debug("error adding bus, %x\n",
|
||||
-ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_remove_acpi_device - remove the acpi_device struct from acpi
|
||||
* @handle - the handle of the device to remove
|
||||
*
|
||||
* Tell acpi to remove the acpi_device. This should cause any loaded
|
||||
* driver to have it's remove routine called.
|
||||
*/
|
||||
static void dock_remove_acpi_device(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *device;
|
||||
int ret;
|
||||
|
||||
if (!acpi_bus_get_device(handle, &device)) {
|
||||
ret = acpi_bus_trim(device, 1);
|
||||
if (ret)
|
||||
pr_debug("error removing bus, %x\n", -ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hotplug_dock_devices - insert or remove devices on the dock station
|
||||
* @ds: the dock station
|
||||
* @event: either bus check or eject request
|
||||
*
|
||||
* Some devices on the dock station need to have drivers called
|
||||
* to perform hotplug operations after a dock event has occurred.
|
||||
* Traverse the list of dock devices that have registered a
|
||||
* hotplug handler, and call the handler.
|
||||
*/
|
||||
static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
mutex_lock(&ds->hp_lock);
|
||||
|
||||
/*
|
||||
* First call driver specific hotplug functions
|
||||
*/
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
|
||||
if (dd->handler)
|
||||
dd->handler(dd->handle, event, dd->context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now make sure that an acpi_device is created for each
|
||||
* dependent device, or removed if this is an eject request.
|
||||
* This will cause acpi_drivers to be stopped/started if they
|
||||
* exist
|
||||
*/
|
||||
list_for_each_entry(dd, &ds->dependent_devices, list) {
|
||||
if (event == ACPI_NOTIFY_EJECT_REQUEST)
|
||||
dock_remove_acpi_device(dd->handle);
|
||||
else
|
||||
dock_create_acpi_device(dd->handle);
|
||||
}
|
||||
mutex_unlock(&ds->hp_lock);
|
||||
}
|
||||
|
||||
static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
{
|
||||
struct device *dev = &dock_device.dev;
|
||||
/*
|
||||
* Indicate that the status of the dock station has
|
||||
* changed.
|
||||
*/
|
||||
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* eject_dock - respond to a dock eject request
|
||||
* @ds: the dock station
|
||||
*
|
||||
* This is called after _DCK is called, to execute the dock station's
|
||||
* _EJ0 method.
|
||||
*/
|
||||
static void eject_dock(struct dock_station *ds)
|
||||
{
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status;
|
||||
acpi_handle tmp;
|
||||
|
||||
/* all dock devices should have _EJ0, but check anyway */
|
||||
status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_debug("No _EJ0 support for dock device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = 1;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
|
||||
&arg_list, NULL)))
|
||||
pr_debug("Failed to evaluate _EJ0!\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_dock - handle a dock event
|
||||
* @ds: the dock station
|
||||
* @dock: to dock, or undock - that is the question
|
||||
*
|
||||
* Execute the _DCK method in response to an acpi event
|
||||
*/
|
||||
static void handle_dock(struct dock_station *ds, int dock)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
|
||||
acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
|
||||
obj = name_buffer.pointer;
|
||||
|
||||
printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
|
||||
|
||||
/* _DCK method has one argument */
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = dock;
|
||||
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
|
||||
kfree(buffer.pointer);
|
||||
kfree(name_buffer.pointer);
|
||||
}
|
||||
|
||||
static inline void dock(struct dock_station *ds)
|
||||
{
|
||||
handle_dock(ds, 1);
|
||||
}
|
||||
|
||||
static inline void undock(struct dock_station *ds)
|
||||
{
|
||||
handle_dock(ds, 0);
|
||||
}
|
||||
|
||||
static inline void begin_dock(struct dock_station *ds)
|
||||
{
|
||||
ds->flags |= DOCK_DOCKING;
|
||||
}
|
||||
|
||||
static inline void complete_dock(struct dock_station *ds)
|
||||
{
|
||||
ds->flags &= ~(DOCK_DOCKING);
|
||||
ds->last_dock_time = jiffies;
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_in_progress - see if we are in the middle of handling a dock event
|
||||
* @ds: the dock station
|
||||
*
|
||||
* Sometimes while docking, false dock events can be sent to the driver
|
||||
* because good connections aren't made or some other reason. Ignore these
|
||||
* if we are in the middle of doing something.
|
||||
*/
|
||||
static int dock_in_progress(struct dock_station *ds)
|
||||
{
|
||||
if ((ds->flags & DOCK_DOCKING) ||
|
||||
time_before(jiffies, (ds->last_dock_time + HZ)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* register_dock_notifier - add yourself to the dock notifier list
|
||||
* @nb: the callers notifier block
|
||||
*
|
||||
* If a driver wishes to be notified about dock events, they can
|
||||
* use this function to put a notifier block on the dock notifier list.
|
||||
* this notifier call chain will be called after a dock event, but
|
||||
* before hotplugging any new devices.
|
||||
*/
|
||||
int register_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
if (!dock_station)
|
||||
return -ENODEV;
|
||||
|
||||
return atomic_notifier_chain_register(&dock_notifier_list, nb);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_dock_notifier);
|
||||
|
||||
/**
|
||||
* unregister_dock_notifier - remove yourself from the dock notifier list
|
||||
* @nb: the callers notifier block
|
||||
*/
|
||||
void unregister_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
if (!dock_station)
|
||||
return;
|
||||
|
||||
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
|
||||
/**
|
||||
* register_hotplug_dock_device - register a hotplug function
|
||||
* @handle: the handle of the device
|
||||
* @handler: the acpi_notifier_handler to call after docking
|
||||
* @context: device specific data
|
||||
*
|
||||
* If a driver would like to perform a hotplug operation after a dock
|
||||
* event, they can register an acpi_notifiy_handler to be called by
|
||||
* the dock driver after _DCK is executed.
|
||||
*/
|
||||
int
|
||||
register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
|
||||
void *context)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
if (!dock_station)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* make sure this handle is for a device dependent on the dock,
|
||||
* this would include the dock station itself
|
||||
*/
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
dd->handler = handler;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
|
||||
|
||||
/**
|
||||
* unregister_hotplug_dock_device - remove yourself from the hotplug list
|
||||
* @handle: the acpi handle of the device
|
||||
*/
|
||||
void unregister_hotplug_dock_device(acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
if (!dock_station)
|
||||
return;
|
||||
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd)
|
||||
dock_del_hotplug_device(dock_station, dd);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
|
||||
|
||||
/**
|
||||
* handle_eject_request - handle an undock request checking for error conditions
|
||||
*
|
||||
* Check to make sure the dock device is still present, then undock and
|
||||
* hotremove all the devices that may need removing.
|
||||
*/
|
||||
static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
{
|
||||
if (!dock_present(ds))
|
||||
return -ENODEV;
|
||||
|
||||
if (dock_in_progress(ds))
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* here we need to generate the undock
|
||||
* event prior to actually doing the undock
|
||||
* so that the device struct still exists.
|
||||
*/
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
undock(ds);
|
||||
eject_dock(ds);
|
||||
if (dock_present(ds)) {
|
||||
printk(KERN_ERR PREFIX "Unable to undock!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_notify - act upon an acpi dock notification
|
||||
* @handle: the dock station handle
|
||||
* @event: the acpi event
|
||||
* @data: our driver data struct
|
||||
*
|
||||
* If we are notified to dock, then check to see if the dock is
|
||||
* present and then dock. Notify all drivers of the dock event,
|
||||
* and then hotplug and devices that may need hotplugging.
|
||||
*/
|
||||
static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct dock_station *ds = data;
|
||||
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
if (!dock_in_progress(ds) && dock_present(ds)) {
|
||||
begin_dock(ds);
|
||||
dock(ds);
|
||||
if (!dock_present(ds)) {
|
||||
printk(KERN_ERR PREFIX "Unable to dock!\n");
|
||||
break;
|
||||
}
|
||||
atomic_notifier_call_chain(&dock_notifier_list,
|
||||
event, NULL);
|
||||
hotplug_dock_devices(ds, event);
|
||||
complete_dock(ds);
|
||||
dock_event(ds, event, DOCK_EVENT);
|
||||
}
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
/*
|
||||
* According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
* is sent and _DCK is present, it is assumed to mean an
|
||||
* undock request. This notify routine will only be called
|
||||
* for objects defining _DCK, so we will fall through to eject
|
||||
* request here. However, we will pass an eject request through
|
||||
* to the driver who wish to hotplug.
|
||||
*/
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
handle_eject_request(ds, event);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find_dock_devices - find devices on the dock station
|
||||
* @handle: the handle of the device we are examining
|
||||
* @lvl: unused
|
||||
* @context: the dock station private data
|
||||
* @rv: unused
|
||||
*
|
||||
* This function is called by acpi_walk_namespace. It will
|
||||
* check to see if an object has an _EJD method. If it does, then it
|
||||
* will see if it is dependent on the dock station.
|
||||
*/
|
||||
static acpi_status
|
||||
find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle tmp, parent;
|
||||
struct dock_station *ds = context;
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
status = acpi_bus_get_ejd(handle, &tmp);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
/* try the parent device as well */
|
||||
status = acpi_get_parent(handle, &parent);
|
||||
if (ACPI_FAILURE(status))
|
||||
goto fdd_out;
|
||||
/* see if parent is dependent on dock */
|
||||
status = acpi_bus_get_ejd(parent, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
goto fdd_out;
|
||||
}
|
||||
|
||||
if (tmp == ds->handle) {
|
||||
dd = alloc_dock_dependent_device(handle);
|
||||
if (dd)
|
||||
add_dock_dependent_device(ds, dd);
|
||||
}
|
||||
fdd_out:
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* show_docked - read method for "docked" file in sysfs
|
||||
*/
|
||||
static ssize_t show_docked(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
|
||||
|
||||
}
|
||||
DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
|
||||
|
||||
/*
|
||||
* write_undock - write method for "undock" file in sysfs
|
||||
*/
|
||||
static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
return ret ? ret: count;
|
||||
}
|
||||
DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
|
||||
|
||||
/**
|
||||
* dock_add - add a new dock station
|
||||
* @handle: the dock station handle
|
||||
*
|
||||
* allocated and initialize a new dock station device. Find all devices
|
||||
* that are on the dock station, and register for dock event notifications.
|
||||
*/
|
||||
static int dock_add(acpi_handle handle)
|
||||
{
|
||||
int ret;
|
||||
acpi_status status;
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
/* allocate & initialize the dock_station private data */
|
||||
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
|
||||
if (!dock_station)
|
||||
return -ENOMEM;
|
||||
dock_station->handle = handle;
|
||||
dock_station->last_dock_time = jiffies - HZ;
|
||||
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
||||
INIT_LIST_HEAD(&dock_station->hotplug_devices);
|
||||
spin_lock_init(&dock_station->dd_lock);
|
||||
mutex_init(&dock_station->hp_lock);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
|
||||
/* initialize platform device stuff */
|
||||
dock_device.name = dock_device_name;
|
||||
ret = platform_device_register(&dock_device);
|
||||
if (ret) {
|
||||
printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
|
||||
kfree(dock_station);
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device.dev, &dev_attr_docked);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
platform_device_unregister(&dock_device);
|
||||
kfree(dock_station);
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device.dev, &dev_attr_undock);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
device_remove_file(&dock_device.dev, &dev_attr_docked);
|
||||
platform_device_unregister(&dock_device);
|
||||
kfree(dock_station);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Find dependent devices */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, find_dock_devices, dock_station,
|
||||
NULL);
|
||||
|
||||
/* add the dock station as a device dependent on itself */
|
||||
dd = alloc_dock_dependent_device(handle);
|
||||
if (!dd) {
|
||||
kfree(dock_station);
|
||||
ret = -ENOMEM;
|
||||
goto dock_add_err_unregister;
|
||||
}
|
||||
add_dock_dependent_device(dock_station, dd);
|
||||
|
||||
/* register for dock events */
|
||||
status = acpi_install_notify_handler(dock_station->handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
dock_notify, dock_station);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Error installing notify handler\n");
|
||||
ret = -ENODEV;
|
||||
goto dock_add_err;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION);
|
||||
|
||||
return 0;
|
||||
|
||||
dock_add_err:
|
||||
kfree(dd);
|
||||
dock_add_err_unregister:
|
||||
device_remove_file(&dock_device.dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device.dev, &dev_attr_undock);
|
||||
platform_device_unregister(&dock_device);
|
||||
kfree(dock_station);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_remove - free up resources related to the dock station
|
||||
*/
|
||||
static int dock_remove(void)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
acpi_status status;
|
||||
|
||||
if (!dock_station)
|
||||
return 0;
|
||||
|
||||
/* remove dependent devices */
|
||||
list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,
|
||||
list)
|
||||
kfree(dd);
|
||||
|
||||
/* remove dock notify handler */
|
||||
status = acpi_remove_notify_handler(dock_station->handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
dock_notify);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(KERN_ERR "Error removing notify handler\n");
|
||||
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(&dock_device.dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device.dev, &dev_attr_undock);
|
||||
platform_device_unregister(&dock_device);
|
||||
|
||||
/* free dock station memory */
|
||||
kfree(dock_station);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_dock - look for a dock station
|
||||
* @handle: acpi handle of a device
|
||||
* @lvl: unused
|
||||
* @context: counter of dock stations found
|
||||
* @rv: unused
|
||||
*
|
||||
* This is called by acpi_walk_namespace to look for dock stations.
|
||||
*/
|
||||
static acpi_status
|
||||
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
int *count = context;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
if (is_dock(handle)) {
|
||||
if (dock_add(handle) >= 0) {
|
||||
(*count)++;
|
||||
status = AE_CTRL_TERMINATE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __init dock_init(void)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
dock_station = NULL;
|
||||
|
||||
/* look for a dock station */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, find_dock, &num, NULL);
|
||||
|
||||
if (!num)
|
||||
printk(KERN_INFO "No dock devices found.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dock_exit(void)
|
||||
{
|
||||
dock_remove();
|
||||
}
|
||||
|
||||
postcore_initcall(dock_init);
|
||||
module_exit(dock_exit);
|
||||
1031
drivers/acpi/ec.c
Normal file
1031
drivers/acpi/ec.c
Normal file
File diff suppressed because it is too large
Load Diff
128
drivers/acpi/event.c
Normal file
128
drivers/acpi/event.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* event.c - exporting ACPI events via procfs
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define _COMPONENT ACPI_SYSTEM_COMPONENT
|
||||
ACPI_MODULE_NAME("event");
|
||||
|
||||
/* Global vars for handling event proc entry */
|
||||
static DEFINE_SPINLOCK(acpi_system_event_lock);
|
||||
int event_is_open = 0;
|
||||
extern struct list_head acpi_bus_event_list;
|
||||
extern wait_queue_head_t acpi_bus_event_queue;
|
||||
|
||||
static int acpi_system_open_event(struct inode *inode, struct file *file)
|
||||
{
|
||||
spin_lock_irq(&acpi_system_event_lock);
|
||||
|
||||
if (event_is_open)
|
||||
goto out_busy;
|
||||
|
||||
event_is_open = 1;
|
||||
|
||||
spin_unlock_irq(&acpi_system_event_lock);
|
||||
return 0;
|
||||
|
||||
out_busy:
|
||||
spin_unlock_irq(&acpi_system_event_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_bus_event event;
|
||||
static char str[ACPI_MAX_STRING];
|
||||
static int chars_remaining = 0;
|
||||
static char *ptr;
|
||||
|
||||
|
||||
if (!chars_remaining) {
|
||||
memset(&event, 0, sizeof(struct acpi_bus_event));
|
||||
|
||||
if ((file->f_flags & O_NONBLOCK)
|
||||
&& (list_empty(&acpi_bus_event_list)))
|
||||
return -EAGAIN;
|
||||
|
||||
result = acpi_bus_receive_event(&event);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
chars_remaining = sprintf(str, "%s %s %08x %08x\n",
|
||||
event.device_class ? event.
|
||||
device_class : "<unknown>",
|
||||
event.bus_id ? event.
|
||||
bus_id : "<unknown>", event.type,
|
||||
event.data);
|
||||
ptr = str;
|
||||
}
|
||||
|
||||
if (chars_remaining < count) {
|
||||
count = chars_remaining;
|
||||
}
|
||||
|
||||
if (copy_to_user(buffer, ptr, count))
|
||||
return -EFAULT;
|
||||
|
||||
*ppos += count;
|
||||
chars_remaining -= count;
|
||||
ptr += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int acpi_system_close_event(struct inode *inode, struct file *file)
|
||||
{
|
||||
spin_lock_irq(&acpi_system_event_lock);
|
||||
event_is_open = 0;
|
||||
spin_unlock_irq(&acpi_system_event_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
|
||||
{
|
||||
poll_wait(file, &acpi_bus_event_queue, wait);
|
||||
if (!list_empty(&acpi_bus_event_list))
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations acpi_system_event_ops = {
|
||||
.open = acpi_system_open_event,
|
||||
.read = acpi_system_read_event,
|
||||
.release = acpi_system_close_event,
|
||||
.poll = acpi_system_poll_event,
|
||||
};
|
||||
|
||||
static int __init acpi_event_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
int error = 0;
|
||||
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
/* 'event' [R] */
|
||||
entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
|
||||
if (entry)
|
||||
entry->proc_fops = &acpi_system_event_ops;
|
||||
else {
|
||||
error = -ENODEV;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_event_init);
|
||||
9
drivers/acpi/events/Makefile
Normal file
9
drivers/acpi/events/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for all Linux ACPI interpreter subdirectories
|
||||
#
|
||||
|
||||
obj-y := evevent.o evregion.o evsci.o evxfevnt.o \
|
||||
evmisc.o evrgnini.o evxface.o evxfregn.o \
|
||||
evgpe.o evgpeblk.o
|
||||
|
||||
EXTRA_CFLAGS += $(ACPI_CFLAGS)
|
||||
314
drivers/acpi/events/evevent.c
Normal file
314
drivers/acpi/events/evevent.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evevent - Fixed Event handling and dispatch
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evevent")
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* 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_fadt_gpes
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Completes initialization of the FADT-defined GPE blocks
|
||||
* (0 and 1). This causes the _PRW methods to be run, so the HW
|
||||
* must be fully initialized at this point, including global lock
|
||||
* support.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_ev_install_fadt_gpes(void)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_install_fadt_gpes);
|
||||
|
||||
/* Namespace must be locked */
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* FADT GPE Block 0 */
|
||||
|
||||
(void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
|
||||
acpi_gbl_gpe_fadt_blocks[0]);
|
||||
|
||||
/* FADT GPE Block 1 */
|
||||
|
||||
(void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
|
||||
acpi_gbl_gpe_fadt_blocks[1]);
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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);
|
||||
|
||||
/* 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 enable the fixed events.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status acpi_ev_fixed_event_initialize(void)
|
||||
{
|
||||
acpi_native_uint 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;
|
||||
|
||||
/* Enable the fixed event */
|
||||
|
||||
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
|
||||
status =
|
||||
acpi_set_register(acpi_gbl_fixed_event_info[i].
|
||||
enable_register_id, 0);
|
||||
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;
|
||||
acpi_native_uint 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_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_STATUS, &fixed_status);
|
||||
(void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
|
||||
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 */
|
||||
|
||||
int_status |= acpi_ev_fixed_event_dispatch((u32) 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static u32 acpi_ev_fixed_event_dispatch(u32 event)
|
||||
{
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/* Clear the status bit */
|
||||
|
||||
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
|
||||
status_register_id, 1);
|
||||
|
||||
/*
|
||||
* Make sure we've got a handler. If not, report an error.
|
||||
* The event is disabled to prevent further interrupts.
|
||||
*/
|
||||
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
|
||||
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
|
||||
enable_register_id, 0);
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"No installed handler for fixed event [%08X]",
|
||||
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));
|
||||
}
|
||||
723
drivers/acpi/events/evgpe.c
Normal file
723
drivers/acpi/events/evgpe.c
Normal file
@@ -0,0 +1,723 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evgpe - General Purpose Event handling and dispatch
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evgpe")
|
||||
|
||||
/* Local prototypes */
|
||||
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_set_gpe_type
|
||||
*
|
||||
* PARAMETERS: gpe_event_info - GPE to set
|
||||
* Type - New type
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_set_gpe_type);
|
||||
|
||||
/* Validate type and update register enable masks */
|
||||
|
||||
switch (type) {
|
||||
case ACPI_GPE_TYPE_WAKE:
|
||||
case ACPI_GPE_TYPE_RUNTIME:
|
||||
case ACPI_GPE_TYPE_WAKE_RUN:
|
||||
break;
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* Disable the GPE if currently enabled */
|
||||
|
||||
status = acpi_ev_disable_gpe(gpe_event_info);
|
||||
|
||||
/* Type was validated above */
|
||||
|
||||
gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK; /* Clear type bits */
|
||||
gpe_event_info->flags |= type; /* Insert type */
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_update_gpe_enable_masks
|
||||
*
|
||||
* PARAMETERS: gpe_event_info - GPE to update
|
||||
* Type - What to do: ACPI_GPE_DISABLE or
|
||||
* ACPI_GPE_ENABLE
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Updates GPE register enable masks based on the GPE type
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
|
||||
u8 type)
|
||||
{
|
||||
struct acpi_gpe_register_info *gpe_register_info;
|
||||
u8 register_bit;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks);
|
||||
|
||||
gpe_register_info = gpe_event_info->register_info;
|
||||
if (!gpe_register_info) {
|
||||
return_ACPI_STATUS(AE_NOT_EXIST);
|
||||
}
|
||||
register_bit = (u8)
|
||||
(1 <<
|
||||
(gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
|
||||
|
||||
/* 1) Disable case. Simply clear all enable bits */
|
||||
|
||||
if (type == ACPI_GPE_DISABLE) {
|
||||
ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
|
||||
register_bit);
|
||||
ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/* 2) Enable case. Set/Clear the appropriate enable bits */
|
||||
|
||||
switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
|
||||
case ACPI_GPE_TYPE_WAKE:
|
||||
ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
|
||||
ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
|
||||
break;
|
||||
|
||||
case ACPI_GPE_TYPE_RUNTIME:
|
||||
ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
|
||||
register_bit);
|
||||
ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
|
||||
break;
|
||||
|
||||
case ACPI_GPE_TYPE_WAKE_RUN:
|
||||
ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
|
||||
ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
|
||||
break;
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_enable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_event_info - GPE to enable
|
||||
* write_to_hardware - Enable now, or just mark data structs
|
||||
* (WAKE GPEs should be deferred)
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Enable a GPE based on the GPE type
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
|
||||
u8 write_to_hardware)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_enable_gpe);
|
||||
|
||||
/* Make sure HW enable masks are updated */
|
||||
|
||||
status =
|
||||
acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_ENABLE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Mark wake-enabled or HW enable, or both */
|
||||
|
||||
switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
|
||||
case ACPI_GPE_TYPE_WAKE:
|
||||
|
||||
ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
|
||||
break;
|
||||
|
||||
case ACPI_GPE_TYPE_WAKE_RUN:
|
||||
|
||||
ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
|
||||
|
||||
/*lint -fallthrough */
|
||||
|
||||
case ACPI_GPE_TYPE_RUNTIME:
|
||||
|
||||
ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
|
||||
|
||||
if (write_to_hardware) {
|
||||
|
||||
/* Clear the GPE (of stale events), then enable it */
|
||||
|
||||
status = acpi_hw_clear_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Enable the requested runtime GPE */
|
||||
|
||||
status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_disable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_event_info - GPE to disable
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Disable a GPE based on the GPE type
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_disable_gpe);
|
||||
|
||||
if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) {
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/* Make sure HW enable masks are updated */
|
||||
|
||||
status =
|
||||
acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Mark wake-disabled or HW disable, or both */
|
||||
|
||||
switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
|
||||
case ACPI_GPE_TYPE_WAKE:
|
||||
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
|
||||
break;
|
||||
|
||||
case ACPI_GPE_TYPE_WAKE_RUN:
|
||||
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
|
||||
|
||||
/*lint -fallthrough */
|
||||
|
||||
case ACPI_GPE_TYPE_RUNTIME:
|
||||
|
||||
/* Disable the requested runtime GPE */
|
||||
|
||||
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
|
||||
status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_block_info *gpe_block;
|
||||
acpi_native_uint i;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/* A NULL gpe_block 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_block = acpi_gbl_gpe_fadt_blocks[i];
|
||||
if (gpe_block) {
|
||||
if ((gpe_number >= gpe_block->block_base_number)
|
||||
&& (gpe_number <
|
||||
gpe_block->block_base_number +
|
||||
(gpe_block->register_count * 8))) {
|
||||
return (&gpe_block->
|
||||
event_info[gpe_number -
|
||||
gpe_block->
|
||||
block_base_number]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
gpe_block = obj_desc->device.gpe_block;
|
||||
|
||||
if ((gpe_number >= gpe_block->block_base_number) &&
|
||||
(gpe_number <
|
||||
gpe_block->block_base_number + (gpe_block->register_count * 8))) {
|
||||
return (&gpe_block->
|
||||
event_info[gpe_number - gpe_block->block_base_number]);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_gpe_register_info *gpe_register_info;
|
||||
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
|
||||
u8 enabled_status_byte;
|
||||
u32 status_reg;
|
||||
u32 enable_reg;
|
||||
acpi_cpu_flags flags;
|
||||
acpi_native_uint i;
|
||||
acpi_native_uint 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) {
|
||||
/*
|
||||
* 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];
|
||||
|
||||
/* Read the Status Register */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH,
|
||||
&status_reg,
|
||||
&gpe_register_info->
|
||||
status_address);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Read the Enable Register */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH,
|
||||
&enable_reg,
|
||||
&gpe_register_info->
|
||||
enable_address);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
|
||||
"Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
|
||||
gpe_register_info->base_gpe_number,
|
||||
status_reg, enable_reg));
|
||||
|
||||
/* 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 */
|
||||
|
||||
if (enabled_status_byte & (1 << j)) {
|
||||
/*
|
||||
* Found an active GPE. Dispatch the event to a handler
|
||||
* or method.
|
||||
*/
|
||||
int_status |=
|
||||
acpi_ev_gpe_dispatch(&gpe_block->
|
||||
event_info[(i *
|
||||
ACPI_GPE_REGISTER_WIDTH)
|
||||
+
|
||||
j],
|
||||
(u32) j +
|
||||
gpe_register_info->
|
||||
base_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 = (void *)context;
|
||||
acpi_status status;
|
||||
struct acpi_gpe_event_info local_gpe_event_info;
|
||||
struct acpi_evaluate_info *info;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/* Must revalidate the gpe_number/gpe_block */
|
||||
|
||||
if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
|
||||
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/* Set the GPE flags for return to enabled state */
|
||||
|
||||
(void)acpi_ev_enable_gpe(gpe_event_info, FALSE);
|
||||
|
||||
/*
|
||||
* Take a snapshot of the GPE info for this level - we copy the
|
||||
* info to prevent a race condition with remove_handler/remove_block.
|
||||
*/
|
||||
ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
|
||||
sizeof(struct acpi_gpe_event_info));
|
||||
|
||||
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must check for control method type dispatch one more
|
||||
* time to avoid race with ev_gpe_install_handler
|
||||
*/
|
||||
if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
|
||||
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 =
|
||||
local_gpe_event_info.dispatch.method_node;
|
||||
info->parameters =
|
||||
ACPI_CAST_PTR(union acpi_operand_object *,
|
||||
gpe_event_info);
|
||||
info->parameter_type = ACPI_PARAM_GPE;
|
||||
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
|
||||
(local_gpe_event_info.dispatch.
|
||||
method_node)));
|
||||
}
|
||||
}
|
||||
|
||||
if ((local_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(&local_gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_VOID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable this GPE */
|
||||
|
||||
(void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_gpe_dispatch
|
||||
*
|
||||
* PARAMETERS: 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_gpe_event_info *gpe_event_info, u32 gpe_number)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
|
||||
|
||||
acpi_gpe_count++;
|
||||
|
||||
/*
|
||||
* 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[%2X]",
|
||||
gpe_number));
|
||||
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, we disable this GPE to prevent further such pointless
|
||||
* events from firing.
|
||||
*/
|
||||
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
|
||||
case ACPI_GPE_DISPATCH_HANDLER:
|
||||
|
||||
/*
|
||||
* Invoke the installed handler (at interrupt level)
|
||||
* Ignore return status for now. TBD: leave GPE disabled on error?
|
||||
*/
|
||||
(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
|
||||
dispatch.
|
||||
handler->
|
||||
context);
|
||||
|
||||
/* It is now safe to clear level-triggered events. */
|
||||
|
||||
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
|
||||
ACPI_GPE_LEVEL_TRIGGERED) {
|
||||
status = acpi_hw_clear_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to clear GPE[%2X]",
|
||||
gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_GPE_DISPATCH_METHOD:
|
||||
|
||||
/*
|
||||
* Disable the GPE, so it doesn't keep firing before the method has a
|
||||
* chance to run (it runs asynchronously with interrupts enabled).
|
||||
*/
|
||||
status = acpi_ev_disable_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to disable GPE[%2X]",
|
||||
gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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[%2X] - event disabled",
|
||||
gpe_number));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* No handler or method to run! */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"No handler or method for GPE[%2X], disabling event",
|
||||
gpe_number));
|
||||
|
||||
/*
|
||||
* Disable the GPE. The GPE will remain disabled until the ACPI
|
||||
* Core Subsystem is restarted, or a handler is installed.
|
||||
*/
|
||||
status = acpi_ev_disable_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to disable GPE[%2X]",
|
||||
gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return_UINT32(ACPI_INTERRUPT_HANDLED);
|
||||
}
|
||||
1210
drivers/acpi/events/evgpeblk.c
Normal file
1210
drivers/acpi/events/evgpeblk.c
Normal file
File diff suppressed because it is too large
Load Diff
629
drivers/acpi/events/evmisc.c
Normal file
629
drivers/acpi/events/evmisc.c
Normal file
@@ -0,0 +1,629 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evmisc - Miscellaneous event manager support functions
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acinterp.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evmisc")
|
||||
|
||||
/* Names for Notify() values, used for debug output */
|
||||
#ifdef ACPI_DEBUG_OUTPUT
|
||||
static const char *acpi_notify_value_names[] = {
|
||||
"Bus Check",
|
||||
"Device Check",
|
||||
"Device Wake",
|
||||
"Eject Request",
|
||||
"Device Check Light",
|
||||
"Frequency Mismatch",
|
||||
"Bus Mode Mismatch",
|
||||
"Power Fault"
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Pointer to FACS needed for the Global Lock */
|
||||
|
||||
static struct acpi_table_facs *facs = NULL;
|
||||
|
||||
/* Local prototypes */
|
||||
|
||||
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
|
||||
|
||||
static u32 acpi_ev_global_lock_handler(void *context);
|
||||
|
||||
static acpi_status acpi_ev_remove_global_lock_handler(void);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_POWER:
|
||||
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_obj = NULL;
|
||||
union acpi_generic_state *notify_info;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
ACPI_FUNCTION_NAME(ev_queue_notify_request);
|
||||
|
||||
/*
|
||||
* For value 3 (Ejection Request), some device method may need to be run.
|
||||
* For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
|
||||
* to be run.
|
||||
* For value 0x80 (Status Change) on the power button or sleep button,
|
||||
* initiate soft-off or sleep operation?
|
||||
*/
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Dispatching Notify(%X) on node %p\n", notify_value,
|
||||
node));
|
||||
|
||||
if (notify_value <= 7) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n",
|
||||
acpi_notify_value_names[notify_value]));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Notify value: 0x%2.2X **Device Specific**\n",
|
||||
notify_value));
|
||||
}
|
||||
|
||||
/* Get the notify object attached to the NS Node */
|
||||
|
||||
obj_desc = acpi_ns_get_attached_object(node);
|
||||
if (obj_desc) {
|
||||
|
||||
/* We have the notify object, Get the right handler */
|
||||
|
||||
switch (node->type) {
|
||||
case ACPI_TYPE_DEVICE:
|
||||
case ACPI_TYPE_THERMAL:
|
||||
case ACPI_TYPE_PROCESSOR:
|
||||
case ACPI_TYPE_POWER:
|
||||
|
||||
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
|
||||
handler_obj =
|
||||
obj_desc->common_notify.system_notify;
|
||||
} else {
|
||||
handler_obj =
|
||||
obj_desc->common_notify.device_notify;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* All other types are not supported */
|
||||
return (AE_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is any handler to run, schedule the dispatcher */
|
||||
|
||||
if ((acpi_gbl_system_notify.handler
|
||||
&& (notify_value <= ACPI_MAX_SYS_NOTIFY))
|
||||
|| (acpi_gbl_device_notify.handler
|
||||
&& (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
|
||||
notify_info = acpi_ut_create_generic_state();
|
||||
if (!notify_info) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
notify_info->common.descriptor_type =
|
||||
ACPI_DESC_TYPE_STATE_NOTIFY;
|
||||
notify_info->notify.node = node;
|
||||
notify_info->notify.value = (u16) notify_value;
|
||||
notify_info->notify.handler_obj = handler_obj;
|
||||
|
||||
acpi_ex_exit_interpreter();
|
||||
|
||||
acpi_ev_notify_dispatch(notify_info);
|
||||
|
||||
status = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!handler_obj) {
|
||||
/*
|
||||
* There is no per-device notify handler for this device.
|
||||
* This may or may not be a problem.
|
||||
*/
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"No notify handler for Notify(%4.4s, %X) node %p\n",
|
||||
acpi_ut_get_node_name(node), notify_value,
|
||||
node));
|
||||
}
|
||||
|
||||
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 *notify_info =
|
||||
(union acpi_generic_state *)context;
|
||||
acpi_notify_handler global_handler = NULL;
|
||||
void *global_context = NULL;
|
||||
union acpi_operand_object *handler_obj;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/*
|
||||
* We will invoke a global notify handler if installed.
|
||||
* This is done _before_ we invoke the per-device handler attached
|
||||
* to the device.
|
||||
*/
|
||||
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
|
||||
|
||||
/* Global system notification handler */
|
||||
|
||||
if (acpi_gbl_system_notify.handler) {
|
||||
global_handler = acpi_gbl_system_notify.handler;
|
||||
global_context = acpi_gbl_system_notify.context;
|
||||
}
|
||||
} else {
|
||||
/* Global driver notification handler */
|
||||
|
||||
if (acpi_gbl_device_notify.handler) {
|
||||
global_handler = acpi_gbl_device_notify.handler;
|
||||
global_context = acpi_gbl_device_notify.context;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the system handler first, if present */
|
||||
|
||||
if (global_handler) {
|
||||
global_handler(notify_info->notify.node,
|
||||
notify_info->notify.value, global_context);
|
||||
}
|
||||
|
||||
/* Now invoke the per-device handler, if present */
|
||||
|
||||
handler_obj = notify_info->notify.handler_obj;
|
||||
if (handler_obj) {
|
||||
handler_obj->notify.handler(notify_info->notify.node,
|
||||
notify_info->notify.value,
|
||||
handler_obj->notify.context);
|
||||
}
|
||||
|
||||
/* All done with the info object */
|
||||
|
||||
acpi_ut_delete_generic_state(notify_info);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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. Attempt to acquire the global lock,
|
||||
* if successful, signal the thread waiting for the lock.
|
||||
*
|
||||
* NOTE: Assumes that the semaphore can be signaled from interrupt level. If
|
||||
* this is not possible for some reason, a separate thread will have to be
|
||||
* scheduled to do this.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static u32 acpi_ev_global_lock_handler(void *context)
|
||||
{
|
||||
u8 acquired = FALSE;
|
||||
|
||||
/*
|
||||
* Attempt to get the lock.
|
||||
*
|
||||
* If we don't get it now, it will be marked pending and we will
|
||||
* take another interrupt when it becomes free.
|
||||
*/
|
||||
ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
|
||||
if (acquired) {
|
||||
|
||||
/* Got the lock, now wake all threads waiting for it */
|
||||
|
||||
acpi_gbl_global_lock_acquired = TRUE;
|
||||
/* Send a unit to the semaphore */
|
||||
|
||||
if (ACPI_FAILURE(acpi_os_signal_semaphore(
|
||||
acpi_gbl_global_lock_semaphore, 1))) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Could not signal Global Lock semaphore"));
|
||||
}
|
||||
}
|
||||
|
||||
return (ACPI_INTERRUPT_HANDLED);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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);
|
||||
|
||||
status =
|
||||
acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
|
||||
(struct acpi_table_header **)&facs);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
acpi_gbl_global_lock_present = TRUE;
|
||||
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.
|
||||
*/
|
||||
if (status == AE_NO_HARDWARE_RESPONSE) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"No response from Global Lock hardware, disabling lock"));
|
||||
|
||||
acpi_gbl_global_lock_present = FALSE;
|
||||
status = AE_OK;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_remove_global_lock_handler
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Remove the handler for the Global Lock
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static 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);
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
static acpi_thread_id acpi_ev_global_lock_thread_id;
|
||||
static int acpi_ev_global_lock_acquired;
|
||||
|
||||
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
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, 0);
|
||||
if (status == AE_TIME) {
|
||||
if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) {
|
||||
acpi_ev_global_lock_acquired++;
|
||||
return AE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
|
||||
}
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
acpi_ev_global_lock_thread_id = acpi_os_get_thread_id();
|
||||
acpi_ev_global_lock_acquired++;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* Attempt to acquire the actual hardware lock */
|
||||
|
||||
ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
|
||||
if (acquired) {
|
||||
|
||||
/* We got the lock */
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Acquired hardware Global Lock\n"));
|
||||
|
||||
acpi_gbl_global_lock_acquired = TRUE;
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Did not get the lock. The pending bit was set above, and we must now
|
||||
* wait until we get the global lock released interrupt.
|
||||
*/
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
acpi_ev_global_lock_acquired--;
|
||||
if (acpi_ev_global_lock_acquired > 0) {
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
if (acpi_gbl_global_lock_present) {
|
||||
|
||||
/* Allow any thread to release the lock */
|
||||
|
||||
ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
|
||||
|
||||
/*
|
||||
* If the pending bit was set, we must write GBL_RLS to the control
|
||||
* register
|
||||
*/
|
||||
if (pending) {
|
||||
status =
|
||||
acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
|
||||
1);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Released hardware Global Lock\n"));
|
||||
}
|
||||
|
||||
acpi_gbl_global_lock_acquired = FALSE;
|
||||
|
||||
/* Release the local GL mutex */
|
||||
acpi_ev_global_lock_thread_id = NULL;
|
||||
acpi_ev_global_lock_acquired = 0;
|
||||
acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_terminate
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURN: none
|
||||
*
|
||||
* DESCRIPTION: Disable events and free memory allocated for table storage.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ev_terminate(void)
|
||||
{
|
||||
acpi_native_uint 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((u32) i, 0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Could not disable fixed event %d",
|
||||
(u32) i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable all GPEs in all GPE blocks */
|
||||
|
||||
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
|
||||
|
||||
/* Remove SCI handler */
|
||||
|
||||
status = acpi_ev_remove_sci_handler();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
|
||||
}
|
||||
|
||||
status = acpi_ev_remove_global_lock_handler();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Could not remove Global Lock handler"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Deallocate all handler objects installed within GPE info structs */
|
||||
|
||||
status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
1082
drivers/acpi/events/evregion.c
Normal file
1082
drivers/acpi/events/evregion.c
Normal file
File diff suppressed because it is too large
Load Diff
686
drivers/acpi/events/evrgnini.c
Normal file
686
drivers/acpi/events/evrgnini.c
Normal file
@@ -0,0 +1,686 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evrgnini- ACPI address_space (op_region) init
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evrgnini")
|
||||
|
||||
/* Local prototypes */
|
||||
static u8 acpi_ev_match_pci_root_bridge(char *id);
|
||||
|
||||
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;
|
||||
acpi_integer 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 = acpi_ns_get_parent_node(region_obj->region.node);
|
||||
|
||||
/*
|
||||
* 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 = acpi_ns_get_parent_node(pci_root_node);
|
||||
}
|
||||
|
||||
/* 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 = acpi_ns_get_parent_node(pci_device_node);
|
||||
}
|
||||
|
||||
if (!pci_device_node) {
|
||||
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 this device's pci_id */
|
||||
|
||||
acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id);
|
||||
|
||||
*region_context = pci_id;
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_match_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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static u8 acpi_ev_match_pci_root_bridge(char *id)
|
||||
{
|
||||
|
||||
/*
|
||||
* Check if this is a PCI root.
|
||||
* ACPI 3.0+: check for a PCI Express root also.
|
||||
*/
|
||||
if (!(ACPI_STRNCMP(id,
|
||||
PCI_ROOT_HID_STRING,
|
||||
sizeof(PCI_ROOT_HID_STRING))) ||
|
||||
!(ACPI_STRNCMP(id,
|
||||
PCI_EXPRESS_ROOT_HID_STRING,
|
||||
sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_device_id hid;
|
||||
struct acpi_compatible_id_list *cid;
|
||||
acpi_native_uint i;
|
||||
|
||||
/*
|
||||
* Get the _HID and check for a PCI Root Bridge
|
||||
*/
|
||||
status = acpi_ut_execute_HID(node, &hid);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
if (acpi_ev_match_pci_root_bridge(hid.value)) {
|
||||
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_ev_match_pci_root_bridge(cid->id[i].value)) {
|
||||
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 = acpi_ns_get_parent_node(region_obj->region.node);
|
||||
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;
|
||||
|
||||
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, 1);
|
||||
|
||||
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 = acpi_ns_get_parent_node(node);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
184
drivers/acpi/events/evsci.c
Normal file
184
drivers/acpi/events/evsci.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: evsci - System Control Interrupt configuration and
|
||||
* legacy to ACPI mode state transition functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evsci")
|
||||
|
||||
/* Local prototypes */
|
||||
static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 ACPI CA 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);
|
||||
|
||||
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 ACPI CA 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_sci_handler
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not
|
||||
* installed to begin with
|
||||
*
|
||||
* DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
|
||||
* taken.
|
||||
*
|
||||
* 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_sci_handler(void)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_remove_sci_handler);
|
||||
|
||||
/* 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);
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
812
drivers/acpi/events/evxface.c
Normal file
812
drivers/acpi/events/evxface.c
Normal file
@@ -0,0 +1,812 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evxface - External interfaces for ACPI events
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acevents.h>
|
||||
#include <acpi/acinterp.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evxface")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 /* ACPI_FUTURE_USAGE */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* Don't allow two handlers. */
|
||||
|
||||
if (NULL != 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 %X",
|
||||
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 %X, Handler=%p\n", 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 write to fixed event enable register %X",
|
||||
event));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X\n",
|
||||
event));
|
||||
}
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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: driver_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 notifies on an ACPI device
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status
|
||||
acpi_install_notify_handler(acpi_handle device,
|
||||
u32 handler_type,
|
||||
acpi_notify_handler handler, void *context)
|
||||
{
|
||||
union acpi_operand_object *obj_desc;
|
||||
union acpi_operand_object *notify_obj;
|
||||
struct acpi_namespace_node *node;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
if ((!device) ||
|
||||
(!handler) || (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);
|
||||
}
|
||||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 <external> global handler can be regsitered (per notify type).
|
||||
*/
|
||||
if (device == ACPI_ROOT_OBJECT) {
|
||||
|
||||
/* Make sure the handler is not already installed */
|
||||
|
||||
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
|
||||
acpi_gbl_system_notify.handler) ||
|
||||
((handler_type & ACPI_DEVICE_NOTIFY) &&
|
||||
acpi_gbl_device_notify.handler)) {
|
||||
status = AE_ALREADY_EXISTS;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
if (handler_type & ACPI_SYSTEM_NOTIFY) {
|
||||
acpi_gbl_system_notify.node = node;
|
||||
acpi_gbl_system_notify.handler = handler;
|
||||
acpi_gbl_system_notify.context = context;
|
||||
}
|
||||
|
||||
if (handler_type & ACPI_DEVICE_NOTIFY) {
|
||||
acpi_gbl_device_notify.node = node;
|
||||
acpi_gbl_device_notify.handler = handler;
|
||||
acpi_gbl_device_notify.context = context;
|
||||
}
|
||||
|
||||
/* Global notify handler installed */
|
||||
}
|
||||
|
||||
/*
|
||||
* All Other Objects:
|
||||
* Caller will only receive notifications specific to the target object.
|
||||
* Note that only certain object types can receive notifications.
|
||||
*/
|
||||
else {
|
||||
/* 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 */
|
||||
|
||||
obj_desc = acpi_ns_get_attached_object(node);
|
||||
if (obj_desc) {
|
||||
|
||||
/* Object exists - make sure there's no handler */
|
||||
|
||||
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
|
||||
obj_desc->common_notify.system_notify) ||
|
||||
((handler_type & ACPI_DEVICE_NOTIFY) &&
|
||||
obj_desc->common_notify.device_notify)) {
|
||||
status = AE_ALREADY_EXISTS;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
} else {
|
||||
/* 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 */
|
||||
|
||||
status =
|
||||
acpi_ns_attach_object(device, obj_desc, node->type);
|
||||
|
||||
/* Remove local reference to the object */
|
||||
|
||||
acpi_ut_remove_reference(obj_desc);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Install the handler */
|
||||
|
||||
notify_obj =
|
||||
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
|
||||
if (!notify_obj) {
|
||||
status = AE_NO_MEMORY;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
notify_obj->notify.node = node;
|
||||
notify_obj->notify.handler = handler;
|
||||
notify_obj->notify.context = context;
|
||||
|
||||
if (handler_type & ACPI_SYSTEM_NOTIFY) {
|
||||
obj_desc->common_notify.system_notify = notify_obj;
|
||||
}
|
||||
|
||||
if (handler_type & ACPI_DEVICE_NOTIFY) {
|
||||
obj_desc->common_notify.device_notify = notify_obj;
|
||||
}
|
||||
|
||||
if (handler_type == ACPI_ALL_NOTIFY) {
|
||||
|
||||
/* Extra ref if installed in both */
|
||||
|
||||
acpi_ut_add_reference(notify_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 notifies will be handled
|
||||
* handler_type - The type of handler:
|
||||
* ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
|
||||
* ACPI_DEVICE_NOTIFY: driver_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)
|
||||
{
|
||||
union acpi_operand_object *notify_obj;
|
||||
union acpi_operand_object *obj_desc;
|
||||
struct acpi_namespace_node *node;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
if ((!device) ||
|
||||
(!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Root Object */
|
||||
|
||||
if (device == ACPI_ROOT_OBJECT) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Removing notify handler for namespace root object\n"));
|
||||
|
||||
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
|
||||
!acpi_gbl_system_notify.handler) ||
|
||||
((handler_type & ACPI_DEVICE_NOTIFY) &&
|
||||
!acpi_gbl_device_notify.handler)) {
|
||||
status = AE_NOT_EXIST;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Make sure all deferred tasks are completed */
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
acpi_os_wait_events_complete(NULL);
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (handler_type & ACPI_SYSTEM_NOTIFY) {
|
||||
acpi_gbl_system_notify.node = NULL;
|
||||
acpi_gbl_system_notify.handler = NULL;
|
||||
acpi_gbl_system_notify.context = NULL;
|
||||
}
|
||||
|
||||
if (handler_type & ACPI_DEVICE_NOTIFY) {
|
||||
acpi_gbl_device_notify.node = NULL;
|
||||
acpi_gbl_device_notify.handler = NULL;
|
||||
acpi_gbl_device_notify.context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* All Other Objects */
|
||||
|
||||
else {
|
||||
/* 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 */
|
||||
|
||||
obj_desc = acpi_ns_get_attached_object(node);
|
||||
if (!obj_desc) {
|
||||
status = AE_NOT_EXIST;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Object exists - make sure there's an existing handler */
|
||||
|
||||
if (handler_type & ACPI_SYSTEM_NOTIFY) {
|
||||
notify_obj = obj_desc->common_notify.system_notify;
|
||||
if (!notify_obj) {
|
||||
status = AE_NOT_EXIST;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
if (notify_obj->notify.handler != handler) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
/* Make sure all deferred tasks are completed */
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
acpi_os_wait_events_complete(NULL);
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Remove the handler */
|
||||
obj_desc->common_notify.system_notify = NULL;
|
||||
acpi_ut_remove_reference(notify_obj);
|
||||
}
|
||||
|
||||
if (handler_type & ACPI_DEVICE_NOTIFY) {
|
||||
notify_obj = obj_desc->common_notify.device_notify;
|
||||
if (!notify_obj) {
|
||||
status = AE_NOT_EXIST;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
if (notify_obj->notify.handler != handler) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
/* Make sure all deferred tasks are completed */
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
acpi_os_wait_events_complete(NULL);
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Remove the handler */
|
||||
obj_desc->common_notify.device_notify = NULL;
|
||||
acpi_ut_remove_reference(notify_obj);
|
||||
}
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
exit:
|
||||
if (ACPI_FAILURE(status))
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_event_handler address, void *context)
|
||||
{
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
struct acpi_handler_info *handler;
|
||||
acpi_status status;
|
||||
acpi_cpu_flags flags;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 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 there isn't a handler there already */
|
||||
|
||||
if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
|
||||
ACPI_GPE_DISPATCH_HANDLER) {
|
||||
status = AE_ALREADY_EXISTS;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Allocate and init handler object */
|
||||
|
||||
handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
|
||||
if (!handler) {
|
||||
status = AE_NO_MEMORY;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
handler->address = address;
|
||||
handler->context = context;
|
||||
handler->method_node = gpe_event_info->dispatch.method_node;
|
||||
|
||||
/* Disable the GPE before installing the handler */
|
||||
|
||||
status = acpi_ev_disable_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Install the handler */
|
||||
|
||||
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
|
||||
gpe_event_info->dispatch.handler = handler;
|
||||
|
||||
/* Setup up dispatch flags to indicate handler (vs. method) */
|
||||
|
||||
gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */
|
||||
gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
|
||||
|
||||
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
|
||||
|
||||
unlock_and_exit:
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
exit:
|
||||
if (ACPI_FAILURE(status))
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Installing notify handler failed"));
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_install_gpe_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_event_handler address)
|
||||
{
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
struct acpi_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);
|
||||
}
|
||||
|
||||
/* 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 ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
|
||||
ACPI_GPE_DISPATCH_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;
|
||||
}
|
||||
|
||||
/* Disable the GPE before removing the handler */
|
||||
|
||||
status = acpi_ev_disable_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Make sure all deferred tasks are completed */
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
acpi_os_wait_events_complete(NULL);
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Remove the handler */
|
||||
|
||||
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
|
||||
handler = gpe_event_info->dispatch.handler;
|
||||
|
||||
/* Restore Method node (if any), set dispatch flags */
|
||||
|
||||
gpe_event_info->dispatch.method_node = handler->method_node;
|
||||
gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */
|
||||
if (handler->method_node) {
|
||||
gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
|
||||
}
|
||||
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
|
||||
|
||||
/* Now we can free the handler object */
|
||||
|
||||
ACPI_FREE(handler);
|
||||
|
||||
unlock_and_exit:
|
||||
(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
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
if (!handle) {
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
status = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
status = acpi_ev_acquire_global_lock(timeout);
|
||||
acpi_ex_exit_interpreter();
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
acpi_gbl_global_lock_handle++;
|
||||
*handle = acpi_gbl_global_lock_handle;
|
||||
}
|
||||
|
||||
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 != acpi_gbl_global_lock_handle) {
|
||||
return (AE_NOT_ACQUIRED);
|
||||
}
|
||||
|
||||
status = acpi_ev_release_global_lock();
|
||||
return (status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_release_global_lock)
|
||||
720
drivers/acpi/events/evxfevnt.c
Normal file
720
drivers/acpi/events/evxfevnt.c
Normal file
@@ -0,0 +1,720 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evxfevnt - External Interfaces, ACPI event disable/enable
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/actables.h>
|
||||
|
||||
#define _COMPONENT ACPI_EVENTS
|
||||
ACPI_MODULE_NAME("evxfevnt")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enable
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Transfers the system into ACPI mode.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_enable(void)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_enable);
|
||||
|
||||
/* ACPI tables must be present */
|
||||
|
||||
if (!acpi_tb_tables_loaded()) {
|
||||
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
|
||||
}
|
||||
|
||||
/* 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"));
|
||||
} else {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
|
||||
"Transition to ACPI mode successful\n"));
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
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 (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_set_register(acpi_gbl_fixed_event_info[event].
|
||||
enable_register_id, 1);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Make sure that the hardware responded */
|
||||
|
||||
status =
|
||||
acpi_get_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_set_gpe_type
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* Type - New GPE type
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Set the type of an individual GPE
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_set_gpe_type);
|
||||
|
||||
/* 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 ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) {
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/* Set the new type (will disable GPE if currently enabled) */
|
||||
|
||||
status = acpi_ev_set_gpe_type(gpe_event_info, type);
|
||||
|
||||
unlock_and_exit:
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_set_gpe_type)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* Flags - Just enable, or also wake enable?
|
||||
* Called from ISR or not
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Enable an ACPI event (general purpose)
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_enable_gpe);
|
||||
|
||||
/* Use semaphore lock if not executing at interrupt level */
|
||||
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 enable */
|
||||
|
||||
status = acpi_ev_enable_gpe(gpe_event_info, TRUE);
|
||||
|
||||
unlock_and_exit:
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_disable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* Flags - Just disable, or also wake disable?
|
||||
* Called from ISR or not
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Disable an ACPI event (general purpose)
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_disable_gpe);
|
||||
|
||||
/* Use semaphore lock if not executing at interrupt level */
|
||||
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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_disable_gpe(gpe_event_info);
|
||||
|
||||
unlock_and_exit:
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_disable_event
|
||||
*
|
||||
* PARAMETERS: Event - The fixed eventto be enabled
|
||||
* 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_set_register(acpi_gbl_fixed_event_info[event].
|
||||
enable_register_id, 0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status =
|
||||
acpi_get_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_set_register(acpi_gbl_fixed_event_info[event].
|
||||
status_register_id, 1);
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_clear_event)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_clear_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* Flags - Called from an ISR or not
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Clear an ACPI event (general purpose)
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_clear_gpe);
|
||||
|
||||
/* Use semaphore lock if not executing at interrupt level */
|
||||
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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:
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
|
||||
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 = AE_OK;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Get the status of the requested fixed event */
|
||||
|
||||
status =
|
||||
acpi_get_register(acpi_gbl_fixed_event_info[event].
|
||||
status_register_id, event_status);
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_event_status)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_get_gpe_status
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* Flags - Called from an ISR or not
|
||||
* event_status - Where the current status of the event will
|
||||
* be returned
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Get status of an event (general purpose)
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status
|
||||
acpi_get_gpe_status(acpi_handle gpe_device,
|
||||
u32 gpe_number, u32 flags, acpi_event_status * event_status)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
|
||||
|
||||
/* Use semaphore lock if not executing at interrupt level */
|
||||
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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:
|
||||
if (flags & ACPI_NOT_ISR) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
|
||||
#endif /* ACPI_FUTURE_USAGE */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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
|
||||
*
|
||||
******************************************************************************/
|
||||
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 (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(gpe_device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
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, register_count, 0,
|
||||
interrupt_number, &gpe_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Run the _PRW methods and enable the GPEs */
|
||||
|
||||
status = acpi_ev_initialize_gpe_block(node, gpe_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Get the device_object attached to the node */
|
||||
|
||||
obj_desc = acpi_ns_get_attached_object(node);
|
||||
if (!obj_desc) {
|
||||
|
||||
/* No object, create a new one */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(gpe_device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
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)
|
||||
253
drivers/acpi/events/evxfregn.c
Normal file
253
drivers/acpi/events/evxfregn.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
|
||||
* Address Spaces.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/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.
|
||||
*
|
||||
******************************************************************************/
|
||||
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_map_handle_to_node(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;
|
||||
}
|
||||
|
||||
/* 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_map_handle_to_node(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)
|
||||
10
drivers/acpi/executer/Makefile
Normal file
10
drivers/acpi/executer/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Makefile for all Linux ACPI interpreter subdirectories
|
||||
#
|
||||
|
||||
obj-y := exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
|
||||
exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\
|
||||
excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \
|
||||
exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o
|
||||
|
||||
EXTRA_CFLAGS += $(ACPI_CFLAGS)
|
||||
411
drivers/acpi/executer/exconfig.c
Normal file
411
drivers/acpi/executer/exconfig.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acevents.h>
|
||||
#include <acpi/actables.h>
|
||||
#include <acpi/acdispat.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exconfig")
|
||||
|
||||
/* Local prototypes */
|
||||
static acpi_status
|
||||
acpi_ex_add_table(acpi_native_uint table_index,
|
||||
struct acpi_namespace_node *parent_node,
|
||||
union acpi_operand_object **ddb_handle);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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(acpi_native_uint table_index,
|
||||
struct acpi_namespace_node *parent_node,
|
||||
union acpi_operand_object **ddb_handle)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_operand_object *obj_desc;
|
||||
|
||||
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->reference.opcode = AML_LOAD_OP;
|
||||
*ddb_handle = obj_desc;
|
||||
|
||||
/* Install the new table into the local data structures */
|
||||
|
||||
obj_desc->reference.object = ACPI_CAST_PTR(void, 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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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];
|
||||
acpi_native_uint table_index;
|
||||
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;
|
||||
|
||||
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_internal_object(ACPI_TYPE_INTEGER);
|
||||
if (!ddb_handle) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
ddb_handle->integer.value = 0;
|
||||
*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] != '\\') &&
|
||||
(operand[4]->string.pointer[0] != '^')) {
|
||||
/*
|
||||
* 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);
|
||||
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 - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
|
||||
table->signature, table->oem_id,
|
||||
table->oem_table_id));
|
||||
}
|
||||
|
||||
*return_desc = ddb_handle;
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_desc table_desc;
|
||||
acpi_native_uint table_index;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_load_op);
|
||||
|
||||
ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
|
||||
|
||||
/* Source Object can be either an op_region or a Buffer/Field */
|
||||
|
||||
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
case ACPI_TYPE_REGION:
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
|
||||
obj_desc,
|
||||
acpi_ut_get_object_type_name(obj_desc)));
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
table_desc.address = obj_desc->region.address;
|
||||
table_desc.length = obj_desc->region.length;
|
||||
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
|
||||
|
||||
/* Simply extract the buffer from the buffer object */
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Load from Buffer or Field %p %s\n", obj_desc,
|
||||
acpi_ut_get_object_type_name(obj_desc)));
|
||||
|
||||
table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
|
||||
obj_desc->buffer.pointer);
|
||||
table_desc.length = table_desc.pointer->length;
|
||||
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
|
||||
|
||||
obj_desc->buffer.pointer = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the new table into the local data structures
|
||||
*/
|
||||
status = acpi_tb_add_table(&table_desc, &table_index);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_tb_delete_table(&table_desc);
|
||||
}
|
||||
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;
|
||||
acpi_native_uint table_index;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_unload_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.
|
||||
*/
|
||||
if ((!ddb_handle) ||
|
||||
(ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
|
||||
(ACPI_GET_OBJECT_TYPE(ddb_handle) != ACPI_TYPE_LOCAL_REFERENCE)) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* Get the table index from the ddb_handle */
|
||||
|
||||
table_index = (acpi_native_uint) table_desc->reference.object;
|
||||
|
||||
/*
|
||||
* Delete the entire namespace under this table Node
|
||||
* (Offset contains the table_id)
|
||||
*/
|
||||
acpi_tb_delete_namespace_by_owner(table_index);
|
||||
acpi_tb_release_owner_id(table_index);
|
||||
|
||||
acpi_tb_set_table_loaded_flag(table_index, FALSE);
|
||||
|
||||
/* Delete the table descriptor (ddb_handle) */
|
||||
|
||||
acpi_ut_remove_reference(table_desc);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
684
drivers/acpi/executer/exconvrt.c
Normal file
684
drivers/acpi/executer/exconvrt.c
Normal file
@@ -0,0 +1,684 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exconvrt - Object conversion routines
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exconvrt")
|
||||
|
||||
/* Local prototypes */
|
||||
static u32
|
||||
acpi_ex_convert_to_ascii(acpi_integer 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;
|
||||
acpi_integer result;
|
||||
u32 i;
|
||||
u32 count;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ex_convert_to_integer, obj_desc);
|
||||
|
||||
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 |= (((acpi_integer) pointer[i]) << (i * 8));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* No other types can get here */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create a new integer */
|
||||
|
||||
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
|
||||
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 */
|
||||
|
||||
return_desc->integer.value = result;
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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;
|
||||
ACPI_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;
|
||||
ACPI_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(acpi_integer integer,
|
||||
u16 base, u8 * string, u8 data_width)
|
||||
{
|
||||
acpi_integer digit;
|
||||
acpi_native_uint i;
|
||||
acpi_native_uint j;
|
||||
acpi_native_uint k = 0;
|
||||
acpi_native_uint hex_length;
|
||||
acpi_native_uint 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_native_uint) 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 supressed, 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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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)
|
||||
*/
|
||||
return_desc =
|
||||
acpi_ut_create_string_object((acpi_size)
|
||||
(string_length - 1));
|
||||
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((acpi_integer)
|
||||
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)
|
||||
*/
|
||||
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 !=
|
||||
ACPI_GET_OBJECT_TYPE(source_desc)) {
|
||||
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:
|
||||
|
||||
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: %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 %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);
|
||||
}
|
||||
612
drivers/acpi/executer/excreate.c
Normal file
612
drivers/acpi/executer/excreate.c
Normal file
@@ -0,0 +1,612 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: excreate - Named object creation
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acevents.h>
|
||||
#include <acpi/actables.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) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
case ACPI_TYPE_STRING:
|
||||
case ACPI_TYPE_BUFFER:
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
case ACPI_TYPE_BUFFER_FIELD:
|
||||
|
||||
/*
|
||||
* The new alias has the type ALIAS and points to the original
|
||||
* NS node, not the object itself. This is because for these
|
||||
* types, the object can change dynamically via a Store.
|
||||
*/
|
||||
alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
|
||||
alias_node->object =
|
||||
ACPI_CAST_PTR(union acpi_operand_object, target_node);
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_METHOD:
|
||||
|
||||
/*
|
||||
* The new alias has the type ALIAS and points to the original
|
||||
* NS node, not the object itself. This is because for these
|
||||
* types, the object can change dynamically via a Store.
|
||||
*/
|
||||
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
|
||||
* region_space - 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 region_space, 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 ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) &&
|
||||
(region_space < ACPI_USER_REGION_BEGIN)) {
|
||||
ACPI_ERROR((AE_INFO, "Invalid AddressSpace type %X",
|
||||
region_space));
|
||||
return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (%X)\n",
|
||||
acpi_ut_get_region_name(region_space), region_space));
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Init the region from the operands */
|
||||
|
||||
obj_desc->region.space_id = region_space;
|
||||
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_table_region
|
||||
*
|
||||
* PARAMETERS: walk_state - Current state
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Create a new data_table_region object
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_operand_object **operand = &walk_state->operands[0];
|
||||
union acpi_operand_object *obj_desc;
|
||||
struct acpi_namespace_node *node;
|
||||
union acpi_operand_object *region_obj2;
|
||||
acpi_native_uint table_index;
|
||||
struct acpi_table_header *table;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_create_table_region);
|
||||
|
||||
/* Get the Node from the object stack */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Find the ACPI table */
|
||||
|
||||
status = acpi_tb_find_table(operand[1]->string.pointer,
|
||||
operand[2]->string.pointer,
|
||||
operand[3]->string.pointer, &table_index);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Create the region descriptor */
|
||||
|
||||
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
|
||||
if (!obj_desc) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
region_obj2 = obj_desc->common.next_object;
|
||||
region_obj2->extra.region_context = NULL;
|
||||
|
||||
status = acpi_get_table_by_index(table_index, &table);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Init the region from the operands */
|
||||
|
||||
obj_desc->region.space_id = REGION_DATA_TABLE;
|
||||
obj_desc->region.address =
|
||||
(acpi_physical_address) ACPI_TO_INTEGER(table);
|
||||
obj_desc->region.length = table->length;
|
||||
obj_desc->region.node = node;
|
||||
obj_desc->region.flags = AOPOBJ_DATA_VALID;
|
||||
|
||||
/* Install the new region object in the parent Node */
|
||||
|
||||
status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = acpi_ev_initialize_region(obj_desc, FALSE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status == AE_NOT_EXIST) {
|
||||
status = AE_OK;
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* Disassemble the method flags. Split off the Arg Count
|
||||
* for efficiency
|
||||
*/
|
||||
method_flags = (u8) operand[1]->integer.value;
|
||||
|
||||
obj_desc->method.method_flags =
|
||||
(u8) (method_flags & ~AML_METHOD_ARG_COUNT);
|
||||
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 (acpi_gbl_all_methods_serialized) {
|
||||
obj_desc->method.sync_level = 0;
|
||||
obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
|
||||
} else if (method_flags & AML_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_SYNCH_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);
|
||||
}
|
||||
1055
drivers/acpi/executer/exdump.c
Normal file
1055
drivers/acpi/executer/exdump.c
Normal file
File diff suppressed because it is too large
Load Diff
384
drivers/acpi/executer/exfield.c
Normal file
384
drivers/acpi/executer/exfield.c
Normal file
@@ -0,0 +1,384 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exfield - ACPI AML (p-code) execution - field manipulation
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exfield")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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;
|
||||
u8 locked;
|
||||
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc) == 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 ((ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD)
|
||||
&& (obj_desc->field.region_obj->region.space_id ==
|
||||
ACPI_ADR_SPACE_SMBUS)) {
|
||||
/*
|
||||
* This is an SMBus read. We must create a buffer to hold the data
|
||||
* and directly access the region handler.
|
||||
*/
|
||||
buffer_desc =
|
||||
acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
|
||||
if (!buffer_desc) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Lock entire transaction if requested */
|
||||
|
||||
locked =
|
||||
acpi_ex_acquire_global_lock(obj_desc->common_field.
|
||||
field_flags);
|
||||
|
||||
/*
|
||||
* Perform the read.
|
||||
* Note: Smbus protocol value is passed in upper 16-bits of Function
|
||||
*/
|
||||
status = acpi_ex_access_region(obj_desc, 0,
|
||||
ACPI_CAST_PTR(acpi_integer,
|
||||
buffer_desc->
|
||||
buffer.pointer),
|
||||
ACPI_READ | (obj_desc->field.
|
||||
attribute << 16));
|
||||
acpi_ex_release_global_lock(locked);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a buffer for the contents of the field.
|
||||
*
|
||||
* If the field is larger than the size of an acpi_integer, 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_internal_object(ACPI_TYPE_INTEGER);
|
||||
if (!buffer_desc) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
length = acpi_gbl_integer_byte_width;
|
||||
buffer_desc->integer.value = 0;
|
||||
buffer = &buffer_desc->integer.value;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||
"FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
|
||||
obj_desc, ACPI_GET_OBJECT_TYPE(obj_desc), 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 */
|
||||
|
||||
locked =
|
||||
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(locked);
|
||||
|
||||
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;
|
||||
u32 required_length;
|
||||
void *buffer;
|
||||
void *new_buffer;
|
||||
u8 locked;
|
||||
union acpi_operand_object *buffer_desc;
|
||||
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc) == 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 ((ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD)
|
||||
&& (obj_desc->field.region_obj->region.space_id ==
|
||||
ACPI_ADR_SPACE_SMBUS)) {
|
||||
/*
|
||||
* This is an SMBus write. We will bypass the entire field mechanism
|
||||
* and handoff the buffer directly to the handler.
|
||||
*
|
||||
* Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE).
|
||||
*/
|
||||
if (ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_BUFFER) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"SMBus write requires Buffer, found type %s",
|
||||
acpi_ut_get_object_type_name(source_desc)));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"SMBus write requires Buffer of length %X, found length %X",
|
||||
ACPI_SMBUS_BUFFER_SIZE,
|
||||
source_desc->buffer.length));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
|
||||
}
|
||||
|
||||
buffer_desc =
|
||||
acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
|
||||
if (!buffer_desc) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
buffer = buffer_desc->buffer.pointer;
|
||||
ACPI_MEMCPY(buffer, source_desc->buffer.pointer,
|
||||
ACPI_SMBUS_BUFFER_SIZE);
|
||||
|
||||
/* Lock entire transaction if requested */
|
||||
|
||||
locked =
|
||||
acpi_ex_acquire_global_lock(obj_desc->common_field.
|
||||
field_flags);
|
||||
|
||||
/*
|
||||
* Perform the write (returns status and perhaps data in the
|
||||
* same buffer)
|
||||
* Note: SMBus protocol type is passed in upper 16-bits of Function.
|
||||
*/
|
||||
status = acpi_ex_access_region(obj_desc, 0,
|
||||
(acpi_integer *) buffer,
|
||||
ACPI_WRITE | (obj_desc->field.
|
||||
attribute << 16));
|
||||
acpi_ex_release_global_lock(locked);
|
||||
|
||||
*result_desc = buffer_desc;
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Get a pointer to the data to be written */
|
||||
|
||||
switch (ACPI_GET_OBJECT_TYPE(source_desc)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
new_buffer = NULL;
|
||||
required_length =
|
||||
ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
|
||||
|
||||
if (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.
|
||||
*/
|
||||
ACPI_MEMCPY((char *)new_buffer, (char *)buffer, length);
|
||||
buffer = new_buffer;
|
||||
length = required_length;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||
"FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
|
||||
source_desc,
|
||||
acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE
|
||||
(source_desc)),
|
||||
ACPI_GET_OBJECT_TYPE(source_desc), 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(ACPI_GET_OBJECT_TYPE(obj_desc)),
|
||||
ACPI_GET_OBJECT_TYPE(obj_desc),
|
||||
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 */
|
||||
|
||||
locked =
|
||||
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(locked);
|
||||
|
||||
/* Free temporary buffer if we used one */
|
||||
|
||||
if (new_buffer) {
|
||||
ACPI_FREE(new_buffer);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
928
drivers/acpi/executer/exfldio.c
Normal file
928
drivers/acpi/executer/exfldio.c
Normal file
@@ -0,0 +1,928 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exfldio - Aml Field I/O
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acevents.h>
|
||||
#include <acpi/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,
|
||||
acpi_integer * value, u32 read_write);
|
||||
|
||||
static u8
|
||||
acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
|
||||
acpi_integer 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;
|
||||
|
||||
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 (ACPI_GET_OBJECT_TYPE(rgn_desc) != ACPI_TYPE_REGION) {
|
||||
ACPI_ERROR((AE_INFO, "Needed Region, found type %X (%s)",
|
||||
ACPI_GET_OBJECT_TYPE(rgn_desc),
|
||||
acpi_ut_get_object_type_name(rgn_desc)));
|
||||
|
||||
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 (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
|
||||
status = acpi_ds_get_region_arguments(rgn_desc);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit if Address/Length have been disallowed by the host OS */
|
||||
|
||||
if (rgn_desc->common.flags & AOPOBJ_INVALID) {
|
||||
return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exit now for SMBus address space, it has a non-linear address space
|
||||
* and the request cannot be directly validated
|
||||
*/
|
||||
if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
|
||||
|
||||
/* SMBus 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.
|
||||
*/
|
||||
if (ACPI_ROUND_UP(rgn_desc->region.length,
|
||||
obj_desc->common_field.
|
||||
access_byte_width) >=
|
||||
(obj_desc->common_field.base_byte_offset +
|
||||
(acpi_native_uint) 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 (%d bytes) too large for region [%4.4s] (length %X)",
|
||||
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 %X+%X+%X is beyond end of region [%4.4s] (length %X)",
|
||||
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
|
||||
* the size of acpi_integer)
|
||||
* 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,
|
||||
acpi_integer * value, u32 function)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_operand_object *rgn_desc;
|
||||
acpi_physical_address address;
|
||||
|
||||
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;
|
||||
address = rgn_desc->region.address +
|
||||
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 %p\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, (void *)address));
|
||||
|
||||
/* Invoke the appropriate address_space/op_region handler */
|
||||
|
||||
status = acpi_ev_address_space_dispatch(rgn_desc, function,
|
||||
address,
|
||||
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(%X) 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(%X) 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,
|
||||
acpi_integer 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 >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) {
|
||||
/*
|
||||
* The Value is larger than the maximum value that can fit into
|
||||
* the register.
|
||||
*/
|
||||
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,
|
||||
acpi_integer * value, u32 read_write)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_integer 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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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.
|
||||
*/
|
||||
ACPI_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.
|
||||
*/
|
||||
ACPI_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,
|
||||
(acpi_integer) 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,
|
||||
(acpi_integer) 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);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||
"I/O to Data Register: ValuePtr %p\n",
|
||||
value));
|
||||
|
||||
if (read_write == ACPI_READ) {
|
||||
|
||||
/* Read the datum from the data_register */
|
||||
|
||||
status =
|
||||
acpi_ex_extract_from_field(obj_desc->index_field.
|
||||
data_obj, value,
|
||||
sizeof(acpi_integer));
|
||||
} else {
|
||||
/* Write the datum to the data_register */
|
||||
|
||||
status =
|
||||
acpi_ex_insert_into_field(obj_desc->index_field.
|
||||
data_obj, value,
|
||||
sizeof(acpi_integer));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %X",
|
||||
ACPI_GET_OBJECT_TYPE(obj_desc)));
|
||||
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 %d\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 %d\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,
|
||||
acpi_integer mask,
|
||||
acpi_integer field_value,
|
||||
u32 field_datum_byte_offset)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
acpi_integer merged_value;
|
||||
acpi_integer 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_INTEGER_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: %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;
|
||||
acpi_integer raw_datum;
|
||||
acpi_integer merged_datum;
|
||||
u32 field_offset = 0;
|
||||
u32 buffer_offset = 0;
|
||||
u32 buffer_tail_bits;
|
||||
u32 datum_count;
|
||||
u32 field_datum_count;
|
||||
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 %X (bits) is too large for buffer (%X)",
|
||||
obj_desc->common_field.bit_length, buffer_length));
|
||||
|
||||
return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
|
||||
}
|
||||
ACPI_MEMSET(buffer, 0, buffer_length);
|
||||
|
||||
/* Compute the number of datums (access width data items) */
|
||||
|
||||
datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
|
||||
obj_desc->common_field.access_bit_width);
|
||||
field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
|
||||
obj_desc->common_field.
|
||||
start_field_bit_offset,
|
||||
obj_desc->common_field.
|
||||
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 ((obj_desc->common_field.access_bit_width -
|
||||
obj_desc->common_field.start_field_bit_offset) <
|
||||
ACPI_INTEGER_BIT_SIZE) {
|
||||
merged_datum |=
|
||||
raw_datum << (obj_desc->common_field.
|
||||
access_bit_width -
|
||||
obj_desc->common_field.
|
||||
start_field_bit_offset);
|
||||
}
|
||||
|
||||
if (i == datum_count) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write merged datum to target buffer */
|
||||
|
||||
ACPI_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 %
|
||||
obj_desc->common_field.access_bit_width;
|
||||
if (buffer_tail_bits) {
|
||||
merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
|
||||
}
|
||||
|
||||
/* Write the last datum to the buffer */
|
||||
|
||||
ACPI_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)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_integer mask;
|
||||
acpi_integer width_mask;
|
||||
acpi_integer merged_datum;
|
||||
acpi_integer raw_datum = 0;
|
||||
u32 field_offset = 0;
|
||||
u32 buffer_offset = 0;
|
||||
u32 buffer_tail_bits;
|
||||
u32 datum_count;
|
||||
u32 field_datum_count;
|
||||
u32 i;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_insert_into_field);
|
||||
|
||||
/* Validate input buffer */
|
||||
|
||||
if (buffer_length <
|
||||
ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Field size %X (bits) is too large for buffer (%X)",
|
||||
obj_desc->common_field.bit_length, buffer_length));
|
||||
|
||||
return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the bitmasks used for bit insertion.
|
||||
* Note: This if/else is used to bypass compiler differences with the
|
||||
* shift operator
|
||||
*/
|
||||
if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
|
||||
width_mask = ACPI_INTEGER_MAX;
|
||||
} else {
|
||||
width_mask =
|
||||
ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
|
||||
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,
|
||||
obj_desc->common_field.access_bit_width);
|
||||
|
||||
field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
|
||||
obj_desc->common_field.
|
||||
start_field_bit_offset,
|
||||
obj_desc->common_field.
|
||||
access_bit_width);
|
||||
|
||||
/* Get initial Datum from the input buffer */
|
||||
|
||||
ACPI_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)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
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 ((obj_desc->common_field.access_bit_width -
|
||||
obj_desc->common_field.start_field_bit_offset) <
|
||||
ACPI_INTEGER_BIT_SIZE) {
|
||||
merged_datum =
|
||||
raw_datum >> (obj_desc->common_field.
|
||||
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;
|
||||
ACPI_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) %
|
||||
obj_desc->common_field.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);
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
725
drivers/acpi/executer/exmisc.c
Normal file
725
drivers/acpi/executer/exmisc.c
Normal file
@@ -0,0 +1,725 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/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 (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be a reference to a Local or Arg
|
||||
*/
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
case AML_DEBUG_OP:
|
||||
|
||||
/* 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 opcode %X",
|
||||
obj_desc->reference.opcode));
|
||||
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 %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.opcode = AML_REF_OF_OP;
|
||||
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;
|
||||
ACPI_MEMCPY(new_buf, operand0->buffer.pointer, length0);
|
||||
ACPI_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 (ACPI_GET_OBJECT_TYPE(operand0)) {
|
||||
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: %X",
|
||||
ACPI_GET_OBJECT_TYPE(operand0)));
|
||||
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 (ACPI_GET_OBJECT_TYPE(operand0)) {
|
||||
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 */
|
||||
|
||||
ACPI_MEMCPY(new_buf, &operand0->integer.value,
|
||||
acpi_gbl_integer_byte_width);
|
||||
|
||||
/* Copy the second integer (LSB first) after the first */
|
||||
|
||||
ACPI_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 */
|
||||
|
||||
ACPI_STRCPY(new_buf, operand0->string.pointer);
|
||||
ACPI_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 */
|
||||
|
||||
ACPI_MEMCPY(new_buf, operand0->buffer.pointer,
|
||||
operand0->buffer.length);
|
||||
ACPI_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: %X",
|
||||
ACPI_GET_OBJECT_TYPE(operand0)));
|
||||
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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_integer
|
||||
acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer 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,
|
||||
acpi_integer integer0,
|
||||
acpi_integer 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;
|
||||
acpi_integer integer0;
|
||||
acpi_integer 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 (ACPI_GET_OBJECT_TYPE(operand0)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(operand0) == 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 = ACPI_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);
|
||||
}
|
||||
373
drivers/acpi/executer/exmutex.c
Normal file
373
drivers/acpi/executer/exmutex.c
Normal file
@@ -0,0 +1,373 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exmutex - ASL Mutex Acquire/Release functions
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/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)
|
||||
{
|
||||
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;
|
||||
} 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
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* Sanity check: we must have a valid thread ID */
|
||||
|
||||
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 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 (%d)",
|
||||
acpi_ut_get_node_name(obj_desc->mutex.node),
|
||||
walk_state->thread->current_sync_level));
|
||||
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
|
||||
}
|
||||
|
||||
/* Support for multiple acquires by the owning thread */
|
||||
|
||||
if (obj_desc->mutex.owner_thread_id == acpi_os_get_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->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
|
||||
status =
|
||||
acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
|
||||
} else {
|
||||
status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
|
||||
(u16) time_desc->integer.
|
||||
value);
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
||||
/* Includes failure from a timeout on time_desc */
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Have the mutex: update mutex and walk info and save the sync_level */
|
||||
|
||||
obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id();
|
||||
obj_desc->mutex.acquisition_depth = 1;
|
||||
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(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_release_mutex);
|
||||
|
||||
if (!obj_desc) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* The mutex must have been previously acquired in order to release it */
|
||||
|
||||
if (!obj_desc->mutex.owner_thread_id) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* Sanity check: we 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 ((obj_desc->mutex.owner_thread_id !=
|
||||
walk_state->thread->thread_id)
|
||||
&& (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
|
||||
(unsigned long)walk_state->thread->thread_id,
|
||||
acpi_ut_get_node_name(obj_desc->mutex.node),
|
||||
(unsigned long)obj_desc->mutex.owner_thread_id));
|
||||
return_ACPI_STATUS(AE_AML_NOT_OWNER);
|
||||
}
|
||||
|
||||
/*
|
||||
* The sync level of the mutex must be less than or equal to the current
|
||||
* sync level
|
||||
*/
|
||||
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Cannot release Mutex [%4.4s], incorrect SyncLevel",
|
||||
acpi_ut_get_node_name(obj_desc->mutex.node)));
|
||||
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Unlink the mutex from the owner's list */
|
||||
|
||||
acpi_ex_unlink_mutex(obj_desc, walk_state->thread);
|
||||
|
||||
/* Release the mutex, special case for Global Lock */
|
||||
|
||||
if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
|
||||
status = acpi_ev_release_global_lock();
|
||||
} else {
|
||||
acpi_os_release_mutex(obj_desc->mutex.os_mutex);
|
||||
}
|
||||
|
||||
/* Update the mutex and restore sync_level */
|
||||
|
||||
obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
|
||||
walk_state->thread->current_sync_level =
|
||||
obj_desc->mutex.original_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_ENTRY();
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Release the mutex, special case for Global Lock */
|
||||
|
||||
if (obj_desc->mutex.os_mutex == 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_id = ACPI_MUTEX_NOT_ACQUIRED;
|
||||
|
||||
/* Update Thread sync_level (Last mutex is the important one) */
|
||||
|
||||
thread->current_sync_level =
|
||||
obj_desc->mutex.original_sync_level;
|
||||
}
|
||||
}
|
||||
436
drivers/acpi/executer/exnames.c
Normal file
436
drivers/acpi/executer/exnames.c
Normal file
@@ -0,0 +1,436 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exnames - interpreter/scanner name load/execute
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/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 %d", 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) {
|
||||
ACPI_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 %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);
|
||||
}
|
||||
1036
drivers/acpi/executer/exoparg1.c
Normal file
1036
drivers/acpi/executer/exoparg1.c
Normal file
File diff suppressed because it is too large
Load Diff
597
drivers/acpi/executer/exoparg2.c
Normal file
597
drivers/acpi/executer/exoparg2.c
Normal file
@@ -0,0 +1,597 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exoparg2 - AML execution - opcodes with 2 arguments
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acparser.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acevents.h>
|
||||
#include <acpi/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;
|
||||
}
|
||||
#ifdef ACPI_GPE_NOTIFY_CHECK
|
||||
/*
|
||||
* GPE method wake/notify check. Here, we want to ensure that we
|
||||
* don't receive any "DeviceWake" Notifies from a GPE _Lxx or _Exx
|
||||
* GPE method during system runtime. If we do, the GPE is marked
|
||||
* as "wake-only" and disabled.
|
||||
*
|
||||
* 1) Is the Notify() value == device_wake?
|
||||
* 2) Is this a GPE deferred method? (An _Lxx or _Exx method)
|
||||
* 3) Did the original GPE happen at system runtime?
|
||||
* (versus during wake)
|
||||
*
|
||||
* If all three cases are true, this is a wake-only GPE that should
|
||||
* be disabled at runtime.
|
||||
*/
|
||||
if (value == 2) { /* device_wake */
|
||||
status =
|
||||
acpi_ev_check_for_wake_only_gpe(walk_state->
|
||||
gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
||||
/* AE_WAKE_ONLY_GPE only error, means ignore this notify */
|
||||
|
||||
return_ACPI_STATUS(AE_OK)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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 %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 %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;
|
||||
}
|
||||
|
||||
/* Return the remainder */
|
||||
|
||||
walk_state->result_obj = return_desc1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
acpi_integer index;
|
||||
acpi_status status = AE_OK;
|
||||
acpi_size length;
|
||||
|
||||
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.
|
||||
*/
|
||||
length = 0;
|
||||
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)
|
||||
*/
|
||||
ACPI_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.offset = (u32) index;
|
||||
return_desc->reference.opcode = AML_INDEX_OP;
|
||||
|
||||
/*
|
||||
* At this point, the Source operand is a String, Buffer, or Package.
|
||||
* Verify that the index is within range.
|
||||
*/
|
||||
switch (ACPI_GET_OBJECT_TYPE(operand[0])) {
|
||||
case ACPI_TYPE_STRING:
|
||||
|
||||
if (index >= operand[0]->string.length) {
|
||||
status = AE_AML_STRING_LIMIT;
|
||||
}
|
||||
|
||||
return_desc->reference.target_type =
|
||||
ACPI_TYPE_BUFFER_FIELD;
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
if (index >= operand[0]->buffer.length) {
|
||||
status = AE_AML_BUFFER_LIMIT;
|
||||
}
|
||||
|
||||
return_desc->reference.target_type =
|
||||
ACPI_TYPE_BUFFER_FIELD;
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
|
||||
if (index >= 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 (%X%8.8X) is beyond end of object",
|
||||
ACPI_FORMAT_UINT64(index)));
|
||||
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 %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);
|
||||
}
|
||||
|
||||
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 %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_INTEGER_MAX;
|
||||
}
|
||||
|
||||
walk_state->result_obj = return_desc;
|
||||
|
||||
cleanup:
|
||||
|
||||
/* Delete return object on error */
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_ut_remove_reference(return_desc);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
271
drivers/acpi/executer/exoparg3.c
Normal file
271
drivers/acpi/executer/exoparg3.c
Normal file
@@ -0,0 +1,271 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exoparg3 - AML execution - opcodes with 3 arguments
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/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);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Unknown AML opcode %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;
|
||||
acpi_integer 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(ACPI_GET_OBJECT_TYPE
|
||||
(operand[0]));
|
||||
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 (ACPI_GET_OBJECT_TYPE(operand[0])) {
|
||||
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 */
|
||||
|
||||
ACPI_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 %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);
|
||||
}
|
||||
|
||||
/* Set the return object and exit */
|
||||
|
||||
else {
|
||||
walk_state->result_obj = return_desc;
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
336
drivers/acpi/executer/exoparg6.c
Normal file
336
drivers/acpi/executer/exoparg6.c
Normal file
@@ -0,0 +1,336 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exoparg6 - AML execution - opcodes with 6 arguments
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/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;
|
||||
acpi_integer 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 (%X%8.8X) beyond package end (%X)",
|
||||
ACPI_FORMAT_UINT64(index),
|
||||
operand[0]->package.count));
|
||||
status = AE_AML_PACKAGE_LIMIT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create an integer for the return value */
|
||||
|
||||
return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
|
||||
if (!return_desc) {
|
||||
status = AE_NO_MEMORY;
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
|
||||
/* Default return value if no match found */
|
||||
|
||||
return_desc->integer.value = ACPI_INTEGER_MAX;
|
||||
|
||||
/*
|
||||
* 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_INTEGER_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 %X",
|
||||
walk_state->opcode));
|
||||
status = AE_AML_BAD_OPCODE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
walk_state->result_obj = return_desc;
|
||||
|
||||
cleanup:
|
||||
|
||||
/* Delete return object on error */
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_ut_remove_reference(return_desc);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
574
drivers/acpi/executer/exprep.c
Normal file
574
drivers/acpi/executer/exprep.c
Normal file
@@ -0,0 +1,574 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exprep - ACPI AML (p-code) execution - field prep utilities
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.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 %d, Bit offset %d\n",
|
||||
field_bit_length, field_bit_offset));
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||
"Byte Length %d, Byte Offset %d, End Offset %d\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 %d end is within region\n",
|
||||
access_byte_width));
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||
"Field Start %d, Field End %d -- requires %d 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 %d\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 %d 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 %d\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 %X", access));
|
||||
return_UINT32(0);
|
||||
}
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(obj_desc) == 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 */
|
||||
|
||||
obj_desc->common_field.access_byte_width = (u8)
|
||||
ACPI_DIV_8(access_bit_width); /* 1, 2, 4, 8 */
|
||||
|
||||
obj_desc->common_field.access_bit_width = (u8) 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));
|
||||
|
||||
/*
|
||||
* Does the entire field fit within a single field access element? (datum)
|
||||
* (i.e., without crossing a datum boundary)
|
||||
*/
|
||||
if ((obj_desc->common_field.start_field_bit_offset +
|
||||
field_bit_length) <= (u16) access_bit_width) {
|
||||
obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_prep_field_value
|
||||
*
|
||||
* PARAMETERS: Info - Contains all field creation info
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Construct an union acpi_operand_object of type 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;
|
||||
u32 type;
|
||||
acpi_status status;
|
||||
|
||||
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 %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);
|
||||
|
||||
/* 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));
|
||||
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);
|
||||
}
|
||||
495
drivers/acpi/executer/exregion.c
Normal file
495
drivers/acpi/executer/exregion.c
Normal file
@@ -0,0 +1,495 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exregion - ACPI default op_region (address space) handlers
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/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,
|
||||
acpi_integer * 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 window_size;
|
||||
#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 %d",
|
||||
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((acpi_integer) 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) ||
|
||||
(((acpi_integer) address + length) > ((acpi_integer)
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't attempt to map memory beyond the end of the region, and
|
||||
* constrain the maximum mapping size to something reasonable.
|
||||
*/
|
||||
window_size = (acpi_size)
|
||||
((mem_info->address + mem_info->length) - address);
|
||||
|
||||
if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) {
|
||||
window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE;
|
||||
}
|
||||
|
||||
/* Create a new mapping starting at the address given */
|
||||
|
||||
mem_info->mapped_logical_address =
|
||||
acpi_os_map_memory((acpi_native_uint) address, window_size);
|
||||
if (!mem_info->mapped_logical_address) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Could not map memory at %8.8X%8.8X, size %X",
|
||||
ACPI_FORMAT_UINT64(address),
|
||||
(u32) window_size));
|
||||
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 = window_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a logical pointer corresponding to the address we want to
|
||||
* access
|
||||
*/
|
||||
logical_addr_ptr = mem_info->mapped_logical_address +
|
||||
((acpi_integer) address -
|
||||
(acpi_integer) mem_info->mapped_physical_address);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"System-Memory (width %d) R/W %d 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 = (acpi_integer) ACPI_GET8(logical_addr_ptr);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
*value = (acpi_integer) ACPI_GET16(logical_addr_ptr);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
*value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
|
||||
break;
|
||||
|
||||
case 64:
|
||||
*value = (acpi_integer) 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) = (u8) * value;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
ACPI_SET16(logical_addr_ptr) = (u16) * value;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
ACPI_SET32(logical_addr_ptr) = (u32) * value;
|
||||
break;
|
||||
|
||||
case 64:
|
||||
ACPI_SET64(logical_addr_ptr) = (u64) * 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,
|
||||
acpi_integer * 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 %d) R/W %d Address=%8.8X%8.8X\n",
|
||||
bit_width, function, ACPI_FORMAT_UINT64(address)));
|
||||
|
||||
/* Decode the function parameter */
|
||||
|
||||
switch (function) {
|
||||
case ACPI_READ:
|
||||
|
||||
status = acpi_os_read_port((acpi_io_address) address,
|
||||
&value32, bit_width);
|
||||
*value = value32;
|
||||
break;
|
||||
|
||||
case ACPI_WRITE:
|
||||
|
||||
status = acpi_os_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,
|
||||
acpi_integer * 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 %d (%d) 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,
|
||||
acpi_integer * 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,
|
||||
acpi_integer * 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,
|
||||
acpi_integer * value,
|
||||
void *handler_context, void *region_context)
|
||||
{
|
||||
ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
|
||||
|
||||
/* Perform the memory read or write */
|
||||
|
||||
switch (function) {
|
||||
case ACPI_READ:
|
||||
|
||||
ACPI_MEMCPY(ACPI_CAST_PTR(char, value),
|
||||
ACPI_PHYSADDR_TO_PTR(address),
|
||||
ACPI_DIV_8(bit_width));
|
||||
break;
|
||||
|
||||
case ACPI_WRITE:
|
||||
default:
|
||||
|
||||
return_ACPI_STATUS(AE_SUPPORT);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
281
drivers/acpi/executer/exresnte.c
Normal file
281
drivers/acpi/executer/exresnte.c
Normal file
@@ -0,0 +1,281 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exresnte - AML Interpreter object resolution
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/amlcode.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
|
||||
*/
|
||||
if ((entry_type == ACPI_TYPE_DEVICE) ||
|
||||
(entry_type == ACPI_TYPE_THERMAL) ||
|
||||
(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 %p", node));
|
||||
return_ACPI_STATUS(AE_AML_NO_OPERAND);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (ACPI_GET_OBJECT_TYPE(source_desc) != 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 (ACPI_GET_OBJECT_TYPE(source_desc) != 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 (ACPI_GET_OBJECT_TYPE(source_desc) != 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 (ACPI_GET_OBJECT_TYPE(source_desc) != 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_METHOD:
|
||||
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.opcode) {
|
||||
case AML_LOAD_OP:
|
||||
|
||||
/* This is a ddb_handle */
|
||||
/* Return an additional reference to the object */
|
||||
|
||||
case AML_REF_OF_OP:
|
||||
|
||||
obj_desc = source_desc;
|
||||
acpi_ut_add_reference(obj_desc);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* No named references are allowed here */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unsupported Reference opcode %X (%s)",
|
||||
source_desc->reference.opcode,
|
||||
acpi_ps_get_opcode_name(source_desc->
|
||||
reference.opcode)));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Default case is for unknown types */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Node %p - Unknown object type %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);
|
||||
}
|
||||
555
drivers/acpi/executer/exresolv.c
Normal file
555
drivers/acpi/executer/exresolv.c
Normal file
@@ -0,0 +1,555 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exresolv - AML Interpreter object resolution
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/amlcode.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.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;
|
||||
void *temp_node;
|
||||
union acpi_operand_object *obj_desc = NULL;
|
||||
u16 opcode;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
|
||||
|
||||
stack_desc = *stack_ptr;
|
||||
|
||||
/* This is an union acpi_operand_object */
|
||||
|
||||
switch (ACPI_GET_OBJECT_TYPE(stack_desc)) {
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
opcode = stack_desc->reference.opcode;
|
||||
|
||||
switch (opcode) {
|
||||
case AML_NAME_OP:
|
||||
|
||||
/*
|
||||
* Convert name reference to a namespace node
|
||||
* Then, acpi_ex_resolve_node_to_value can be used to get the value
|
||||
*/
|
||||
temp_node = stack_desc->reference.object;
|
||||
|
||||
/* Delete the Reference Object */
|
||||
|
||||
acpi_ut_remove_reference(stack_desc);
|
||||
|
||||
/* Return the namespace node */
|
||||
|
||||
(*stack_ptr) = temp_node;
|
||||
break;
|
||||
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
|
||||
/*
|
||||
* 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(opcode,
|
||||
stack_desc->
|
||||
reference.offset,
|
||||
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.offset,
|
||||
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 AML_INDEX_OP:
|
||||
|
||||
switch (stack_desc->reference.target_type) {
|
||||
case ACPI_TYPE_BUFFER_FIELD:
|
||||
|
||||
/* Just return - leave the Reference on the stack */
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
|
||||
obj_desc = *stack_desc->reference.where;
|
||||
if (obj_desc) {
|
||||
/*
|
||||
* Valid obj descriptor, copy pointer to return value
|
||||
* (i.e., dereference the package index)
|
||||
* Delete the ref object, increment the returned object
|
||||
*/
|
||||
acpi_ut_remove_reference(stack_desc);
|
||||
acpi_ut_add_reference(obj_desc);
|
||||
*stack_ptr = obj_desc;
|
||||
} else {
|
||||
/*
|
||||
* A NULL object descriptor means an unitialized element of
|
||||
* the package, can't dereference it
|
||||
*/
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Attempt to deref an Index to NULL pkg element Idx=%p",
|
||||
stack_desc));
|
||||
status = AE_AML_UNINITIALIZED_ELEMENT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Invalid reference object */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unknown TargetType %X in Index/Reference obj %p",
|
||||
stack_desc->reference.target_type,
|
||||
stack_desc));
|
||||
status = AE_AML_INTERNAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_REF_OF_OP:
|
||||
case AML_DEBUG_OP:
|
||||
case AML_LOAD_OP:
|
||||
|
||||
/* Just leave the object as-is */
|
||||
|
||||
break;
|
||||
|
||||
case AML_INT_NAMEPATH_OP: /* 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 opcode %X (%s) in %p",
|
||||
opcode, acpi_ps_get_opcode_name(opcode),
|
||||
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,
|
||||
ACPI_GET_OBJECT_TYPE(stack_desc)));
|
||||
|
||||
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 = (void *)operand;
|
||||
struct acpi_namespace_node *node;
|
||||
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((struct acpi_namespace_node *)
|
||||
obj_desc);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
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 or Index 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 (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_REF_OF_OP:
|
||||
case AML_INT_NAMEPATH_OP:
|
||||
|
||||
/* Dereference the reference pointer */
|
||||
|
||||
if (obj_desc->reference.opcode == AML_REF_OF_OP) {
|
||||
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 NS 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 AML_INDEX_OP:
|
||||
|
||||
/* 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 AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
|
||||
if (return_desc) {
|
||||
status =
|
||||
acpi_ds_method_data_get_value(obj_desc->
|
||||
reference.
|
||||
opcode,
|
||||
obj_desc->
|
||||
reference.
|
||||
offset,
|
||||
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.
|
||||
opcode,
|
||||
obj_desc->
|
||||
reference.
|
||||
offset,
|
||||
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 AML_DEBUG_OP:
|
||||
|
||||
/* The Debug Object is of type "DebugObject" */
|
||||
|
||||
type = ACPI_TYPE_DEBUG_OBJECT;
|
||||
goto exit;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unknown Reference subtype %X",
|
||||
obj_desc->reference.opcode));
|
||||
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 = ACPI_GET_OBJECT_TYPE(obj_desc);
|
||||
|
||||
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);
|
||||
}
|
||||
714
drivers/acpi/executer/exresop.c
Normal file
714
drivers/acpi/executer/exresop.c
Normal file
@@ -0,0 +1,714 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exresop - AML Interpreter operand/object resolution
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/amlcode.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/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;
|
||||
void *temp_node;
|
||||
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 %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 = ACPI_GET_OBJECT_TYPE(obj_desc);
|
||||
|
||||
/* Check for bad acpi_object_type */
|
||||
|
||||
if (!acpi_ut_valid_object_type(object_type)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Bad operand object type [%X]",
|
||||
object_type));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
|
||||
/* Decode the Reference */
|
||||
|
||||
op_info = acpi_ps_get_opcode_info(opcode);
|
||||
if (op_info->class == AML_CLASS_UNKNOWN) {
|
||||
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
|
||||
}
|
||||
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_DEBUG_OP:
|
||||
target_op = AML_DEBUG_OP;
|
||||
|
||||
/*lint -fallthrough */
|
||||
|
||||
case AML_NAME_OP:
|
||||
case AML_INDEX_OP:
|
||||
case AML_REF_OF_OP:
|
||||
case AML_ARG_OP:
|
||||
case AML_LOCAL_OP:
|
||||
case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
|
||||
case AML_INT_NAMEPATH_OP: /* Reference to a named object */
|
||||
|
||||
ACPI_DEBUG_ONLY_MEMBERS(ACPI_DEBUG_PRINT
|
||||
((ACPI_DB_EXEC,
|
||||
"Operand is a Reference, RefOpcode [%s]\n",
|
||||
(acpi_ps_get_opcode_info
|
||||
(obj_desc->
|
||||
reference.
|
||||
opcode))->
|
||||
name)));
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Operand is a Reference, Unknown Reference Opcode: %X",
|
||||
obj_desc->reference.
|
||||
opcode));
|
||||
|
||||
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)
|
||||
&& (ACPI_GET_OBJECT_TYPE(obj_desc) ==
|
||||
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 */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
if (obj_desc->reference.opcode == AML_NAME_OP) {
|
||||
|
||||
/* Convert a named reference to the actual named object */
|
||||
|
||||
temp_node = obj_desc->reference.object;
|
||||
acpi_ut_remove_reference(obj_desc);
|
||||
(*stack_ptr) = temp_node;
|
||||
}
|
||||
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) &&
|
||||
(ACPI_GET_OBJECT_TYPE(*stack_ptr) ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& ((*stack_ptr)->reference.opcode ==
|
||||
AML_INDEX_OP)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
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 %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,
|
||||
ACPI_GET_OBJECT_TYPE
|
||||
(*stack_ptr), *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--;
|
||||
}
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
651
drivers/acpi/executer/exstore.c
Normal file
651
drivers/acpi/executer/exstore.c
Normal file
@@ -0,0 +1,651 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exstore - AML Interpreter object store support
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exstore")
|
||||
|
||||
/* Local prototypes */
|
||||
static void
|
||||
acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
|
||||
u32 level, u32 index);
|
||||
|
||||
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);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_do_debug_object
|
||||
*
|
||||
* PARAMETERS: source_desc - Value to be stored
|
||||
* Level - Indentation level (used for packages)
|
||||
* Index - Current package element, zero if not pkg
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Handles stores to the Debug Object.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
|
||||
u32 level, u32 index)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc);
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
|
||||
level, " "));
|
||||
|
||||
/* Display index for package output only */
|
||||
|
||||
if (index > 0) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
"(%.2u) ", index - 1));
|
||||
}
|
||||
|
||||
if (!source_desc) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "<Null Object>\n"));
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s: ",
|
||||
acpi_ut_get_object_type_name
|
||||
(source_desc)));
|
||||
|
||||
if (!acpi_ut_valid_internal_object(source_desc)) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
"%p, Invalid Internal Object!\n",
|
||||
source_desc));
|
||||
return_VOID;
|
||||
}
|
||||
} else if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) ==
|
||||
ACPI_DESC_TYPE_NAMED) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s: %p\n",
|
||||
acpi_ut_get_type_name(((struct
|
||||
acpi_namespace_node
|
||||
*)source_desc)->
|
||||
type),
|
||||
source_desc));
|
||||
return_VOID;
|
||||
} else {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
switch (ACPI_GET_OBJECT_TYPE(source_desc)) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
|
||||
/* Output correct integer width */
|
||||
|
||||
if (acpi_gbl_integer_byte_width == 4) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n",
|
||||
(u32) source_desc->integer.
|
||||
value));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
"0x%8.8X%8.8X\n",
|
||||
ACPI_FORMAT_UINT64(source_desc->
|
||||
integer.
|
||||
value)));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]\n",
|
||||
(u32) source_desc->buffer.length));
|
||||
ACPI_DUMP_BUFFER(source_desc->buffer.pointer,
|
||||
(source_desc->buffer.length <
|
||||
32) ? source_desc->buffer.length : 32);
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_STRING:
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n",
|
||||
source_desc->string.length,
|
||||
source_desc->string.pointer));
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
"[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:
|
||||
|
||||
if (source_desc->reference.opcode == AML_INDEX_OP) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
"[%s, 0x%X]\n",
|
||||
acpi_ps_get_opcode_name
|
||||
(source_desc->reference.opcode),
|
||||
source_desc->reference.offset));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]\n",
|
||||
acpi_ps_get_opcode_name
|
||||
(source_desc->reference.opcode)));
|
||||
}
|
||||
|
||||
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 {
|
||||
acpi_ex_do_debug_object(source_desc->reference.
|
||||
object, level + 4, 0);
|
||||
}
|
||||
} else if (source_desc->reference.node) {
|
||||
acpi_ex_do_debug_object((source_desc->reference.node)->
|
||||
object, level + 4, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p %s\n",
|
||||
source_desc,
|
||||
acpi_ut_get_object_type_name
|
||||
(source_desc)));
|
||||
break;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "\n"));
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_store
|
||||
*
|
||||
* PARAMETERS: *source_desc - Value to be stored
|
||||
* *dest_desc - Where to store it. Must be an NS node
|
||||
* or an 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 (ACPI_GET_OBJECT_TYPE(dest_desc)) {
|
||||
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));
|
||||
|
||||
ACPI_DUMP_STACK_ENTRY(source_desc);
|
||||
ACPI_DUMP_STACK_ENTRY(dest_desc);
|
||||
ACPI_DUMP_OPERANDS(&dest_desc, ACPI_IMODE_EXECUTE, "ExStore",
|
||||
2,
|
||||
"Target is not a Reference or Constant object");
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine the Reference opcode. 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.opcode) {
|
||||
case AML_NAME_OP:
|
||||
case AML_REF_OF_OP:
|
||||
|
||||
/* 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 AML_INDEX_OP:
|
||||
|
||||
/* 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 AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
|
||||
/* Store to a method local/arg */
|
||||
|
||||
status =
|
||||
acpi_ds_store_object_to_local(ref_desc->reference.opcode,
|
||||
ref_desc->reference.offset,
|
||||
source_desc, walk_state);
|
||||
break;
|
||||
|
||||
case AML_DEBUG_OP:
|
||||
|
||||
/*
|
||||
* 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_ex_do_debug_object(source_desc, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X",
|
||||
ref_desc->reference.opcode));
|
||||
ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_ERROR);
|
||||
|
||||
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);
|
||||
|
||||
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 ((ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_BUFFER) &&
|
||||
(ACPI_GET_OBJECT_TYPE(obj_desc) != 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 (ACPI_GET_OBJECT_TYPE(source_desc)) {
|
||||
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 Integer/Buffer/String type, not %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.offset] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField"));
|
||||
status = AE_AML_OPERAND_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.
|
||||
*
|
||||
* 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) into node %p(%s)\n",
|
||||
source_desc,
|
||||
acpi_ut_get_object_type_name(source_desc), node,
|
||||
acpi_ut_get_type_name(target_type)));
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* If no implicit conversion, drop into the default case below */
|
||||
|
||||
if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {
|
||||
|
||||
/* Force execution of default (no implicit conversion) */
|
||||
|
||||
target_type = ACPI_TYPE_ANY;
|
||||
}
|
||||
|
||||
/* Do the actual store operation */
|
||||
|
||||
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:
|
||||
|
||||
/* For fields, copy the source data to the target field. */
|
||||
|
||||
status = acpi_ex_write_data_to_field(source_desc, target_desc,
|
||||
&walk_state->result_obj);
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_INTEGER:
|
||||
case ACPI_TYPE_STRING:
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/*
|
||||
* These target types are all of type Integer/String/Buffer, and
|
||||
* therefore support implicit conversion before the store.
|
||||
*
|
||||
* Copy and/or convert the source object to a new target object
|
||||
*/
|
||||
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 %s into %s via Convert/Attach\n",
|
||||
acpi_ut_get_object_type_name
|
||||
(source_desc),
|
||||
acpi_ut_get_object_type_name
|
||||
(new_desc)));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Storing %s (%p) directly into node (%p) with no implicit conversion\n",
|
||||
acpi_ut_get_object_type_name(source_desc),
|
||||
source_desc, node));
|
||||
|
||||
/* No conversions for all other types. Just attach the source object */
|
||||
|
||||
status = acpi_ns_attach_object(node, source_desc,
|
||||
ACPI_GET_OBJECT_TYPE
|
||||
(source_desc));
|
||||
break;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
302
drivers/acpi/executer/exstoren.c
Normal file
302
drivers/acpi/executer/exstoren.c
Normal file
@@ -0,0 +1,302 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exstoren - AML Interpreter object store support,
|
||||
* Store to Node (namespace object)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/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 (ACPI_GET_OBJECT_TYPE(source_desc) ==
|
||||
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 ((ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_INTEGER) &&
|
||||
(ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_BUFFER) &&
|
||||
(ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_STRING) &&
|
||||
!((ACPI_GET_OBJECT_TYPE(source_desc) ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& (source_desc->reference.opcode == AML_LOAD_OP))) {
|
||||
|
||||
/* 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 (ACPI_GET_OBJECT_TYPE(source_desc) !=
|
||||
ACPI_GET_OBJECT_TYPE(dest_desc)) {
|
||||
/*
|
||||
* 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(ACPI_GET_OBJECT_TYPE
|
||||
(dest_desc), 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 (ACPI_GET_OBJECT_TYPE(dest_desc)) {
|
||||
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 */
|
||||
|
||||
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);
|
||||
}
|
||||
208
drivers/acpi/executer/exstorob.c
Normal file
208
drivers/acpi/executer/exstorob.c
Normal file
@@ -0,0 +1,208 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exstorob - AML Interpreter object store support, store to object
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/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);
|
||||
|
||||
/* 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 */
|
||||
|
||||
ACPI_MEMSET(target_desc->buffer.pointer, 0,
|
||||
target_desc->buffer.length);
|
||||
ACPI_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.0_a 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 */
|
||||
|
||||
ACPI_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);
|
||||
|
||||
/* 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
|
||||
*/
|
||||
ACPI_MEMSET(target_desc->string.pointer, 0,
|
||||
(acpi_size) target_desc->string.length + 1);
|
||||
ACPI_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;
|
||||
ACPI_MEMCPY(target_desc->string.pointer, buffer, length);
|
||||
}
|
||||
|
||||
/* Set the new target length */
|
||||
|
||||
target_desc->string.length = length;
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
319
drivers/acpi/executer/exsystem.c
Normal file
319
drivers/acpi/executer/exsystem.c
Normal file
@@ -0,0 +1,319 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exsystem - Interface to OS services
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/acevents.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_status status2;
|
||||
|
||||
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 */
|
||||
|
||||
status2 = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status2)) {
|
||||
|
||||
/* Report fatal error, could not acquire interpreter */
|
||||
|
||||
return_ACPI_STATUS(status2);
|
||||
}
|
||||
}
|
||||
|
||||
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_status status2;
|
||||
|
||||
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 */
|
||||
|
||||
status2 = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status2)) {
|
||||
|
||||
/* Report fatal error, could not acquire interpreter */
|
||||
|
||||
return_ACPI_STATUS(status2);
|
||||
}
|
||||
}
|
||||
|
||||
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 (%d)",
|
||||
how_long));
|
||||
status = AE_AML_OPERAND_VALUE;
|
||||
} else {
|
||||
acpi_os_stall(how_long);
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_system_do_suspend
|
||||
*
|
||||
* PARAMETERS: how_long - The amount of time to suspend,
|
||||
* in milliseconds
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Suspend running thread for specified amount of time.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/* Since this thread will sleep, we must release the interpreter */
|
||||
|
||||
acpi_ex_exit_interpreter();
|
||||
|
||||
acpi_os_sleep(how_long);
|
||||
|
||||
/* And now we must get the interpreter again */
|
||||
|
||||
status = acpi_ex_enter_interpreter();
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
355
drivers/acpi/executer/exutils.c
Normal file
355
drivers/acpi/executer/exutils.c
Normal file
@@ -0,0 +1,355 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: exutils - interpreter/scanner utilities
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acevents.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exutils")
|
||||
|
||||
/* Local prototypes */
|
||||
static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
|
||||
|
||||
#ifndef ACPI_NO_METHOD_EXECUTION
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_enter_interpreter
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Enter the interpreter execution region. Failure to enter
|
||||
* the interpreter region is a fatal system error
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status 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 interpreter mutex"));
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_exit_interpreter
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Exit the interpreter execution region
|
||||
*
|
||||
* Cases where the interpreter is unlocked:
|
||||
* 1) Completion of the execution of a control method
|
||||
* 2) Method blocked on a Sleep() AML opcode
|
||||
* 3) Method blocked on an Acquire() AML opcode
|
||||
* 4) Method blocked on a Wait() AML opcode
|
||||
* 5) Method blocked to acquire the global lock
|
||||
* 6) Method blocked to execute a serialized control method that is
|
||||
* already executing
|
||||
* 7) 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 interpreter mutex"));
|
||||
}
|
||||
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_truncate_for32bit_table
|
||||
*
|
||||
* PARAMETERS: obj_desc - Object to be truncated
|
||||
*
|
||||
* RETURN: none
|
||||
*
|
||||
* DESCRIPTION: Truncate a number to 32-bits if the currently executing method
|
||||
* belongs to a 32-bit ACPI table.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void 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
|
||||
*/
|
||||
if ((!obj_desc) ||
|
||||
(ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (acpi_gbl_integer_byte_width == 4) {
|
||||
/*
|
||||
* We are running a method that exists in a 32-bit ACPI table.
|
||||
* Truncate the value to 32 bits by zeroing out the upper 32-bit field
|
||||
*/
|
||||
obj_desc->integer.value &= (acpi_integer) ACPI_UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_acquire_global_lock
|
||||
*
|
||||
* PARAMETERS: field_flags - Flags with Lock rule:
|
||||
* always_lock or never_lock
|
||||
*
|
||||
* RETURN: TRUE/FALSE indicating whether the lock was actually acquired
|
||||
*
|
||||
* DESCRIPTION: Obtain the global lock and keep track of this fact via two
|
||||
* methods. A global variable keeps the state of the lock, and
|
||||
* the state is returned to the caller.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
u8 acpi_ex_acquire_global_lock(u32 field_flags)
|
||||
{
|
||||
u8 locked = FALSE;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_acquire_global_lock);
|
||||
|
||||
/* Only attempt lock if the always_lock bit is set */
|
||||
|
||||
if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
|
||||
|
||||
/* We should attempt to get the lock, wait forever */
|
||||
|
||||
status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
locked = TRUE;
|
||||
} else {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Could not acquire Global Lock"));
|
||||
}
|
||||
}
|
||||
|
||||
return_UINT8(locked);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_release_global_lock
|
||||
*
|
||||
* PARAMETERS: locked_by_me - Return value from corresponding call to
|
||||
* acquire_global_lock.
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Release the global lock if it is locked.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ex_release_global_lock(u8 locked_by_me)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_release_global_lock);
|
||||
|
||||
/* Only attempt unlock if the caller locked it */
|
||||
|
||||
if (locked_by_me) {
|
||||
|
||||
/* OK, now release the lock */
|
||||
|
||||
status = acpi_ev_release_global_lock();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
||||
/* Report the error, but there isn't much else we can do */
|
||||
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Could not release ACPI 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(acpi_integer value, u32 base)
|
||||
{
|
||||
u32 num_digits;
|
||||
acpi_integer current_value;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_digits_needed);
|
||||
|
||||
/* acpi_integer 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: numeric_id - EISA ID to be converted
|
||||
* out_string - Where to put the converted string (8 bytes)
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Convert a numeric EISA ID to string representation
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string)
|
||||
{
|
||||
u32 eisa_id;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/* Swap ID to big-endian to get contiguous bits */
|
||||
|
||||
eisa_id = acpi_ut_dword_byte_swap(numeric_id);
|
||||
|
||||
out_string[0] = (char)('@' + (((unsigned long)eisa_id >> 26) & 0x1f));
|
||||
out_string[1] = (char)('@' + ((eisa_id >> 21) & 0x1f));
|
||||
out_string[2] = (char)('@' + ((eisa_id >> 16) & 0x1f));
|
||||
out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 12);
|
||||
out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 8);
|
||||
out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 4);
|
||||
out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 0);
|
||||
out_string[7] = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_unsigned_integer_to_string
|
||||
*
|
||||
* PARAMETERS: Value - Value to be converted
|
||||
* out_string - Where to put the converted string (8 bytes)
|
||||
*
|
||||
* RETURN: None, string
|
||||
*
|
||||
* DESCRIPTION: Convert a number to string representation. Assumes string
|
||||
* buffer is large enough to hold the string.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
301
drivers/acpi/fan.c
Normal file
301
drivers/acpi/fan.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* acpi_fan.c - ACPI Fan Driver ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||
* 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.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#define ACPI_FAN_COMPONENT 0x00200000
|
||||
#define ACPI_FAN_CLASS "fan"
|
||||
#define ACPI_FAN_FILE_STATE "state"
|
||||
|
||||
#define _COMPONENT ACPI_FAN_COMPONENT
|
||||
ACPI_MODULE_NAME("fan");
|
||||
|
||||
MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_DESCRIPTION("ACPI Fan Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int acpi_fan_add(struct acpi_device *device);
|
||||
static int acpi_fan_remove(struct acpi_device *device, int type);
|
||||
static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
|
||||
static int acpi_fan_resume(struct acpi_device *device);
|
||||
|
||||
static struct acpi_driver acpi_fan_driver = {
|
||||
.name = "fan",
|
||||
.class = ACPI_FAN_CLASS,
|
||||
.ids = "PNP0C0B",
|
||||
.ops = {
|
||||
.add = acpi_fan_add,
|
||||
.remove = acpi_fan_remove,
|
||||
.suspend = acpi_fan_suspend,
|
||||
.resume = acpi_fan_resume,
|
||||
},
|
||||
};
|
||||
|
||||
struct acpi_fan {
|
||||
struct acpi_device * device;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static struct proc_dir_entry *acpi_fan_dir;
|
||||
|
||||
static int acpi_fan_read_state(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_fan *fan = seq->private;
|
||||
int state = 0;
|
||||
|
||||
|
||||
if (fan) {
|
||||
if (acpi_bus_get_power(fan->device->handle, &state))
|
||||
seq_printf(seq, "status: ERROR\n");
|
||||
else
|
||||
seq_printf(seq, "status: %s\n",
|
||||
!state ? "on" : "off");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, acpi_fan_read_state, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
acpi_fan_write_state(struct file *file, const char __user * buffer,
|
||||
size_t count, loff_t * ppos)
|
||||
{
|
||||
int result = 0;
|
||||
struct seq_file *m = file->private_data;
|
||||
struct acpi_fan *fan = m->private;
|
||||
char state_string[12] = { '\0' };
|
||||
|
||||
|
||||
if (!fan || (count > sizeof(state_string) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(state_string, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
state_string[count] = '\0';
|
||||
|
||||
result = acpi_bus_set_power(fan->device->handle,
|
||||
simple_strtoul(state_string, NULL, 0));
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations acpi_fan_state_ops = {
|
||||
.open = acpi_fan_state_open_fs,
|
||||
.read = seq_read,
|
||||
.write = acpi_fan_write_state,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int acpi_fan_add_fs(struct acpi_device *device)
|
||||
{
|
||||
struct proc_dir_entry *entry = NULL;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
if (!acpi_device_dir(device)) {
|
||||
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
|
||||
acpi_fan_dir);
|
||||
if (!acpi_device_dir(device))
|
||||
return -ENODEV;
|
||||
acpi_device_dir(device)->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
/* 'status' [R/W] */
|
||||
entry = create_proc_entry(ACPI_FAN_FILE_STATE,
|
||||
S_IFREG | S_IRUGO | S_IWUSR,
|
||||
acpi_device_dir(device));
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
else {
|
||||
entry->proc_fops = &acpi_fan_state_ops;
|
||||
entry->data = acpi_driver_data(device);
|
||||
entry->owner = THIS_MODULE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_fan_remove_fs(struct acpi_device *device)
|
||||
{
|
||||
|
||||
if (acpi_device_dir(device)) {
|
||||
remove_proc_entry(ACPI_FAN_FILE_STATE, acpi_device_dir(device));
|
||||
remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
|
||||
acpi_device_dir(device) = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Driver Interface
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static int acpi_fan_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_fan *fan = NULL;
|
||||
int state = 0;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL);
|
||||
if (!fan)
|
||||
return -ENOMEM;
|
||||
|
||||
fan->device = device;
|
||||
strcpy(acpi_device_name(device), "Fan");
|
||||
strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
|
||||
acpi_driver_data(device) = fan;
|
||||
|
||||
result = acpi_bus_get_power(device->handle, &state);
|
||||
if (result) {
|
||||
printk(KERN_ERR PREFIX "Reading power state\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
device->flags.force_power_state = 1;
|
||||
acpi_bus_set_power(device->handle, state);
|
||||
device->flags.force_power_state = 0;
|
||||
|
||||
result = acpi_fan_add_fs(device);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
|
||||
acpi_device_name(device), acpi_device_bid(device),
|
||||
!device->power.state ? "on" : "off");
|
||||
|
||||
end:
|
||||
if (result)
|
||||
kfree(fan);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_fan_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct acpi_fan *fan = NULL;
|
||||
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
fan = acpi_driver_data(device);
|
||||
|
||||
acpi_fan_remove_fs(device);
|
||||
|
||||
kfree(fan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
|
||||
{
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
acpi_bus_set_power(device->handle, ACPI_STATE_D0);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int acpi_fan_resume(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
int power_state = 0;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
result = acpi_bus_get_power(device->handle, &power_state);
|
||||
if (result) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error reading fan power state\n"));
|
||||
return result;
|
||||
}
|
||||
|
||||
device->flags.force_power_state = 1;
|
||||
acpi_bus_set_power(device->handle, power_state);
|
||||
device->flags.force_power_state = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int __init acpi_fan_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
|
||||
acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
|
||||
if (!acpi_fan_dir)
|
||||
return -ENODEV;
|
||||
acpi_fan_dir->owner = THIS_MODULE;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_fan_driver);
|
||||
if (result < 0) {
|
||||
remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_fan_exit(void)
|
||||
{
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_fan_driver);
|
||||
|
||||
remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acpi_fan_init);
|
||||
module_exit(acpi_fan_exit);
|
||||
305
drivers/acpi/glue.c
Normal file
305
drivers/acpi/glue.c
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Link physical devices with ACPI devices support
|
||||
*
|
||||
* Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
|
||||
* Copyright (c) 2005 Intel Corp.
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define ACPI_GLUE_DEBUG 0
|
||||
#if ACPI_GLUE_DEBUG
|
||||
#define DBG(x...) printk(PREFIX x)
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#endif
|
||||
static LIST_HEAD(bus_type_list);
|
||||
static DECLARE_RWSEM(bus_type_sem);
|
||||
|
||||
int register_acpi_bus_type(struct acpi_bus_type *type)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
if (type && type->bus && type->find_device) {
|
||||
down_write(&bus_type_sem);
|
||||
list_add_tail(&type->list, &bus_type_list);
|
||||
up_write(&bus_type_sem);
|
||||
printk(KERN_INFO PREFIX "bus type %s registered\n",
|
||||
type->bus->name);
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(register_acpi_bus_type);
|
||||
|
||||
int unregister_acpi_bus_type(struct acpi_bus_type *type)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
if (type) {
|
||||
down_write(&bus_type_sem);
|
||||
list_del_init(&type->list);
|
||||
up_write(&bus_type_sem);
|
||||
printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n",
|
||||
type->bus->name);
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(unregister_acpi_bus_type);
|
||||
|
||||
static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
|
||||
{
|
||||
struct acpi_bus_type *tmp, *ret = NULL;
|
||||
|
||||
down_read(&bus_type_sem);
|
||||
list_for_each_entry(tmp, &bus_type_list, list) {
|
||||
if (tmp->bus == type) {
|
||||
ret = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_read(&bus_type_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
|
||||
{
|
||||
struct acpi_bus_type *tmp;
|
||||
int ret = -ENODEV;
|
||||
|
||||
down_read(&bus_type_sem);
|
||||
list_for_each_entry(tmp, &bus_type_list, list) {
|
||||
if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_read(&bus_type_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get device's handler per its address under its parent */
|
||||
struct acpi_find_child {
|
||||
acpi_handle handle;
|
||||
acpi_integer address;
|
||||
};
|
||||
|
||||
static acpi_status
|
||||
do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_device_info *info;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_find_child *find = context;
|
||||
|
||||
status = acpi_get_object_info(handle, &buffer);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
info = buffer.pointer;
|
||||
if (info->address == find->address)
|
||||
find->handle = handle;
|
||||
kfree(buffer.pointer);
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address)
|
||||
{
|
||||
struct acpi_find_child find = { NULL, address };
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, parent,
|
||||
1, do_acpi_find_child, &find, NULL);
|
||||
return find.handle;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_get_child);
|
||||
|
||||
/* Link ACPI devices with physical devices */
|
||||
static void acpi_glue_data_handler(acpi_handle handle,
|
||||
u32 function, void *context)
|
||||
{
|
||||
/* we provide an empty handler */
|
||||
}
|
||||
|
||||
/* Note: a success call will increase reference count by one */
|
||||
struct device *acpi_get_physical_device(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
struct device *dev;
|
||||
|
||||
status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return get_device(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_get_physical_device);
|
||||
|
||||
static int acpi_bind_one(struct device *dev, acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
if (dev->archdata.acpi_handle) {
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Drivers changed 'acpi_handle' for %s\n", dev->bus_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
get_device(dev);
|
||||
status = acpi_attach_data(handle, acpi_glue_data_handler, dev);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
put_device(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev->archdata.acpi_handle = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_unbind_one(struct device *dev)
|
||||
{
|
||||
if (!dev->archdata.acpi_handle)
|
||||
return 0;
|
||||
if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
|
||||
/* acpi_get_physical_device increase refcnt by one */
|
||||
put_device(dev);
|
||||
acpi_detach_data(dev->archdata.acpi_handle,
|
||||
acpi_glue_data_handler);
|
||||
dev->archdata.acpi_handle = NULL;
|
||||
/* acpi_bind_one increase refcnt by one */
|
||||
put_device(dev);
|
||||
} else {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_platform_notify(struct device *dev)
|
||||
{
|
||||
struct acpi_bus_type *type;
|
||||
acpi_handle handle;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!dev->bus || !dev->parent) {
|
||||
/* bridge devices genernally haven't bus or parent */
|
||||
ret = acpi_find_bridge_device(dev, &handle);
|
||||
goto end;
|
||||
}
|
||||
type = acpi_get_bus_type(dev->bus);
|
||||
if (!type) {
|
||||
DBG("No ACPI bus support for %s\n", dev->bus_id);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
if ((ret = type->find_device(dev, &handle)) != 0)
|
||||
DBG("Can't get handler for %s\n", dev->bus_id);
|
||||
end:
|
||||
if (!ret)
|
||||
acpi_bind_one(dev, handle);
|
||||
|
||||
#if ACPI_GLUE_DEBUG
|
||||
if (!ret) {
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
acpi_get_name(dev->archdata.acpi_handle,
|
||||
ACPI_FULL_PATHNAME, &buffer);
|
||||
DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer);
|
||||
kfree(buffer.pointer);
|
||||
} else
|
||||
DBG("Device %s -> No ACPI support\n", dev->bus_id);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_platform_notify_remove(struct device *dev)
|
||||
{
|
||||
acpi_unbind_one(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init init_acpi_device_notify(void)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
if (platform_notify || platform_notify_remove) {
|
||||
printk(KERN_ERR PREFIX "Can't use platform_notify\n");
|
||||
return 0;
|
||||
}
|
||||
platform_notify = acpi_platform_notify;
|
||||
platform_notify_remove = acpi_platform_notify_remove;
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(init_acpi_device_notify);
|
||||
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
|
||||
|
||||
/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
|
||||
* its device node and pass extra config data. This helps its driver use
|
||||
* capabilities that the now-obsolete mc146818 didn't have, and informs it
|
||||
* that this board's RTC is wakeup-capable (per ACPI spec).
|
||||
*/
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
static struct cmos_rtc_board_info rtc_info;
|
||||
|
||||
|
||||
/* PNP devices are registered in a subsys_initcall();
|
||||
* ACPI specifies the PNP IDs to use.
|
||||
*/
|
||||
#include <linux/pnp.h>
|
||||
|
||||
static int __init pnp_match(struct device *dev, void *data)
|
||||
{
|
||||
static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", };
|
||||
struct pnp_dev *pnp = to_pnp_dev(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ids); i++) {
|
||||
if (compare_pnp_id(pnp->id, ids[i]) != 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device *__init get_rtc_dev(void)
|
||||
{
|
||||
return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
|
||||
}
|
||||
|
||||
static int __init acpi_rtc_init(void)
|
||||
{
|
||||
struct device *dev = get_rtc_dev();
|
||||
|
||||
if (dev) {
|
||||
rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
|
||||
rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
|
||||
rtc_info.rtc_century = acpi_gbl_FADT.century;
|
||||
|
||||
/* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */
|
||||
|
||||
dev->platform_data = &rtc_info;
|
||||
|
||||
/* RTC always wakes from S1/S2/S3, and often S4/STD */
|
||||
device_init_wakeup(dev, 1);
|
||||
|
||||
put_device(dev);
|
||||
} else
|
||||
pr_debug("ACPI: RTC unavailable?\n");
|
||||
return 0;
|
||||
}
|
||||
/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
|
||||
fs_initcall(acpi_rtc_init);
|
||||
|
||||
#endif
|
||||
9
drivers/acpi/hardware/Makefile
Normal file
9
drivers/acpi/hardware/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for all Linux ACPI interpreter subdirectories
|
||||
#
|
||||
|
||||
obj-y := hwacpi.o hwgpe.o hwregs.o hwsleep.o
|
||||
|
||||
obj-$(ACPI_FUTURE_USAGE) += hwtimer.o
|
||||
|
||||
EXTRA_CFLAGS += $(ACPI_CFLAGS)
|
||||
184
drivers/acpi/hardware/hwacpi.c
Normal file
184
drivers/acpi/hardware/hwacpi.c
Normal file
@@ -0,0 +1,184 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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>
|
||||
|
||||
#define _COMPONENT ACPI_HARDWARE
|
||||
ACPI_MODULE_NAME("hwacpi")
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* 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;
|
||||
u32 retry;
|
||||
|
||||
ACPI_FUNCTION_TRACE(hw_set_mode);
|
||||
|
||||
/*
|
||||
* 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_os_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_os_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some hardware takes a LONG time to switch modes. Give them 3 sec to
|
||||
* do so, but allow faster systems to proceed more quickly.
|
||||
*/
|
||||
retry = 3000;
|
||||
while (retry) {
|
||||
if (acpi_hw_get_mode() == mode) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Mode %X successfully enabled\n",
|
||||
mode));
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
acpi_os_stall(1000);
|
||||
retry--;
|
||||
}
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Hardware did not change modes"));
|
||||
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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_get_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);
|
||||
}
|
||||
}
|
||||
431
drivers/acpi/hardware/hwgpe.c
Normal file
431
drivers/acpi/hardware/hwgpe.c
Normal file
@@ -0,0 +1,431 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: hwgpe - Low level GPE enable/disable/clear functions
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acevents.h>
|
||||
|
||||
#define _COMPONENT ACPI_HARDWARE
|
||||
ACPI_MODULE_NAME("hwgpe")
|
||||
|
||||
/* 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);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_write_gpe_enable_reg
|
||||
*
|
||||
* PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Write a GPE enable register. Note: The bit for this GPE must
|
||||
* already be cleared or set in the parent register
|
||||
* enable_for_run mask.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
|
||||
{
|
||||
struct acpi_gpe_register_info *gpe_register_info;
|
||||
acpi_status status;
|
||||
|
||||
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 the entire GPE (runtime) enable register */
|
||||
|
||||
status = acpi_hw_low_level_write(8, gpe_register_info->enable_for_run,
|
||||
&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)
|
||||
{
|
||||
acpi_status status;
|
||||
u8 register_bit;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
register_bit = (u8)
|
||||
(1 <<
|
||||
(gpe_event_info->gpe_number -
|
||||
gpe_event_info->register_info->base_gpe_number));
|
||||
|
||||
/*
|
||||
* Write a one to the appropriate bit in the status register to
|
||||
* clear this GPE.
|
||||
*/
|
||||
status = acpi_hw_low_level_write(8, register_bit,
|
||||
&gpe_event_info->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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
acpi_status
|
||||
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
|
||||
acpi_event_status * event_status)
|
||||
{
|
||||
u32 in_byte;
|
||||
u8 register_bit;
|
||||
struct acpi_gpe_register_info *gpe_register_info;
|
||||
acpi_status status;
|
||||
acpi_event_status local_event_status = 0;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
if (!event_status) {
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* 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 = (u8)
|
||||
(1 <<
|
||||
(gpe_event_info->gpe_number -
|
||||
gpe_event_info->register_info->base_gpe_number));
|
||||
|
||||
/* 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 active (status bit == 1)? */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(8, &in_byte,
|
||||
&gpe_register_info->status_address);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
if (register_bit & in_byte) {
|
||||
local_event_status |= ACPI_EVENT_FLAG_SET;
|
||||
}
|
||||
|
||||
/* Set return value */
|
||||
|
||||
(*event_status) = local_event_status;
|
||||
|
||||
unlock_and_exit:
|
||||
return (status);
|
||||
}
|
||||
#endif /* ACPI_FUTURE_USAGE */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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_low_level_write(8, 0x00,
|
||||
&gpe_block->register_info[i].
|
||||
enable_address);
|
||||
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)
|
||||
{
|
||||
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_low_level_write(8, 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)
|
||||
{
|
||||
u32 i;
|
||||
acpi_status status;
|
||||
|
||||
/* NOTE: assumes that all GPEs are currently disabled */
|
||||
|
||||
/* Examine each GPE Register within the block */
|
||||
|
||||
for (i = 0; i < gpe_block->register_count; i++) {
|
||||
if (!gpe_block->register_info[i].enable_for_run) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Enable all "runtime" GPEs in this register */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(8,
|
||||
gpe_block->register_info[i].
|
||||
enable_for_run,
|
||||
&gpe_block->register_info[i].
|
||||
enable_address);
|
||||
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)
|
||||
{
|
||||
u32 i;
|
||||
acpi_status status;
|
||||
|
||||
/* Examine each GPE Register within the block */
|
||||
|
||||
for (i = 0; i < gpe_block->register_count; i++) {
|
||||
if (!gpe_block->register_info[i].enable_for_wake) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Enable all "wake" GPEs in this register */
|
||||
|
||||
status = acpi_hw_low_level_write(8,
|
||||
gpe_block->register_info[i].
|
||||
enable_for_wake,
|
||||
&gpe_block->register_info[i].
|
||||
enable_address);
|
||||
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);
|
||||
status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
|
||||
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);
|
||||
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);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
876
drivers/acpi/hardware/hwregs.c
Normal file
876
drivers/acpi/hardware/hwregs.c
Normal file
@@ -0,0 +1,876 @@
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: hwregs - Read/write access functions for the various ACPI
|
||||
* control and status registers.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acevents.h>
|
||||
|
||||
#define _COMPONENT ACPI_HARDWARE
|
||||
ACPI_MODULE_NAME("hwregs")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_clear_acpi_status
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Clears all fixed and general purpose status bits
|
||||
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
|
||||
*
|
||||
******************************************************************************/
|
||||
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 %04X\n",
|
||||
ACPI_BITMASK_ALL_FIXED_STATUS,
|
||||
(u16) acpi_gbl_FADT.xpm1a_event_block.address));
|
||||
|
||||
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_STATUS,
|
||||
ACPI_BITMASK_ALL_FIXED_STATUS);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Clear the fixed events */
|
||||
|
||||
if (acpi_gbl_FADT.xpm1b_event_block.address) {
|
||||
status =
|
||||
acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
|
||||
&acpi_gbl_FADT.xpm1b_event_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the GPE Bits in all GPE registers in all GPE blocks */
|
||||
|
||||
status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
|
||||
|
||||
unlock_and_exit:
|
||||
acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 - ACPI status
|
||||
*
|
||||
* DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
|
||||
* state.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_evaluate_info *info;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
info->pathname =
|
||||
ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
|
||||
|
||||
/* Evaluate the namespace object containing the values for this state */
|
||||
|
||||
status = acpi_ns_evaluate(info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"%s while evaluating SleepState [%s]\n",
|
||||
acpi_format_exception(status),
|
||||
info->pathname));
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Must have a return object */
|
||||
|
||||
if (!info->return_object) {
|
||||
ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
|
||||
info->pathname));
|
||||
status = AE_NOT_EXIST;
|
||||
}
|
||||
|
||||
/* It must be of type Package */
|
||||
|
||||
else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Sleep State return object is not a Package"));
|
||||
status = AE_AML_OPERAND_TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The package must have at least two elements. NOTE (March 2005): This
|
||||
* goes against the current ACPI spec which defines this object as a
|
||||
* package with one encoded DWORD element. However, existing practice
|
||||
* by BIOS vendors seems to be to have 2 or more elements, at least
|
||||
* one per sleep type (A/B).
|
||||
*/
|
||||
else if (info->return_object->package.count < 2) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Sleep State return package does not have at least two elements"));
|
||||
status = AE_AML_NO_OPERAND;
|
||||
}
|
||||
|
||||
/* The first two elements must both be of type Integer */
|
||||
|
||||
else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0])
|
||||
!= ACPI_TYPE_INTEGER) ||
|
||||
(ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1])
|
||||
!= ACPI_TYPE_INTEGER)) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Sleep State return package elements are not both Integers (%s, %s)",
|
||||
acpi_ut_get_object_type_name(info->return_object->
|
||||
package.elements[0]),
|
||||
acpi_ut_get_object_type_name(info->return_object->
|
||||
package.elements[1])));
|
||||
status = AE_AML_OPERAND_TYPE;
|
||||
} else {
|
||||
/* Valid _Sx_ package size, type, and value */
|
||||
|
||||
*sleep_type_a = (u8)
|
||||
(info->return_object->package.elements[0])->integer.value;
|
||||
*sleep_type_b = (u8)
|
||||
(info->return_object->package.elements[1])->integer.value;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"While evaluating SleepState [%s], bad Sleep object %p type %s",
|
||||
info->pathname, info->return_object,
|
||||
acpi_ut_get_object_type_name(info->
|
||||
return_object)));
|
||||
}
|
||||
|
||||
acpi_ut_remove_reference(info->return_object);
|
||||
|
||||
cleanup:
|
||||
ACPI_FREE(info);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_get_register_bit_mask
|
||||
*
|
||||
* 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: %X",
|
||||
register_id));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (&acpi_gbl_bit_register_info[register_id]);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_get_register
|
||||
*
|
||||
* PARAMETERS: register_id - ID of ACPI bit_register to access
|
||||
* return_value - Value that was read from the register
|
||||
*
|
||||
* RETURN: Status and the value read from specified Register. Value
|
||||
* returned is normalized to bit0 (is shifted all the way right)
|
||||
*
|
||||
* DESCRIPTION: ACPI bit_register read function.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_get_register(u32 register_id, u32 * return_value)
|
||||
{
|
||||
u32 register_value = 0;
|
||||
struct acpi_bit_register_info *bit_reg_info;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_get_register);
|
||||
|
||||
/* 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 from the register */
|
||||
|
||||
status = acpi_hw_register_read(ACPI_MTX_LOCK,
|
||||
bit_reg_info->parent_register,
|
||||
®ister_value);
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
||||
/* Normalize the value that was read */
|
||||
|
||||
register_value =
|
||||
((register_value & bit_reg_info->access_bit_mask)
|
||||
>> bit_reg_info->bit_position);
|
||||
|
||||
*return_value = register_value;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read value %8.8X register %X\n",
|
||||
register_value,
|
||||
bit_reg_info->parent_register));
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_register)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_set_register
|
||||
*
|
||||
* PARAMETERS: register_id - ID of ACPI bit_register to access
|
||||
* Value - (only used on write) value to write to the
|
||||
* Register, NOT pre-normalized to the bit pos
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: ACPI Bit Register write function.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_set_register(u32 register_id, u32 value)
|
||||
{
|
||||
u32 register_value = 0;
|
||||
struct acpi_bit_register_info *bit_reg_info;
|
||||
acpi_status status;
|
||||
acpi_cpu_flags lock_flags;
|
||||
|
||||
ACPI_FUNCTION_TRACE_U32(acpi_set_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) {
|
||||
ACPI_ERROR((AE_INFO, "Bad ACPI HW RegisterId: %X",
|
||||
register_id));
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
|
||||
|
||||
/* Always do a register read first so we can insert the new bits */
|
||||
|
||||
status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
|
||||
bit_reg_info->parent_register,
|
||||
®ister_value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Register ID
|
||||
* Register ID = [Register block ID] | [bit ID]
|
||||
*
|
||||
* Check bit ID to fine locate Register offset.
|
||||
* Check Mask to determine Register offset, and then read-write.
|
||||
*/
|
||||
switch (bit_reg_info->parent_register) {
|
||||
case ACPI_REGISTER_PM1_STATUS:
|
||||
|
||||
/*
|
||||
* Status Registers are different from the rest. Clear by
|
||||
* writing 1, and 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.
|
||||
*/
|
||||
value = ACPI_REGISTER_PREPARE_BITS(value,
|
||||
bit_reg_info->bit_position,
|
||||
bit_reg_info->
|
||||
access_bit_mask);
|
||||
if (value) {
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_STATUS,
|
||||
(u16) value);
|
||||
register_value = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1_ENABLE:
|
||||
|
||||
ACPI_REGISTER_INSERT_VALUE(register_value,
|
||||
bit_reg_info->bit_position,
|
||||
bit_reg_info->access_bit_mask,
|
||||
value);
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_ENABLE,
|
||||
(u16) register_value);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1_CONTROL:
|
||||
|
||||
/*
|
||||
* Write the PM1 Control register.
|
||||
* Note that at this level, the fact that there are actually TWO
|
||||
* registers (A and B - and B may not exist) is abstracted.
|
||||
*/
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO, "PM1 control: Read %X\n",
|
||||
register_value));
|
||||
|
||||
ACPI_REGISTER_INSERT_VALUE(register_value,
|
||||
bit_reg_info->bit_position,
|
||||
bit_reg_info->access_bit_mask,
|
||||
value);
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_CONTROL,
|
||||
(u16) register_value);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM2_CONTROL:
|
||||
|
||||
status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM2_CONTROL,
|
||||
®ister_value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO,
|
||||
"PM2 control: Read %X from %8.8X%8.8X\n",
|
||||
register_value,
|
||||
ACPI_FORMAT_UINT64(acpi_gbl_FADT.
|
||||
xpm2_control_block.
|
||||
address)));
|
||||
|
||||
ACPI_REGISTER_INSERT_VALUE(register_value,
|
||||
bit_reg_info->bit_position,
|
||||
bit_reg_info->access_bit_mask,
|
||||
value);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO,
|
||||
"About to write %4.4X to %8.8X%8.8X\n",
|
||||
register_value,
|
||||
ACPI_FORMAT_UINT64(acpi_gbl_FADT.
|
||||
xpm2_control_block.
|
||||
address)));
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM2_CONTROL,
|
||||
(u8) (register_value));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
|
||||
acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
|
||||
|
||||
/* Normalize the value that was read */
|
||||
|
||||
ACPI_DEBUG_EXEC(register_value =
|
||||
((register_value & bit_reg_info->access_bit_mask) >>
|
||||
bit_reg_info->bit_position));
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO,
|
||||
"Set bits: %8.8X actual %8.8X register %X\n", value,
|
||||
register_value, bit_reg_info->parent_register));
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_set_register)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_register_read
|
||||
*
|
||||
* PARAMETERS: use_lock - Lock hardware? True/False
|
||||
* 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(u8 use_lock, u32 register_id, u32 * return_value)
|
||||
{
|
||||
u32 value1 = 0;
|
||||
u32 value2 = 0;
|
||||
acpi_status status;
|
||||
acpi_cpu_flags lock_flags = 0;
|
||||
|
||||
ACPI_FUNCTION_TRACE(hw_register_read);
|
||||
|
||||
if (ACPI_MTX_LOCK == use_lock) {
|
||||
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
|
||||
}
|
||||
|
||||
switch (register_id) {
|
||||
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(16, &value1,
|
||||
&acpi_gbl_FADT.xpm1a_event_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* PM1B is optional */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(16, &value2,
|
||||
&acpi_gbl_FADT.xpm1b_event_block);
|
||||
value1 |= value2;
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* PM1B is optional */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(16, &value2, &acpi_gbl_xpm1b_enable);
|
||||
value1 |= value2;
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(16, &value1,
|
||||
&acpi_gbl_FADT.xpm1a_control_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(16, &value2,
|
||||
&acpi_gbl_FADT.xpm1b_control_block);
|
||||
value1 |= value2;
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(8, &value1,
|
||||
&acpi_gbl_FADT.xpm2_control_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(32, &value1,
|
||||
&acpi_gbl_FADT.xpm_timer_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
|
||||
|
||||
status =
|
||||
acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id));
|
||||
status = AE_BAD_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
if (ACPI_MTX_LOCK == use_lock) {
|
||||
acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
|
||||
}
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
*return_value = value1;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_register_write
|
||||
*
|
||||
* PARAMETERS: use_lock - Lock hardware? True/False
|
||||
* 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(u8 use_lock, u32 register_id, u32 value)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_cpu_flags lock_flags = 0;
|
||||
u32 read_value;
|
||||
|
||||
ACPI_FUNCTION_TRACE(hw_register_write);
|
||||
|
||||
if (ACPI_MTX_LOCK == use_lock) {
|
||||
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
|
||||
}
|
||||
|
||||
switch (register_id) {
|
||||
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
|
||||
|
||||
/* Perform a read first to preserve certain bits (per ACPI spec) */
|
||||
|
||||
status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_STATUS,
|
||||
&read_value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* Insert the bits to be preserved */
|
||||
|
||||
ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
|
||||
read_value);
|
||||
|
||||
/* Now we can write the data */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value,
|
||||
&acpi_gbl_FADT.xpm1a_event_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* PM1B is optional */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value,
|
||||
&acpi_gbl_FADT.xpm1b_event_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
/* PM1B is optional */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1b_enable);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
|
||||
|
||||
/*
|
||||
* Perform a read first to preserve certain bits (per ACPI spec)
|
||||
*/
|
||||
status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_CONTROL,
|
||||
&read_value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_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_low_level_write(16, value,
|
||||
&acpi_gbl_FADT.xpm1a_control_block);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value,
|
||||
&acpi_gbl_FADT.xpm1b_control_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value,
|
||||
&acpi_gbl_FADT.xpm1a_control_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(16, value,
|
||||
&acpi_gbl_FADT.xpm1b_control_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(8, value,
|
||||
&acpi_gbl_FADT.xpm2_control_block);
|
||||
break;
|
||||
|
||||
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_write(32, 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_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = AE_BAD_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
if (ACPI_MTX_LOCK == use_lock) {
|
||||
acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_low_level_read
|
||||
*
|
||||
* PARAMETERS: Width - 8, 16, or 32
|
||||
* Value - Where the value is returned
|
||||
* Reg - GAS register structure
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Read from either memory or IO space.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
|
||||
{
|
||||
u64 address;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_NAME(hw_low_level_read);
|
||||
|
||||
/*
|
||||
* Must have a valid pointer to a GAS structure, and
|
||||
* a non-zero address within. However, don't return an error
|
||||
* because the PM1A/B code must not fail if B isn't present.
|
||||
*/
|
||||
if (!reg) {
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/* Get a local copy of the address. Handles possible alignment issues */
|
||||
|
||||
ACPI_MOVE_64_TO_64(&address, ®->address);
|
||||
if (!address) {
|
||||
return (AE_OK);
|
||||
}
|
||||
*value = 0;
|
||||
|
||||
/*
|
||||
* Two address spaces supported: Memory or IO.
|
||||
* PCI_Config is not supported here because the GAS struct is insufficient
|
||||
*/
|
||||
switch (reg->space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
|
||||
status = acpi_os_read_memory((acpi_physical_address) address,
|
||||
value, width);
|
||||
break;
|
||||
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
|
||||
status =
|
||||
acpi_os_read_port((acpi_io_address) address, value, width);
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unsupported address space: %X", reg->space_id));
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO,
|
||||
"Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
|
||||
*value, width, ACPI_FORMAT_UINT64(address),
|
||||
acpi_ut_get_region_name(reg->space_id)));
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_hw_low_level_write
|
||||
*
|
||||
* PARAMETERS: Width - 8, 16, or 32
|
||||
* Value - To be written
|
||||
* Reg - GAS register structure
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Write to either memory or IO space.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
|
||||
{
|
||||
u64 address;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_NAME(hw_low_level_write);
|
||||
|
||||
/*
|
||||
* Must have a valid pointer to a GAS structure, and
|
||||
* a non-zero address within. However, don't return an error
|
||||
* because the PM1A/B code must not fail if B isn't present.
|
||||
*/
|
||||
if (!reg) {
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/* Get a local copy of the address. Handles possible alignment issues */
|
||||
|
||||
ACPI_MOVE_64_TO_64(&address, ®->address);
|
||||
if (!address) {
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Two address spaces supported: Memory or IO.
|
||||
* PCI_Config is not supported here because the GAS struct is insufficient
|
||||
*/
|
||||
switch (reg->space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
|
||||
status = acpi_os_write_memory((acpi_physical_address) address,
|
||||
value, width);
|
||||
break;
|
||||
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
|
||||
status = acpi_os_write_port((acpi_io_address) address, value,
|
||||
width);
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unsupported address space: %X", reg->space_id));
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_IO,
|
||||
"Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
|
||||
value, width, ACPI_FORMAT_UINT64(address),
|
||||
acpi_ut_get_region_name(reg->space_id)));
|
||||
|
||||
return (status);
|
||||
}
|
||||
621
drivers/acpi/hardware/hwsleep.c
Normal file
621
drivers/acpi/hardware/hwsleep.c
Normal file
@@ -0,0 +1,621 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/actables.h>
|
||||
|
||||
#define _COMPONENT ACPI_HARDWARE
|
||||
ACPI_MODULE_NAME("hwsleep")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_set_firmware_waking_vector
|
||||
*
|
||||
* PARAMETERS: physical_address - Physical address of ACPI real mode
|
||||
* entry point.
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Access function for the firmware_waking_vector field in FACS
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status
|
||||
acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
|
||||
{
|
||||
struct acpi_table_facs *facs;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
|
||||
|
||||
/* Get the FACS */
|
||||
|
||||
status =
|
||||
acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
|
||||
(struct acpi_table_header **)&facs);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Set the vector */
|
||||
|
||||
if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
|
||||
/*
|
||||
* ACPI 1.0 FACS or short table or optional X_ field is zero
|
||||
*/
|
||||
facs->firmware_waking_vector = (u32) physical_address;
|
||||
} else {
|
||||
/*
|
||||
* ACPI 2.0 FACS with valid X_ field
|
||||
*/
|
||||
facs->xfirmware_waking_vector = physical_address;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_get_firmware_waking_vector
|
||||
*
|
||||
* PARAMETERS: *physical_address - Where the contents of
|
||||
* the firmware_waking_vector field of
|
||||
* the FACS will be returned.
|
||||
*
|
||||
* RETURN: Status, vector
|
||||
*
|
||||
* DESCRIPTION: Access function for the firmware_waking_vector field in FACS
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
acpi_status
|
||||
acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
|
||||
{
|
||||
struct acpi_table_facs *facs;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
|
||||
|
||||
if (!physical_address) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* Get the FACS */
|
||||
|
||||
status =
|
||||
acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
|
||||
(struct acpi_table_header **)&facs);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Get the vector */
|
||||
|
||||
if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
|
||||
/*
|
||||
* ACPI 1.0 FACS or short table or optional X_ field is zero
|
||||
*/
|
||||
*physical_address =
|
||||
(acpi_physical_address) facs->firmware_waking_vector;
|
||||
} else {
|
||||
/*
|
||||
* ACPI 2.0 FACS with valid X_ field
|
||||
*/
|
||||
*physical_address =
|
||||
(acpi_physical_address) facs->xfirmware_waking_vector;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector)
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enter_sleep_state_prep
|
||||
*
|
||||
* PARAMETERS: sleep_state - Which sleep state to enter
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
|
||||
* 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;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
|
||||
|
||||
/*
|
||||
* _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/* Setup parameter object */
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = sleep_state;
|
||||
|
||||
/* Run the _PTS and _GTS methods */
|
||||
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Setup the argument to _SST */
|
||||
|
||||
switch (sleep_state) {
|
||||
case ACPI_STATE_S0:
|
||||
arg.integer.value = ACPI_SST_WORKING;
|
||||
break;
|
||||
|
||||
case ACPI_STATE_S1:
|
||||
case ACPI_STATE_S2:
|
||||
case ACPI_STATE_S3:
|
||||
arg.integer.value = ACPI_SST_SLEEPING;
|
||||
break;
|
||||
|
||||
case ACPI_STATE_S4:
|
||||
arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
|
||||
break;
|
||||
|
||||
default:
|
||||
arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is off */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the system indicators to show the desired sleep state. */
|
||||
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"While executing method _SST"));
|
||||
}
|
||||
|
||||
/*
|
||||
* 1) Disable/Clear all GPEs
|
||||
*/
|
||||
status = acpi_hw_disable_all_gpes();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
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 (see ACPI 2.0 spec p 231)
|
||||
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
|
||||
{
|
||||
u32 PM1Acontrol;
|
||||
u32 PM1Bcontrol;
|
||||
struct acpi_bit_register_info *sleep_type_reg_info;
|
||||
struct acpi_bit_register_info *sleep_enable_reg_info;
|
||||
u32 in_value;
|
||||
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=%X B=%X",
|
||||
acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
|
||||
}
|
||||
|
||||
sleep_type_reg_info =
|
||||
acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE_A);
|
||||
sleep_enable_reg_info =
|
||||
acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
|
||||
|
||||
/* Clear wake status */
|
||||
|
||||
status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
|
||||
"Entering sleep state [S%d]\n", sleep_state));
|
||||
|
||||
/* Clear SLP_EN and SLP_TYP fields */
|
||||
|
||||
PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
|
||||
sleep_enable_reg_info->access_bit_mask);
|
||||
PM1Bcontrol = PM1Acontrol;
|
||||
|
||||
/* Insert SLP_TYP bits */
|
||||
|
||||
PM1Acontrol |=
|
||||
(acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
|
||||
PM1Bcontrol |=
|
||||
(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: fill in SLP_TYP data */
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1A_CONTROL,
|
||||
PM1Acontrol);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1B_CONTROL,
|
||||
PM1Bcontrol);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Insert SLP_ENABLE bit */
|
||||
|
||||
PM1Acontrol |= sleep_enable_reg_info->access_bit_mask;
|
||||
PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask;
|
||||
|
||||
/* Write #2: SLP_TYP + SLP_EN */
|
||||
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1A_CONTROL,
|
||||
PM1Acontrol);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1B_CONTROL,
|
||||
PM1Bcontrol);
|
||||
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(10000000);
|
||||
|
||||
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_CONTROL,
|
||||
sleep_enable_reg_info->
|
||||
access_bit_mask);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait until we enter sleep state */
|
||||
|
||||
do {
|
||||
status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Spin until we wake */
|
||||
|
||||
} while (!in_value);
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 asmlinkage acpi_enter_sleep_state_s4bios(void)
|
||||
{
|
||||
u32 in_value;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
|
||||
|
||||
status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
|
||||
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_os_write_port(acpi_gbl_FADT.smi_command,
|
||||
(u32) acpi_gbl_FADT.S4bios_request, 8);
|
||||
|
||||
do {
|
||||
acpi_os_stall(1000);
|
||||
status = acpi_get_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)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_leave_sleep_state
|
||||
*
|
||||
* 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_leave_sleep_state(u8 sleep_state)
|
||||
{
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status;
|
||||
struct acpi_bit_register_info *sleep_type_reg_info;
|
||||
struct acpi_bit_register_info *sleep_enable_reg_info;
|
||||
u32 PM1Acontrol;
|
||||
u32 PM1Bcontrol;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
|
||||
|
||||
/*
|
||||
* 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_A);
|
||||
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_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1_CONTROL,
|
||||
&PM1Acontrol);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
||||
/* Clear SLP_EN and SLP_TYP fields */
|
||||
|
||||
PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
|
||||
sleep_enable_reg_info->
|
||||
access_bit_mask);
|
||||
PM1Bcontrol = PM1Acontrol;
|
||||
|
||||
/* Insert SLP_TYP bits */
|
||||
|
||||
PM1Acontrol |=
|
||||
(acpi_gbl_sleep_type_a << sleep_type_reg_info->
|
||||
bit_position);
|
||||
PM1Bcontrol |=
|
||||
(acpi_gbl_sleep_type_b << sleep_type_reg_info->
|
||||
bit_position);
|
||||
|
||||
/* Just ignore any errors */
|
||||
|
||||
(void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1A_CONTROL,
|
||||
PM1Acontrol);
|
||||
(void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
|
||||
ACPI_REGISTER_PM1B_CONTROL,
|
||||
PM1Bcontrol);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
|
||||
|
||||
acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
|
||||
|
||||
/* Setup parameter object */
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
|
||||
/* Ignore any errors from these methods */
|
||||
|
||||
arg.integer.value = ACPI_SST_WAKING;
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
|
||||
}
|
||||
|
||||
arg.integer.value = sleep_state;
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
|
||||
}
|
||||
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
|
||||
}
|
||||
/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
acpi_gbl_system_awake_and_running = TRUE;
|
||||
|
||||
status = acpi_hw_enable_all_runtime_gpes();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Enable power button */
|
||||
|
||||
(void)
|
||||
acpi_set_register(acpi_gbl_fixed_event_info
|
||||
[ACPI_EVENT_POWER_BUTTON].enable_register_id, 1);
|
||||
|
||||
(void)
|
||||
acpi_set_register(acpi_gbl_fixed_event_info
|
||||
[ACPI_EVENT_POWER_BUTTON].status_register_id, 1);
|
||||
|
||||
arg.integer.value = ACPI_SST_WORKING;
|
||||
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)
|
||||
187
drivers/acpi/hardware/hwtimer.c
Normal file
187
drivers/acpi/hardware/hwtimer.c
Normal file
@@ -0,0 +1,187 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Name: hwtimer.c - ACPI Power Management Timer Interface
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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>
|
||||
|
||||
#define _COMPONENT ACPI_HARDWARE
|
||||
ACPI_MODULE_NAME("hwtimer")
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
status =
|
||||
acpi_hw_low_level_read(32, 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;
|
||||
acpi_integer quotient;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_get_timer_duration);
|
||||
|
||||
if (!time_elapsed) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY;
|
||||
*/
|
||||
status = acpi_ut_short_divide(((u64) delta_ticks) * 1000000,
|
||||
PM_TIMER_FREQUENCY, "ient, NULL);
|
||||
|
||||
*time_elapsed = (u32) quotient;
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_timer_duration)
|
||||
403
drivers/acpi/i2c_ec.c
Normal file
403
drivers/acpi/i2c_ec.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* SMBus driver for ACPI Embedded Controller ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* Copyright (c) 2002, 2005 Ducrot Bruno
|
||||
* Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
|
||||
*
|
||||
* 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 version 2.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "i2c_ec.h"
|
||||
|
||||
#define xudelay(t) udelay(t)
|
||||
#define xmsleep(t) msleep(t)
|
||||
|
||||
#define ACPI_EC_HC_COMPONENT 0x00080000
|
||||
#define ACPI_EC_HC_CLASS "ec_hc_smbus"
|
||||
#define ACPI_EC_HC_HID "ACPI0001"
|
||||
#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
|
||||
|
||||
#define _COMPONENT ACPI_EC_HC_COMPONENT
|
||||
|
||||
ACPI_MODULE_NAME("i2c_ec");
|
||||
|
||||
static int acpi_ec_hc_add(struct acpi_device *device);
|
||||
static int acpi_ec_hc_remove(struct acpi_device *device, int type);
|
||||
|
||||
static struct acpi_driver acpi_ec_hc_driver = {
|
||||
.name = "i2c_ec",
|
||||
.class = ACPI_EC_HC_CLASS,
|
||||
.ids = ACPI_EC_HC_HID,
|
||||
.ops = {
|
||||
.add = acpi_ec_hc_add,
|
||||
.remove = acpi_ec_hc_remove,
|
||||
},
|
||||
};
|
||||
|
||||
/* Various bit mask for EC_SC (R) */
|
||||
#define OBF 0x01
|
||||
#define IBF 0x02
|
||||
#define CMD 0x08
|
||||
#define BURST 0x10
|
||||
#define SCI_EVT 0x20
|
||||
#define SMI_EVT 0x40
|
||||
|
||||
/* Commands for EC_SC (W) */
|
||||
#define RD_EC 0x80
|
||||
#define WR_EC 0x81
|
||||
#define BE_EC 0x82
|
||||
#define BD_EC 0x83
|
||||
#define QR_EC 0x84
|
||||
|
||||
/*
|
||||
* ACPI 2.0 chapter 13 SMBus 2.0 EC register model
|
||||
*/
|
||||
|
||||
#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
|
||||
#define ACPI_EC_SMB_STS 0x01 /* status */
|
||||
#define ACPI_EC_SMB_ADDR 0x02 /* address */
|
||||
#define ACPI_EC_SMB_CMD 0x03 /* command */
|
||||
#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
|
||||
#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
|
||||
#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */
|
||||
#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
|
||||
|
||||
#define ACPI_EC_SMB_STS_DONE 0x80
|
||||
#define ACPI_EC_SMB_STS_ALRM 0x40
|
||||
#define ACPI_EC_SMB_STS_RES 0x20
|
||||
#define ACPI_EC_SMB_STS_STATUS 0x1f
|
||||
|
||||
#define ACPI_EC_SMB_STATUS_OK 0x00
|
||||
#define ACPI_EC_SMB_STATUS_FAIL 0x07
|
||||
#define ACPI_EC_SMB_STATUS_DNAK 0x10
|
||||
#define ACPI_EC_SMB_STATUS_DERR 0x11
|
||||
#define ACPI_EC_SMB_STATUS_CMD_DENY 0x12
|
||||
#define ACPI_EC_SMB_STATUS_UNKNOWN 0x13
|
||||
#define ACPI_EC_SMB_STATUS_ACC_DENY 0x17
|
||||
#define ACPI_EC_SMB_STATUS_TIMEOUT 0x18
|
||||
#define ACPI_EC_SMB_STATUS_NOTSUP 0x19
|
||||
#define ACPI_EC_SMB_STATUS_BUSY 0x1A
|
||||
#define ACPI_EC_SMB_STATUS_PEC 0x1F
|
||||
|
||||
#define ACPI_EC_SMB_PRTCL_WRITE 0x00
|
||||
#define ACPI_EC_SMB_PRTCL_READ 0x01
|
||||
#define ACPI_EC_SMB_PRTCL_QUICK 0x02
|
||||
#define ACPI_EC_SMB_PRTCL_BYTE 0x04
|
||||
#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06
|
||||
#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
|
||||
#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
|
||||
#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c
|
||||
#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
|
||||
#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
|
||||
#define ACPI_EC_SMB_PRTCL_PEC 0x80
|
||||
|
||||
/* Length of pre/post transaction sleep (msec) */
|
||||
#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
|
||||
#define ACPI_EC_SMB_ACCESS_SLEEP1 1
|
||||
#define ACPI_EC_SMB_ACCESS_SLEEP2 10
|
||||
|
||||
static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
|
||||
{
|
||||
u8 val;
|
||||
int err;
|
||||
|
||||
err = ec_read(smbus->base + address, &val);
|
||||
if (!err) {
|
||||
*data = val;
|
||||
}
|
||||
xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ec_write(smbus->base + address, data);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
char read_write, u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
struct acpi_ec_smbus *smbus = adap->algo_data;
|
||||
unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
|
||||
int i;
|
||||
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
protocol = ACPI_EC_SMB_PRTCL_READ;
|
||||
} else {
|
||||
protocol = ACPI_EC_SMB_PRTCL_WRITE;
|
||||
}
|
||||
pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
|
||||
|
||||
switch (size) {
|
||||
|
||||
case I2C_SMBUS_QUICK:
|
||||
protocol |= ACPI_EC_SMB_PRTCL_QUICK;
|
||||
read_write = I2C_SMBUS_WRITE;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
|
||||
}
|
||||
protocol |= ACPI_EC_SMB_PRTCL_BYTE;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
|
||||
}
|
||||
protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
|
||||
data->word >> 8);
|
||||
}
|
||||
protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = min_t(u8, data->block[0], 32);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
|
||||
for (i = 0; i < len; i++)
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
|
||||
data->block[i + 1]);
|
||||
}
|
||||
protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
len = min_t(u8, data->block[0], 32);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
for (i = 0; i < len; i++) {
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
|
||||
data->block[i + 1]);
|
||||
}
|
||||
}
|
||||
protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
|
||||
protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
|
||||
read_write = I2C_SMBUS_READ;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
protocol |= pec;
|
||||
len = min_t(u8, data->block[0], 31);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
|
||||
for (i = 0; i < len; i++)
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
|
||||
data->block[i + 1]);
|
||||
protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
|
||||
read_write = I2C_SMBUS_READ;
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
|
||||
"Unsupported transaction %d\n", size));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
|
||||
acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
|
||||
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
|
||||
|
||||
if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
|
||||
xudelay(500);
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
|
||||
}
|
||||
if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
|
||||
xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
|
||||
}
|
||||
if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
|
||||
|| (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
|
||||
case I2C_SMBUS_BYTE:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
|
||||
data->word = (temp[1] << 8) | temp[0];
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
len = 0;
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
|
||||
len = min_t(u8, len, 32);
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
for (i = 0; i < len; i++)
|
||||
acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
|
||||
data->block + i + 1);
|
||||
data->block[0] = len;
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
|
||||
return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA |
|
||||
I2C_FUNC_SMBUS_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
|
||||
.smbus_xfer = acpi_ec_smb_access,
|
||||
.functionality = acpi_ec_smb_func,
|
||||
};
|
||||
|
||||
static int acpi_ec_hc_add(struct acpi_device *device)
|
||||
{
|
||||
int status;
|
||||
unsigned long val;
|
||||
struct acpi_ec_hc *ec_hc;
|
||||
struct acpi_ec_smbus *smbus;
|
||||
|
||||
if (!device) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
|
||||
if (!ec_hc) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
|
||||
if (!smbus) {
|
||||
kfree(ec_hc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ec_hc->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
|
||||
acpi_driver_data(device) = ec_hc;
|
||||
|
||||
status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
|
||||
kfree(ec_hc);
|
||||
kfree(smbus);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
smbus->ec = acpi_driver_data(device->parent);
|
||||
smbus->base = (val & 0xff00ull) >> 8;
|
||||
smbus->alert = val & 0xffull;
|
||||
|
||||
smbus->adapter.owner = THIS_MODULE;
|
||||
smbus->adapter.algo = &acpi_ec_smbus_algorithm;
|
||||
smbus->adapter.algo_data = smbus;
|
||||
smbus->adapter.dev.parent = &device->dev;
|
||||
|
||||
if (i2c_add_adapter(&smbus->adapter)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
|
||||
"EC SMBus adapter: Failed to register adapter\n"));
|
||||
kfree(smbus);
|
||||
kfree(ec_hc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ec_hc->smbus = smbus;
|
||||
|
||||
printk(KERN_INFO PREFIX "%s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int acpi_ec_hc_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct acpi_ec_hc *ec_hc;
|
||||
|
||||
if (!device) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ec_hc = acpi_driver_data(device);
|
||||
|
||||
i2c_del_adapter(&ec_hc->smbus->adapter);
|
||||
kfree(ec_hc->smbus);
|
||||
kfree(ec_hc);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int __init acpi_ec_hc_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_ec_hc_driver);
|
||||
if (result < 0) {
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_ec_hc_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_ec_hc_driver);
|
||||
}
|
||||
|
||||
struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
|
||||
{
|
||||
return acpi_driver_data(device->parent);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_get_ec_hc);
|
||||
|
||||
module_init(acpi_ec_hc_init);
|
||||
module_exit(acpi_ec_hc_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ducrot Bruno");
|
||||
MODULE_DESCRIPTION("ACPI EC SMBus driver");
|
||||
23
drivers/acpi/i2c_ec.h
Normal file
23
drivers/acpi/i2c_ec.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SMBus driver for ACPI Embedded Controller ($Revision: 1.1.1.1 $)
|
||||
*
|
||||
* Copyright (c) 2002, 2005 Ducrot Bruno
|
||||
*
|
||||
* 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 version 2.
|
||||
*/
|
||||
|
||||
struct acpi_ec_smbus {
|
||||
struct i2c_adapter adapter;
|
||||
union acpi_ec *ec;
|
||||
int base;
|
||||
int alert;
|
||||
};
|
||||
|
||||
struct acpi_ec_hc {
|
||||
acpi_handle handle;
|
||||
struct acpi_ec_smbus *smbus;
|
||||
};
|
||||
|
||||
struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
|
||||
2798
drivers/acpi/ibm_acpi.c
Normal file
2798
drivers/acpi/ibm_acpi.c
Normal file
File diff suppressed because it is too large
Load Diff
12
drivers/acpi/namespace/Makefile
Normal file
12
drivers/acpi/namespace/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# Makefile for all Linux ACPI interpreter subdirectories
|
||||
#
|
||||
|
||||
obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \
|
||||
nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
|
||||
nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
|
||||
nsparse.o
|
||||
|
||||
obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
|
||||
|
||||
EXTRA_CFLAGS += $(ACPI_CFLAGS)
|
||||
651
drivers/acpi/namespace/nsaccess.c
Normal file
651
drivers/acpi/namespace/nsaccess.c
Normal file
@@ -0,0 +1,651 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nsaccess - Top-level functions for accessing ACPI namespace
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/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 (!ACPI_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) || (!new_node)) { /* Must be on same line for code converter */
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Could not create predefined name %s",
|
||||
init_val->name));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 i_aSL compiler */
|
||||
|
||||
new_node->value = obj_desc->method.param_count;
|
||||
#else
|
||||
/* Mark this as a very SPECIAL method */
|
||||
|
||||
obj_desc->method.method_flags =
|
||||
AML_METHOD_INTERNAL_ONLY;
|
||||
|
||||
#ifndef ACPI_DUMP_APP
|
||||
obj_desc->method.implementation =
|
||||
acpi_ut_osi_implementation;
|
||||
#endif
|
||||
#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) ACPI_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 (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
|
||||
acpi_gbl_global_lock_mutex =
|
||||
obj_desc->mutex.os_mutex;
|
||||
|
||||
/* 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 %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,
|
||||
ACPI_GET_OBJECT_TYPE
|
||||
(obj_desc));
|
||||
|
||||
/* 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_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 =
|
||||
acpi_ns_get_parent_node(prefix_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 = acpi_ns_get_parent_node(this_node);
|
||||
if (!this_node) {
|
||||
|
||||
/* Current scope has no parent scope */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"ACPI path has too many parent prefixes (^) - reached beyond root node"));
|
||||
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 %d 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 (%d 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ((num_segments == 0) &&
|
||||
(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 see if it opens a scope.
|
||||
*/
|
||||
if ((num_segments == 0) && (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);
|
||||
}
|
||||
496
drivers/acpi/namespace/nsalloc.c
Normal file
496
drivers/acpi/namespace/nsalloc.c
Normal file
@@ -0,0 +1,496 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nsalloc - Namespace allocation and deletion utilities
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/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
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ns_delete_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_delete_node, node);
|
||||
|
||||
parent_node = acpi_ns_get_parent_node(node);
|
||||
|
||||
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 = prev_node->peer;
|
||||
}
|
||||
|
||||
if (prev_node) {
|
||||
|
||||
/* Node is not first child, unlink it */
|
||||
|
||||
prev_node->peer = next_node->peer;
|
||||
if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
|
||||
prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
|
||||
}
|
||||
} else {
|
||||
/* Node is first child (has no previous peer) */
|
||||
|
||||
if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
|
||||
|
||||
/* No peers at all */
|
||||
|
||||
parent_node->child = NULL;
|
||||
} else { /* Link peer list to parent */
|
||||
|
||||
parent_node->child = next_node->peer;
|
||||
}
|
||||
}
|
||||
|
||||
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
|
||||
|
||||
/*
|
||||
* Detach an object if there is one, then delete the node
|
||||
*/
|
||||
acpi_ns_detach_object(node);
|
||||
(void)acpi_os_release_object(acpi_gbl_namespace_cache, 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);
|
||||
|
||||
/*
|
||||
* Get the owner ID from the Walk state
|
||||
* The owner ID is used to track table deletion and
|
||||
* deletion of objects created by methods
|
||||
*/
|
||||
if (walk_state) {
|
||||
owner_id = walk_state->owner_id;
|
||||
}
|
||||
|
||||
/* Link the new entry into the parent and existing children */
|
||||
|
||||
child_node = parent_node->child;
|
||||
if (!child_node) {
|
||||
parent_node->child = node;
|
||||
node->flags |= ANOBJ_END_OF_PEER_LIST;
|
||||
node->peer = parent_node;
|
||||
} else {
|
||||
while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
|
||||
child_node = child_node->peer;
|
||||
}
|
||||
|
||||
child_node->peer = node;
|
||||
|
||||
/* Clear end-of-list flag */
|
||||
|
||||
child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
|
||||
node->flags |= ANOBJ_END_OF_PEER_LIST;
|
||||
node->peer = parent_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 *child_node;
|
||||
struct acpi_namespace_node *next_node;
|
||||
u8 flags;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
|
||||
|
||||
if (!parent_node) {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/* If no children, all done! */
|
||||
|
||||
child_node = parent_node->child;
|
||||
if (!child_node) {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deallocate all children at this level
|
||||
*/
|
||||
do {
|
||||
|
||||
/* Get the things we need */
|
||||
|
||||
next_node = child_node->peer;
|
||||
flags = child_node->flags;
|
||||
|
||||
/* Grandchildren should have all been deleted already */
|
||||
|
||||
if (child_node->child) {
|
||||
ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p",
|
||||
parent_node, child_node));
|
||||
}
|
||||
|
||||
/* Now we can free this child object */
|
||||
|
||||
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
||||
"Object %p, Remaining %X\n", child_node,
|
||||
acpi_gbl_current_node_count));
|
||||
|
||||
/*
|
||||
* Detach an object if there is one, then free the child node
|
||||
*/
|
||||
acpi_ns_detach_object(child_node);
|
||||
|
||||
/* Now we can delete the node */
|
||||
|
||||
(void)acpi_os_release_object(acpi_gbl_namespace_cache,
|
||||
child_node);
|
||||
|
||||
/* And move on to the next child in the list */
|
||||
|
||||
child_node = next_node;
|
||||
|
||||
} while (!(flags & ANOBJ_END_OF_PEER_LIST));
|
||||
|
||||
/* 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_FUNCTION_TRACE(ns_delete_namespace_subtree);
|
||||
|
||||
if (!parent_node) {
|
||||
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(ACPI_TYPE_ANY, 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 (acpi_ns_get_next_node
|
||||
(ACPI_TYPE_ANY, child_node, NULL)) {
|
||||
/*
|
||||
* 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 = acpi_ns_get_parent_node(parent_node);
|
||||
}
|
||||
}
|
||||
|
||||
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(ACPI_TYPE_ANY, parent_node,
|
||||
child_node);
|
||||
|
||||
if (deletion_node) {
|
||||
acpi_ns_delete_children(deletion_node);
|
||||
acpi_ns_delete_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 (acpi_ns_get_next_node
|
||||
(ACPI_TYPE_ANY, child_node, NULL)) {
|
||||
/*
|
||||
* 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 = acpi_ns_get_parent_node(parent_node);
|
||||
}
|
||||
}
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return_VOID;
|
||||
}
|
||||
710
drivers/acpi/namespace/nsdump.c
Normal file
710
drivers/acpi/namespace/nsdump.c
Normal file
@@ -0,0 +1,710 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nsdump - table dumping routines for debug
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.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)
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
acpi_native_uint i;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_print_pathname);
|
||||
|
||||
if (!(acpi_dbg_level & ACPI_LV_NAMES)
|
||||
|| !(acpi_dbg_layer & ACPI_NAMESPACE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print the entire name */
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "["));
|
||||
|
||||
while (num_segments) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
ACPI_IS_PRINT(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_dbg_level & level) || !(acpi_dbg_layer & 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_map_handle_to_node(obj_handle);
|
||||
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 %08X",
|
||||
type));
|
||||
}
|
||||
|
||||
if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
|
||||
this_node->name.integer =
|
||||
acpi_ut_repair_name(this_node->name.ascii);
|
||||
|
||||
ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
|
||||
this_node->name.integer));
|
||||
}
|
||||
|
||||
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, we are done */
|
||||
|
||||
acpi_os_printf("\n");
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ACPI_TYPE_PROCESSOR:
|
||||
|
||||
acpi_os_printf("ID %X Len %.4X Addr %p\n",
|
||||
obj_desc->processor.proc_id,
|
||||
obj_desc->processor.length,
|
||||
(char *)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_ps_get_opcode_name(obj_desc->
|
||||
reference.
|
||||
opcode));
|
||||
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%d)", 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 = ACPI_GET_OBJECT_TYPE(obj_desc);
|
||||
|
||||
if (obj_type > ACPI_TYPE_LOCAL_MAX) {
|
||||
acpi_os_printf
|
||||
("(Ptr to ACPI Object type %X [UNKNOWN])\n",
|
||||
obj_type);
|
||||
bytes_to_dump = 32;
|
||||
} else {
|
||||
acpi_os_printf
|
||||
("(Ptr to ACPI Object type %X [%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);
|
||||
}
|
||||
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_FUNCTION_ENTRY();
|
||||
|
||||
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, (void *)&info,
|
||||
NULL);
|
||||
}
|
||||
#endif /* ACPI_FUTURE_USAGE */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 /* _ACPI_ASL_COMPILER */
|
||||
#endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */
|
||||
140
drivers/acpi/namespace/nsdumpdv.c
Normal file
140
drivers/acpi/namespace/nsdumpdv.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nsdump - table dumping routines for debug
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/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, ACPI_NS_SYSTEM_BUS, &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);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
240
drivers/acpi/namespace/nseval.c
Normal file
240
drivers/acpi/namespace/nseval.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nseval - Object evaluation, includes control method execution
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acparser.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nseval")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_evaluate
|
||||
*
|
||||
* PARAMETERS: Info - Evaluation info block, contains:
|
||||
* prefix_node - Prefix or Method/Object Node to execute
|
||||
* Pathname - 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.
|
||||
* 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.
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* Initialize the return value to an invalid object */
|
||||
|
||||
info->return_object = NULL;
|
||||
|
||||
/*
|
||||
* Get the actual namespace node for the target object. Handles these cases:
|
||||
*
|
||||
* 1) Null node, Pathname (absolute path)
|
||||
* 2) Node, Pathname (path relative to Node)
|
||||
* 3) Node, Null Pathname
|
||||
*/
|
||||
status = acpi_ns_get_node(info->prefix_node, info->pathname,
|
||||
ACPI_NS_NO_UPSEARCH, &info->resolved_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->resolved_node) ==
|
||||
ACPI_TYPE_LOCAL_METHOD_ALIAS) {
|
||||
info->resolved_node =
|
||||
ACPI_CAST_PTR(struct acpi_namespace_node,
|
||||
info->resolved_node->object);
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname,
|
||||
info->resolved_node,
|
||||
acpi_ns_get_attached_object(info->resolved_node)));
|
||||
|
||||
/*
|
||||
* Two major cases here:
|
||||
*
|
||||
* 1) The object is a control method -- execute it
|
||||
* 2) The object is not a method -- just return it's current value
|
||||
*/
|
||||
if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) {
|
||||
/*
|
||||
* 1) Object is a control method - execute it
|
||||
*/
|
||||
|
||||
/* Verify that there is a method object associated with this node */
|
||||
|
||||
info->obj_desc =
|
||||
acpi_ns_get_attached_object(info->resolved_node);
|
||||
if (!info->obj_desc) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Control method has no attached sub-object"));
|
||||
return_ACPI_STATUS(AE_NULL_OBJECT);
|
||||
}
|
||||
|
||||
ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:",
|
||||
ACPI_LV_INFO, _COMPONENT);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Method at AML address %p Length %X\n",
|
||||
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
|
||||
*/
|
||||
status = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status = acpi_ps_execute_method(info);
|
||||
acpi_ex_exit_interpreter();
|
||||
} else {
|
||||
/*
|
||||
* 2) Object is not a method, return its current value
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
* resolved_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 opregion.
|
||||
* The opregion access code assumes that the interpreter is locked.
|
||||
*/
|
||||
status = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Function has a strange interface */
|
||||
|
||||
status =
|
||||
acpi_ex_resolve_node_to_value(&info->resolved_node, NULL);
|
||||
acpi_ex_exit_interpreter();
|
||||
|
||||
/*
|
||||
* If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
|
||||
* in resolved_node.
|
||||
*/
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
status = AE_CTRL_RETURN_VALUE;
|
||||
info->return_object =
|
||||
ACPI_CAST_PTR(union acpi_operand_object,
|
||||
info->resolved_node);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
|
||||
"Returning object %p [%s]\n",
|
||||
info->return_object,
|
||||
acpi_ut_get_object_type_name(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->pathname));
|
||||
|
||||
/*
|
||||
* Namespace was unlocked by the handling acpi_ns* function, so we
|
||||
* just return
|
||||
*/
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
586
drivers/acpi/namespace/nsinit.c
Normal file
586
drivers/acpi/namespace/nsinit.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nsinit - namespace initialization
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <linux/nmi.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:"));
|
||||
|
||||
/* Set all init info to zero */
|
||||
|
||||
ACPI_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,
|
||||
&info, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
|
||||
"\nInitialized %hd/%hd Regions %hd/%hd Fields %hd/%hd Buffers %hd/%hd Packages (%hd 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,
|
||||
"%hd Control Methods found\n", info.method_count));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
|
||||
"%hd Op Regions found\n", 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 by executing _INI methods:"));
|
||||
|
||||
/* 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, &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;
|
||||
}
|
||||
|
||||
/* 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, &info, NULL);
|
||||
|
||||
ACPI_FREE(info.evaluate_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
|
||||
"\nExecuted %hd _INI methods requiring %hd _STA executions (examined %hd 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;
|
||||
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_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
|
||||
*/
|
||||
status = acpi_ex_enter_interpreter();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_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)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a dot for each object unless we are going to print the entire
|
||||
* pathname
|
||||
*/
|
||||
if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = acpi_ns_get_parent_node(node);
|
||||
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 = acpi_ns_get_parent_node(parent_node);
|
||||
}
|
||||
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));
|
||||
|
||||
info->prefix_node = device_node;
|
||||
info->pathname = METHOD_NAME__INI;
|
||||
info->parameters = NULL;
|
||||
info->parameter_type = ACPI_PARAM_ARGS;
|
||||
info->flags = ACPI_IGNORE_RETURN_VALUE;
|
||||
|
||||
/*
|
||||
* Some hardware relies on this being executed as atomically
|
||||
* as possible (without an NMI being received in the middle of
|
||||
* this) - so disable NMIs and initialize the device:
|
||||
*/
|
||||
acpi_nmi_disable();
|
||||
status = acpi_ns_evaluate(info);
|
||||
acpi_nmi_enable();
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
walk_info->num_INI++;
|
||||
|
||||
if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
|
||||
(!(acpi_dbg_level & ACPI_LV_INFO))) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
|
||||
}
|
||||
}
|
||||
#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->resolved_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);
|
||||
}
|
||||
315
drivers/acpi/namespace/nsload.c
Normal file
315
drivers/acpi/namespace/nsload.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nsload - namespace loading/expanding/contracting procedures
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/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(acpi_native_uint 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->child);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
acpi_tb_set_table_loaded_flag(table_index, TRUE);
|
||||
} else {
|
||||
acpi_tb_release_owner_id(table_index);
|
||||
}
|
||||
|
||||
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 Method Parsing and Object Initialization ****\n"));
|
||||
|
||||
status = acpi_ds_initialize_objects(table_index, node);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"**** Completed Table Method Parsing and 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_delete_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
|
||||
241
drivers/acpi/namespace/nsnames.c
Normal file
241
drivers/acpi/namespace/nsnames.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nsnames - Name manipulation and search
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsnames")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_build_external_path
|
||||
*
|
||||
* PARAMETERS: Node - NS node whose pathname is needed
|
||||
* Size - Size of the pathname
|
||||
* *name_buffer - Where to return the pathname
|
||||
*
|
||||
* RETURN: Places the pathname into the name_buffer, in external format
|
||||
* (name segments separated by path separators)
|
||||
*
|
||||
* DESCRIPTION: Generate a full pathaname
|
||||
*
|
||||
******************************************************************************/
|
||||
void
|
||||
acpi_ns_build_external_path(struct acpi_namespace_node *node,
|
||||
acpi_size size, char *name_buffer)
|
||||
{
|
||||
acpi_size index;
|
||||
struct acpi_namespace_node *parent_node;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/* Special case for root */
|
||||
|
||||
index = size - 1;
|
||||
if (index < ACPI_NAME_SIZE) {
|
||||
name_buffer[0] = AML_ROOT_PREFIX;
|
||||
name_buffer[1] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store terminator byte, then build name backwards */
|
||||
|
||||
parent_node = node;
|
||||
name_buffer[index] = 0;
|
||||
|
||||
while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) {
|
||||
index -= ACPI_NAME_SIZE;
|
||||
|
||||
/* Put the name into the buffer */
|
||||
|
||||
ACPI_MOVE_32_TO_32((name_buffer + index), &parent_node->name);
|
||||
parent_node = acpi_ns_get_parent_node(parent_node);
|
||||
|
||||
/* Prefix name with the path separator */
|
||||
|
||||
index--;
|
||||
name_buffer[index] = ACPI_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
/* Overwrite final separator with the root prefix character */
|
||||
|
||||
name_buffer[index] = AML_ROOT_PREFIX;
|
||||
|
||||
if (index != 0) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Could not construct pathname; index=%X, size=%X, Path=%s",
|
||||
(u32) index, (u32) size, &name_buffer[size]));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ACPI_DEBUG_OUTPUT
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 for debug printing in acpi_ns_search_table().
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
|
||||
{
|
||||
char *name_buffer;
|
||||
acpi_size size;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node);
|
||||
|
||||
/* Calculate required buffer size based on depth below root */
|
||||
|
||||
size = acpi_ns_get_pathname_length(node);
|
||||
|
||||
/* Allocate a buffer to be returned to caller */
|
||||
|
||||
name_buffer = ACPI_ALLOCATE_ZEROED(size);
|
||||
if (!name_buffer) {
|
||||
ACPI_ERROR((AE_INFO, "Allocation failure"));
|
||||
return_PTR(NULL);
|
||||
}
|
||||
|
||||
/* Build the path in the allocated buffer */
|
||||
|
||||
acpi_ns_build_external_path(node, size, name_buffer);
|
||||
return_PTR(name_buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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;
|
||||
struct acpi_namespace_node *next_node;
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/*
|
||||
* Compute length of pathname as 5 * number of name segments.
|
||||
* Go back up the parent tree to the root
|
||||
*/
|
||||
size = 0;
|
||||
next_node = node;
|
||||
|
||||
while (next_node && (next_node != acpi_gbl_root_node)) {
|
||||
size += ACPI_PATH_SEGMENT_LENGTH;
|
||||
next_node = acpi_ns_get_parent_node(next_node);
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
size = 1; /* Root node case */
|
||||
}
|
||||
|
||||
return (size + 1); /* +1 for null string terminator */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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_map_handle_to_node(target_handle);
|
||||
if (!node) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* Determine size required for the caller buffer */
|
||||
|
||||
required_size = acpi_ns_get_pathname_length(node);
|
||||
|
||||
/* 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 */
|
||||
|
||||
acpi_ns_build_external_path(node, required_size, buffer->pointer);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n",
|
||||
(char *)buffer->pointer, (u32) required_size));
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
440
drivers/acpi/namespace/nsobject.c
Normal file
440
drivers/acpi/namespace/nsobject.c
Normal file
@@ -0,0 +1,440 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nsobject - Utilities for objects attached to namespace
|
||||
* table entries
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/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 ||
|
||||
(ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_DATA)) {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/* Clear the entry in all cases */
|
||||
|
||||
node->object = NULL;
|
||||
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) {
|
||||
node->object = obj_desc->common.next_object;
|
||||
if (node->object &&
|
||||
(ACPI_GET_OBJECT_TYPE(node->object) !=
|
||||
ACPI_TYPE_LOCAL_DATA)) {
|
||||
node->object = node->object->common.next_object;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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))
|
||||
|| (ACPI_GET_OBJECT_TYPE(node->object) == 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) ||
|
||||
(ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_DATA) ||
|
||||
(!obj_desc->common.next_object) ||
|
||||
(ACPI_GET_OBJECT_TYPE(obj_desc->common.next_object) ==
|
||||
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 ((ACPI_GET_OBJECT_TYPE(obj_desc) == 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 ((ACPI_GET_OBJECT_TYPE(obj_desc) == 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 ((ACPI_GET_OBJECT_TYPE(obj_desc) == 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);
|
||||
}
|
||||
187
drivers/acpi/namespace/nsparse.c
Normal file
187
drivers/acpi/namespace/nsparse.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nsparse - namespace interface to AML parser
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/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(acpi_native_uint pass_number,
|
||||
acpi_native_uint table_index)
|
||||
{
|
||||
union acpi_parse_object *parse_root;
|
||||
acpi_status status;
|
||||
acpi_native_uint 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_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();
|
||||
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_get_table_by_index(table_index, &table);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_ds_delete_walk_state(walk_state);
|
||||
acpi_ps_free_op(parse_root);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Table must consist of at least a complete header */
|
||||
|
||||
if (table->length < sizeof(struct acpi_table_header)) {
|
||||
status = AE_BAD_HEADER;
|
||||
} else {
|
||||
aml_start = (u8 *) table + sizeof(struct acpi_table_header);
|
||||
aml_length = table->length - sizeof(struct acpi_table_header);
|
||||
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);
|
||||
acpi_ps_delete_parse_tree(parse_root);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Parse the AML */
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
|
||||
(unsigned)pass_number));
|
||||
status = acpi_ps_parse_aml(walk_state);
|
||||
|
||||
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(acpi_native_uint 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);
|
||||
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);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
414
drivers/acpi/namespace/nssearch.c
Normal file
414
drivers/acpi/namespace/nssearch.c
Normal file
@@ -0,0 +1,414 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nssearch - Namespace search
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
/*
|
||||
* The last entry in the list points back to the parent,
|
||||
* so a flag is used to indicate the end-of-list
|
||||
*/
|
||||
if (node->flags & ANOBJ_END_OF_PEER_LIST) {
|
||||
|
||||
/* Searched entire list, we are done */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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 = acpi_ns_get_parent_node(node);
|
||||
|
||||
/*
|
||||
* 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 = acpi_ns_get_parent_node(parent_node);
|
||||
}
|
||||
|
||||
/* 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 %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.
|
||||
*/
|
||||
if (!acpi_ut_valid_acpi_name(target_name)) {
|
||||
target_name =
|
||||
acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name));
|
||||
|
||||
/* Report warning only if in strict mode or debug mode */
|
||||
|
||||
if (!acpi_gbl_enable_interpreter_slack) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"Found bad character(s) in name, repaired: [%4.4s]\n",
|
||||
ACPI_CAST_PTR(char, &target_name)));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
|
||||
"Found bad character(s) in name, repaired: [%4.4s]\n",
|
||||
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) && (flags & ACPI_NS_ERROR_IF_FOUND)) {
|
||||
status = AE_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
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);
|
||||
}
|
||||
990
drivers/acpi/namespace/nsutils.c
Normal file
990
drivers/acpi/namespace/nsutils.c
Normal file
@@ -0,0 +1,990 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
|
||||
* parents and siblings and Scope manipulation
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/actables.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsutils")
|
||||
|
||||
/* Local prototypes */
|
||||
static u8 acpi_ns_valid_path_separator(char sep);
|
||||
|
||||
#ifdef ACPI_OBSOLETE_FUNCTIONS
|
||||
acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_report_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 warning message with full pathname
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
acpi_ns_report_error(char *module_name,
|
||||
u32 line_number,
|
||||
char *internal_name, acpi_status lookup_status)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 bad_name;
|
||||
char *name = NULL;
|
||||
|
||||
acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
|
||||
|
||||
if (lookup_status == AE_BAD_CHARACTER) {
|
||||
|
||||
/* There is a non-ascii character in the name */
|
||||
|
||||
ACPI_MOVE_32_TO_32(&bad_name, internal_name);
|
||||
acpi_os_printf("[0x%4.4X] (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\n",
|
||||
acpi_format_exception(lookup_status));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_report_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 warning message with full pathname
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
acpi_ns_report_method_error(char *module_name,
|
||||
u32 line_number,
|
||||
char *message,
|
||||
struct acpi_namespace_node *prefix_node,
|
||||
char *path, acpi_status method_status)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_namespace_node *node = prefix_node;
|
||||
|
||||
acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
|
||||
|
||||
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\n", acpi_format_exception(method_status));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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, 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);
|
||||
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_valid_root_prefix
|
||||
*
|
||||
* PARAMETERS: Prefix - Character to be checked
|
||||
*
|
||||
* RETURN: TRUE if a valid prefix
|
||||
*
|
||||
* DESCRIPTION: Check if a character is a valid ACPI Root prefix
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
u8 acpi_ns_valid_root_prefix(char prefix)
|
||||
{
|
||||
|
||||
return ((u8) (prefix == '\\'));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_valid_path_separator
|
||||
*
|
||||
* PARAMETERS: Sep - Character to be checked
|
||||
*
|
||||
* RETURN: TRUE if a valid path separator
|
||||
*
|
||||
* DESCRIPTION: Check if a character is a valid ACPI path separator
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static u8 acpi_ns_valid_path_separator(char sep)
|
||||
{
|
||||
|
||||
return ((u8) (sep == '.'));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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_UINT32(ACPI_TYPE_ANY);
|
||||
}
|
||||
|
||||
return_UINT32((acpi_object_type) 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 %X", type));
|
||||
return_UINT32(ACPI_NS_NORMAL);
|
||||
}
|
||||
|
||||
return_UINT32((u32) 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)
|
||||
{
|
||||
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_ns_valid_root_prefix(next_external_char[0])) {
|
||||
info->fully_qualified = TRUE;
|
||||
next_external_char++;
|
||||
} else {
|
||||
/*
|
||||
* Handle Carat prefixes
|
||||
*/
|
||||
while (*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_ns_valid_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;
|
||||
char *external_name = info->next_external_char;
|
||||
char *result = NULL;
|
||||
acpi_native_uint i;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ns_build_internal_name);
|
||||
|
||||
/* Setup the correct prefixes, counts, and pointers */
|
||||
|
||||
if (info->fully_qualified) {
|
||||
internal_name[0] = '\\';
|
||||
|
||||
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] = '^';
|
||||
}
|
||||
}
|
||||
|
||||
if (num_segments <= 1) {
|
||||
result = &internal_name[i];
|
||||
} else if (num_segments == 2) {
|
||||
internal_name[i] = AML_DUAL_NAME_PREFIX;
|
||||
result = &internal_name[(acpi_native_uint) (i + 1)];
|
||||
} else {
|
||||
internal_name[i] = AML_MULTI_NAME_PREFIX_OP;
|
||||
internal_name[(acpi_native_uint) (i + 1)] =
|
||||
(char)num_segments;
|
||||
result = &internal_name[(acpi_native_uint) (i + 2)];
|
||||
}
|
||||
}
|
||||
|
||||
/* Build the name (minus path separators) */
|
||||
|
||||
for (; num_segments; num_segments--) {
|
||||
for (i = 0; i < ACPI_NAME_SIZE; i++) {
|
||||
if (acpi_ns_valid_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)ACPI_TOUPPER((int)*external_name);
|
||||
external_name++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we must have a path separator, or the pathname is bad */
|
||||
|
||||
if (!acpi_ns_valid_path_separator(*external_name) &&
|
||||
(*external_name != 0)) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* 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(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,
|
||||
char *internal_name,
|
||||
u32 * converted_name_length, char **converted_name)
|
||||
{
|
||||
acpi_native_uint names_index = 0;
|
||||
acpi_native_uint num_segments = 0;
|
||||
acpi_native_uint required_length;
|
||||
acpi_native_uint prefix_length = 0;
|
||||
acpi_native_uint i = 0;
|
||||
acpi_native_uint 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 '\\':
|
||||
prefix_length = 1;
|
||||
break;
|
||||
|
||||
case '^':
|
||||
for (i = 0; i < internal_name_length; i++) {
|
||||
if (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 = (acpi_native_uint) (u8)
|
||||
internal_name[(acpi_native_uint)
|
||||
(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 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++] = '.';
|
||||
}
|
||||
|
||||
(*converted_name)[j++] = internal_name[names_index++];
|
||||
(*converted_name)[j++] = internal_name[names_index++];
|
||||
(*converted_name)[j++] = internal_name[names_index++];
|
||||
(*converted_name)[j++] = internal_name[names_index++];
|
||||
}
|
||||
}
|
||||
|
||||
if (converted_name_length) {
|
||||
*converted_name_length = (u32) required_length;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_map_handle_to_node
|
||||
*
|
||||
* PARAMETERS: Handle - Handle to be converted to an Node
|
||||
*
|
||||
* RETURN: A Name table entry pointer
|
||||
*
|
||||
* DESCRIPTION: Convert a namespace handle to a real Node
|
||||
*
|
||||
* Note: Real integer handles would allow for more verification
|
||||
* and keep all pointers within this subsystem - however this introduces
|
||||
* more (and perhaps unnecessary) overhead.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle)
|
||||
{
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
/*
|
||||
* Simple implementation
|
||||
*/
|
||||
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_convert_entry_to_handle
|
||||
*
|
||||
* PARAMETERS: Node - Node to be converted to a Handle
|
||||
*
|
||||
* RETURN: A user handle
|
||||
*
|
||||
* DESCRIPTION: Convert a real Node to a namespace handle
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* Simple implementation for now;
|
||||
*/
|
||||
return ((acpi_handle) node);
|
||||
|
||||
/* Example future implementation ---------------------
|
||||
|
||||
if (!Node)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (Node == acpi_gbl_root_node)
|
||||
{
|
||||
return (ACPI_ROOT_OBJECT);
|
||||
}
|
||||
|
||||
return ((acpi_handle) Node);
|
||||
------------------------------------------------------*/
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_terminate
|
||||
*
|
||||
* PARAMETERS: none
|
||||
*
|
||||
* RETURN: none
|
||||
*
|
||||
* DESCRIPTION: free memory allocated for namespace and ACPI table storage.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ns_terminate(void)
|
||||
{
|
||||
union acpi_operand_object *obj_desc;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ns_terminate);
|
||||
|
||||
/*
|
||||
* 1) Free the entire namespace -- all nodes and objects
|
||||
*
|
||||
* Delete all object descriptors attached to namepsace nodes
|
||||
*/
|
||||
acpi_ns_delete_namespace_subtree(acpi_gbl_root_node);
|
||||
|
||||
/* Detach any objects attached to the root */
|
||||
|
||||
obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node);
|
||||
if (obj_desc) {
|
||||
acpi_ns_detach_object(acpi_gbl_root_node);
|
||||
}
|
||||
|
||||
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_TRACE_STR(ns_opens_scope, acpi_ut_get_type_name(type));
|
||||
|
||||
if (!acpi_ut_valid_object_type(type)) {
|
||||
|
||||
/* type code out of range */
|
||||
|
||||
ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type));
|
||||
return_UINT32(ACPI_NS_NORMAL);
|
||||
}
|
||||
|
||||
return_UINT32(((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,
|
||||
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, pathname);
|
||||
|
||||
if (!pathname) {
|
||||
*return_node = prefix_node;
|
||||
if (!prefix_node) {
|
||||
*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_INFO, "%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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_get_parent_node
|
||||
*
|
||||
* PARAMETERS: Node - Current table entry
|
||||
*
|
||||
* RETURN: Parent entry of the given entry
|
||||
*
|
||||
* DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
|
||||
*node)
|
||||
{
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
||||
if (!node) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk to the end of this peer list. The last entry is marked with a flag
|
||||
* and the peer pointer is really a pointer back to the parent. This saves
|
||||
* putting a parent back pointer in each and every named object!
|
||||
*/
|
||||
while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
|
||||
node = node->peer;
|
||||
}
|
||||
|
||||
return (node->peer);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_get_next_valid_node
|
||||
*
|
||||
* PARAMETERS: Node - Current table entry
|
||||
*
|
||||
* RETURN: Next valid Node in the linked node list. NULL if no more valid
|
||||
* nodes.
|
||||
*
|
||||
* DESCRIPTION: Find the next valid node within a name table.
|
||||
* Useful for implementing NULL-end-of-list loops.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
|
||||
acpi_namespace_node
|
||||
*node)
|
||||
{
|
||||
|
||||
/* If we are at the end of this peer list, return NULL */
|
||||
|
||||
if (node->flags & ANOBJ_END_OF_PEER_LIST) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Otherwise just return the next peer */
|
||||
|
||||
return (node->peer);
|
||||
}
|
||||
|
||||
#ifdef ACPI_OBSOLETE_FUNCTIONS
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_find_parent_name
|
||||
*
|
||||
* PARAMETERS: *child_node - Named Obj whose name is to be found
|
||||
*
|
||||
* RETURN: The ACPI name
|
||||
*
|
||||
* DESCRIPTION: Search for the given obj in its parent scope and return the
|
||||
* name segment, or "????" if the parent name can't be found
|
||||
* (which "should not happen").
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node)
|
||||
{
|
||||
struct acpi_namespace_node *parent_node;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ns_find_parent_name);
|
||||
|
||||
if (child_node) {
|
||||
|
||||
/* Valid entry. Get the parent Node */
|
||||
|
||||
parent_node = acpi_ns_get_parent_node(child_node);
|
||||
if (parent_node) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Parent of %p [%4.4s] is %p [%4.4s]\n",
|
||||
child_node,
|
||||
acpi_ut_get_node_name(child_node),
|
||||
parent_node,
|
||||
acpi_ut_get_node_name(parent_node)));
|
||||
|
||||
if (parent_node->name.integer) {
|
||||
return_VALUE((acpi_name) parent_node->name.
|
||||
integer);
|
||||
}
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Unable to find parent of %p (%4.4s)\n",
|
||||
child_node,
|
||||
acpi_ut_get_node_name(child_node)));
|
||||
}
|
||||
|
||||
return_VALUE(ACPI_UNKNOWN_NAME);
|
||||
}
|
||||
#endif
|
||||
299
drivers/acpi/namespace/nswalk.c
Normal file
299
drivers/acpi/namespace/nswalk.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nswalk - Functions for walking the ACPI namespace
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nswalk")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_get_next_node
|
||||
*
|
||||
* 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(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();
|
||||
|
||||
if (!child_node) {
|
||||
|
||||
/* It's really the parent's _scope_ that we want */
|
||||
|
||||
if (parent_node->child) {
|
||||
next_node = parent_node->child;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
/* Start search at the NEXT node */
|
||||
|
||||
next_node = acpi_ns_get_next_valid_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 node */
|
||||
|
||||
next_node = acpi_ns_get_next_valid_node(next_node);
|
||||
}
|
||||
|
||||
/* 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
|
||||
* user_function - Called when an object of "Type" is found
|
||||
* Context - Passed to user function
|
||||
* 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 user_function is called whenever a node that matches
|
||||
* the type parameter is found. If the user 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 User Function 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 user_function,
|
||||
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;
|
||||
|
||||
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 = 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) {
|
||||
|
||||
/* Get the next node in this scope. Null if not found */
|
||||
|
||||
status = AE_OK;
|
||||
child_node =
|
||||
acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
|
||||
child_node);
|
||||
if (child_node) {
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
status =
|
||||
user_function(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 ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
|
||||
if (acpi_ns_get_next_node
|
||||
(ACPI_TYPE_ANY, child_node, NULL)) {
|
||||
|
||||
/* There is at least one child of this node, visit it */
|
||||
|
||||
level++;
|
||||
parent_node = child_node;
|
||||
child_node = NULL;
|
||||
}
|
||||
}
|
||||
} 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 = acpi_ns_get_parent_node(parent_node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Complete walk, not terminated by user function */
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
732
drivers/acpi/namespace/nsxfeval.c
Normal file
732
drivers/acpi/namespace/nsxfeval.c
Normal file
@@ -0,0 +1,732 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Module Name: nsxfeval - Public interfaces to the ACPI subsystem
|
||||
* ACPI Object evaluation interfaces
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2007, R. Byron Moore
|
||||
* 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acinterp.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsxfeval")
|
||||
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 must_free = 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) {
|
||||
must_free = 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 (must_free) {
|
||||
|
||||
/* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */
|
||||
|
||||
ACPI_FREE(return_buffer->pointer);
|
||||
return_buffer->pointer = NULL;
|
||||
}
|
||||
|
||||
return_buffer->length = 0;
|
||||
return_ACPI_STATUS(AE_TYPE);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed)
|
||||
#endif /* ACPI_FUTURE_USAGE */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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;
|
||||
acpi_status status2;
|
||||
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);
|
||||
}
|
||||
|
||||
info->pathname = pathname;
|
||||
info->parameter_type = ACPI_PARAM_ARGS;
|
||||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
info->prefix_node = acpi_ns_map_handle_to_node(handle);
|
||||
if (!info->prefix_node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are parameters to be passed to a control method, the external
|
||||
* objects must all be converted to internal objects
|
||||
*/
|
||||
if (external_params && external_params->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)
|
||||
external_params->
|
||||
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 < external_params->count; i++) {
|
||||
status =
|
||||
acpi_ut_copy_eobject_to_iobject(&external_params->
|
||||
pointer[i],
|
||||
&info->
|
||||
parameters[i]);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
info->parameters[external_params->count] = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Three major cases:
|
||||
* 1) Fully qualified pathname
|
||||
* 2) No handle, not fully qualified pathname (error)
|
||||
* 3) Valid handle
|
||||
*/
|
||||
if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) {
|
||||
|
||||
/* The path is fully qualified, just evaluate by name */
|
||||
|
||||
info->prefix_node = NULL;
|
||||
status = acpi_ns_evaluate(info);
|
||||
} 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;
|
||||
} else {
|
||||
/* We have a namespace a node and a possible relative path */
|
||||
|
||||
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)) {
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
status2 = acpi_ex_enter_interpreter();
|
||||
if (ACPI_SUCCESS(status2)) {
|
||||
|
||||
/* 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_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
|
||||
* user_function - Called when an object of "Type" 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 that matches
|
||||
* the type parameter is found. If the user 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 User Function 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 user_function,
|
||||
void *context, void **return_value)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(acpi_walk_namespace);
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
if ((type > ACPI_TYPE_LOCAL_MAX) || (!max_depth) || (!user_function)) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(type, start_object, max_depth,
|
||||
ACPI_NS_WALK_UNLOCK,
|
||||
user_function, context, return_value);
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
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_device_id hid;
|
||||
struct acpi_compatible_id_list *cid;
|
||||
acpi_native_uint i;
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
|
||||
/* Don't examine children of the device if not present */
|
||||
|
||||
return (AE_CTRL_DEPTH);
|
||||
}
|
||||
|
||||
/* Filter based on device HID & CID */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) {
|
||||
|
||||
/* Get the list of Compatible IDs */
|
||||
|
||||
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 */
|
||||
|
||||
for (i = 0; i < cid->count; i++) {
|
||||
if (ACPI_STRNCMP(cid->id[i].value, info->hid,
|
||||
sizeof(struct
|
||||
acpi_compatible_id)) !=
|
||||
0) {
|
||||
ACPI_FREE(cid);
|
||||
return (AE_OK);
|
||||
}
|
||||
}
|
||||
ACPI_FREE(cid);
|
||||
}
|
||||
}
|
||||
|
||||
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_get_device_callback.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_get_devices(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, &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_map_handle_to_node(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_map_handle_to_node(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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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_map_handle_to_node(obj_handle);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
|
||||
status = acpi_ns_get_attached_data(node, handler, data);
|
||||
|
||||
unlock_and_exit:
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return (status);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_get_data)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user