Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
This commit is contained in:
Linus Torvalds
2005-04-16 15:20:36 -07:00
commit 1da177e4c3
17291 changed files with 6718755 additions and 0 deletions

61
drivers/Kconfig Normal file
View File

@@ -0,0 +1,61 @@
# drivers/Kconfig
menu "Device Drivers"
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
source "drivers/pnp/Kconfig"
source "drivers/block/Kconfig"
source "drivers/ide/Kconfig"
source "drivers/scsi/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 "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/w1/Kconfig"
source "drivers/misc/Kconfig"
source "drivers/media/Kconfig"
source "drivers/video/Kconfig"
source "sound/Kconfig"
source "drivers/usb/Kconfig"
source "drivers/mmc/Kconfig"
source "drivers/infiniband/Kconfig"
endmenu

66
drivers/Makefile Normal file
View File

@@ -0,0 +1,66 @@
#
# 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-y += video/
obj-$(CONFIG_ACPI_BOOT) += 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/
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
obj-y += char/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
# we also need input/serio early so serio bus is initialized by the time
# serial drivers start registering their serio ports
obj-$(CONFIG_SERIO) += input/serio/
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_PPC_PMAC) += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_FUSION) += message/
obj-$(CONFIG_IEEE1394) += ieee1394/
obj-y += cdrom/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_PCCARD) += pcmcia/
obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
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_USB_GADGET) += usb/gadget/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_MCA) += mca/
obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_INFINIBAND) += infiniband/
obj-$(CONFIG_BLK_DEV_SGIIOC4) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/

1
drivers/acorn/README Normal file
View File

@@ -0,0 +1 @@
Drivers for the ACORN "podule" ARM specific bus.

View File

@@ -0,0 +1,36 @@
#
# Block device driver configuration
#
menu "Acorn-specific block devices"
depends on ARCH_ACORN
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

View 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

1609
drivers/acorn/block/fd1772.c Normal file

File diff suppressed because it is too large Load Diff

View 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
View 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)

1416
drivers/acorn/block/mfmhd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
#
# Makefile for the acorn character device drivers.
#
obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o
obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o

View 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;

369
drivers/acorn/char/i2c.c Normal file
View File

@@ -0,0 +1,369 @@
/*
* linux/drivers/acorn/char/i2c.c
*
* Copyright (C) 2000 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ARM IOC/IOMD i2c driver.
*
* On Acorn machines, the following i2c devices are on the bus:
* - PCF8583 real time clock & static RAM
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/fs.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/hardware/ioc.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "pcf8583.h"
extern int (*set_rtc)(void);
static struct i2c_client *rtc_client;
static const unsigned char days_in_mon[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
#define CMOS_CHECKSUM (63)
/*
* Acorn machines store the year in the static RAM at
* location 128.
*/
#define CMOS_YEAR (64 + 128)
static inline int rtc_command(int cmd, void *data)
{
int ret = -EIO;
if (rtc_client)
ret = rtc_client->driver->command(rtc_client, cmd, data);
return ret;
}
/*
* Update the century + year bytes in the CMOS RAM, ensuring
* that the check byte is correctly adjusted for the change.
*/
static int rtc_update_year(unsigned int new_year)
{
unsigned char yr[2], chk;
struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr };
struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
int ret;
ret = rtc_command(MEM_READ, &cmos_check);
if (ret)
goto out;
ret = rtc_command(MEM_READ, &cmos_year);
if (ret)
goto out;
chk -= yr[1] + yr[0];
yr[1] = new_year / 100;
yr[0] = new_year % 100;
chk += yr[1] + yr[0];
ret = rtc_command(MEM_WRITE, &cmos_year);
if (ret == 0)
ret = rtc_command(MEM_WRITE, &cmos_check);
out:
return ret;
}
/*
* Read the current RTC time and date, and update xtime.
*/
static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year)
{
unsigned char ctrl, yr[2];
struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr };
int real_year, year_offset;
/*
* Ensure that the RTC is running.
*/
rtc_command(RTC_GETCTRL, &ctrl);
if (ctrl & 0xc0) {
unsigned char new_ctrl = ctrl & ~0xc0;
printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
ctrl, new_ctrl);
rtc_command(RTC_SETCTRL, &new_ctrl);
}
if (rtc_command(RTC_GETDATETIME, rtctm) ||
rtc_command(MEM_READ, &rtcmem))
return;
real_year = yr[0];
/*
* The RTC year holds the LSB two bits of the current
* year, which should reflect the LSB two bits of the
* CMOS copy of the year. Any difference indicates
* that we have to correct the CMOS version.
*/
year_offset = rtctm->year_off - (real_year & 3);
if (year_offset < 0)
/*
* RTC year wrapped. Adjust it appropriately.
*/
year_offset += 4;
*year = real_year + year_offset + yr[1] * 100;
}
static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year)
{
unsigned char leap;
int ret;
leap = (!(year % 4) && (year % 100)) || !(year % 400);
if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0)
return -EINVAL;
if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap)))
return -EINVAL;
if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60)
return -EINVAL;
/*
* The RTC's own 2-bit year must reflect the least
* significant two bits of the CMOS year.
*/
rtctm->year_off = (year % 100) & 3;
ret = rtc_command(RTC_SETDATETIME, rtctm);
if (ret == 0)
ret = rtc_update_year(year);
return ret;
}
/*
* Set the RTC time only. Note that
* we do not touch the date.
*/
static int k_set_rtc_time(void)
{
struct rtc_tm new_rtctm, old_rtctm;
unsigned long nowtime = xtime.tv_sec;
if (rtc_command(RTC_GETDATETIME, &old_rtctm))
return 0;
new_rtctm.cs = xtime.tv_nsec / 10000000;
new_rtctm.secs = nowtime % 60; nowtime /= 60;
new_rtctm.mins = nowtime % 60; nowtime /= 60;
new_rtctm.hours = nowtime % 24;
/*
* avoid writing when we're going to change the day
* of the month. We will retry in the next minute.
* This basically means that if the RTC must not drift
* by more than 1 minute in 11 minutes.
*
* [ rtc: 1/1/2000 23:58:00, real 2/1/2000 00:01:00,
* rtc gets set to 1/1/2000 00:01:00 ]
*/
if ((old_rtctm.hours == 23 && old_rtctm.mins == 59) ||
(new_rtctm.hours == 23 && new_rtctm.mins == 59))
return 1;
return rtc_command(RTC_SETTIME, &new_rtctm);
}
static int rtc_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int year;
struct rtc_time rtctm;
struct rtc_tm rtc_raw;
switch (cmd) {
case RTC_ALM_READ:
case RTC_ALM_SET:
break;
case RTC_RD_TIME:
memset(&rtctm, 0, sizeof(struct rtc_time));
get_rtc_time(&rtc_raw, &year);
rtctm.tm_sec = rtc_raw.secs;
rtctm.tm_min = rtc_raw.mins;
rtctm.tm_hour = rtc_raw.hours;
rtctm.tm_mday = rtc_raw.mday;
rtctm.tm_mon = rtc_raw.mon - 1; /* month starts at 0 */
rtctm.tm_year = year - 1900; /* starts at 1900 */
return copy_to_user((void *)arg, &rtctm, sizeof(rtctm))
? -EFAULT : 0;
case RTC_SET_TIME:
if (!capable(CAP_SYS_TIME))
return -EACCES;
if (copy_from_user(&rtctm, (void *)arg, sizeof(rtctm)))
return -EFAULT;
rtc_raw.secs = rtctm.tm_sec;
rtc_raw.mins = rtctm.tm_min;
rtc_raw.hours = rtctm.tm_hour;
rtc_raw.mday = rtctm.tm_mday;
rtc_raw.mon = rtctm.tm_mon + 1;
year = rtctm.tm_year + 1900;
return set_rtc_time(&rtc_raw, year);
break;
case RTC_EPOCH_READ:
return put_user(1900, (unsigned long *)arg);
}
return -EINVAL;
}
static struct file_operations rtc_fops = {
.ioctl = rtc_ioctl,
};
static struct miscdevice rtc_dev = {
.minor = RTC_MINOR,
.name = "rtc",
.fops = &rtc_fops,
};
/* IOC / IOMD i2c driver */
#define FORCE_ONES 0xdc
#define SCL 0x02
#define SDA 0x01
/*
* We must preserve all non-i2c output bits in IOC_CONTROL.
* Note also that we need to preserve the value of SCL and
* SDA outputs as well (which may be different from the
* values read back from IOC_CONTROL).
*/
static u_int force_ones;
static void ioc_setscl(void *data, int state)
{
u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
u_int ones = force_ones;
if (state)
ones |= SCL;
else
ones &= ~SCL;
force_ones = ones;
ioc_writeb(ioc_control | ones, IOC_CONTROL);
}
static void ioc_setsda(void *data, int state)
{
u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
u_int ones = force_ones;
if (state)
ones |= SDA;
else
ones &= ~SDA;
force_ones = ones;
ioc_writeb(ioc_control | ones, IOC_CONTROL);
}
static int ioc_getscl(void *data)
{
return (ioc_readb(IOC_CONTROL) & SCL) != 0;
}
static int ioc_getsda(void *data)
{
return (ioc_readb(IOC_CONTROL) & SDA) != 0;
}
static struct i2c_algo_bit_data ioc_data = {
.setsda = ioc_setsda,
.setscl = ioc_setscl,
.getsda = ioc_getsda,
.getscl = ioc_getscl,
.udelay = 80,
.mdelay = 80,
.timeout = 100
};
static int ioc_client_reg(struct i2c_client *client)
{
if (client->driver->id == I2C_DRIVERID_PCF8583 &&
client->addr == 0x50) {
struct rtc_tm rtctm;
unsigned int year;
struct timespec tv;
rtc_client = client;
get_rtc_time(&rtctm, &year);
tv.tv_nsec = rtctm.cs * 10000000;
tv.tv_sec = mktime(year, rtctm.mon, rtctm.mday,
rtctm.hours, rtctm.mins, rtctm.secs);
do_settimeofday(&tv);
set_rtc = k_set_rtc_time;
}
return 0;
}
static int ioc_client_unreg(struct i2c_client *client)
{
if (client == rtc_client) {
set_rtc = NULL;
rtc_client = NULL;
}
return 0;
}
static struct i2c_adapter ioc_ops = {
.id = I2C_HW_B_IOC,
.algo_data = &ioc_data,
.client_register = ioc_client_reg,
.client_unregister = ioc_client_unreg,
};
static int __init i2c_ioc_init(void)
{
int ret;
force_ones = FORCE_ONES | SCL | SDA;
ret = i2c_bit_add_bus(&ioc_ops);
if (ret >= 0){
ret = misc_register(&rtc_dev);
if(ret < 0)
i2c_bit_del_bus(&ioc_ops);
}
return ret;
}
__initcall(i2c_ioc_init);

View File

@@ -0,0 +1,239 @@
/*
* linux/drivers/acorn/char/pcf8583.c
*
* Copyright (C) 2000 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Driver for PCF8583 RTC & RAM chip
*/
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/mc146818rtc.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/bcd.h>
#include "pcf8583.h"
static struct i2c_driver pcf8583_driver;
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
.normal_i2c_range = ignore,
.probe = ignore,
.probe_range = ignore,
.ignore = ignore,
.ignore_range = ignore,
.force = ignore,
};
#define DAT(x) ((unsigned int)(x->dev.driver_data))
static int
pcf8583_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *c;
unsigned char buf[1], ad[1] = { 0 };
struct i2c_msg msgs[2] = {
{ addr, 0, 1, ad },
{ addr, I2C_M_RD, 1, buf }
};
c = kmalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
memset(c, 0, sizeof(*c));
c->addr = addr;
c->adapter = adap;
c->driver = &pcf8583_driver;
if (i2c_transfer(c->adapter, msgs, 2) == 2)
DAT(c) = buf[0];
return i2c_attach_client(c);
}
static int
pcf8583_probe(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, pcf8583_attach);
}
static int
pcf8583_detach(struct i2c_client *client)
{
i2c_detach_client(client);
kfree(client);
return 0;
}
static int
pcf8583_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
{
unsigned char buf[8], addr[1] = { 1 };
struct i2c_msg msgs[2] = {
{ client->addr, 0, 1, addr },
{ client->addr, I2C_M_RD, 6, buf }
};
int ret = -EIO;
memset(buf, 0, sizeof(buf));
ret = i2c_transfer(client->adapter, msgs, 2);
if (ret == 2) {
dt->year_off = buf[4] >> 6;
dt->wday = buf[5] >> 5;
buf[4] &= 0x3f;
buf[5] &= 0x1f;
dt->cs = BCD_TO_BIN(buf[0]);
dt->secs = BCD_TO_BIN(buf[1]);
dt->mins = BCD_TO_BIN(buf[2]);
dt->hours = BCD_TO_BIN(buf[3]);
dt->mday = BCD_TO_BIN(buf[4]);
dt->mon = BCD_TO_BIN(buf[5]);
ret = 0;
}
return ret;
}
static int
pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
{
unsigned char buf[8];
int ret, len = 6;
buf[0] = 0;
buf[1] = DAT(client) | 0x80;
buf[2] = BIN_TO_BCD(dt->cs);
buf[3] = BIN_TO_BCD(dt->secs);
buf[4] = BIN_TO_BCD(dt->mins);
buf[5] = BIN_TO_BCD(dt->hours);
if (datetoo) {
len = 8;
buf[6] = BIN_TO_BCD(dt->mday) | (dt->year_off << 6);
buf[7] = BIN_TO_BCD(dt->mon) | (dt->wday << 5);
}
ret = i2c_master_send(client, (char *)buf, len);
if (ret == len)
ret = 0;
buf[1] = DAT(client);
i2c_master_send(client, (char *)buf, 2);
return ret;
}
static int
pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
{
*ctrl = DAT(client);
return 0;
}
static int
pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
{
unsigned char buf[2];
buf[0] = 0;
buf[1] = *ctrl;
DAT(client) = *ctrl;
return i2c_master_send(client, (char *)buf, 2);
}
static int
pcf8583_read_mem(struct i2c_client *client, struct mem *mem)
{
unsigned char addr[1];
struct i2c_msg msgs[2] = {
{ client->addr, 0, 1, addr },
{ client->addr, I2C_M_RD, 0, mem->data }
};
if (mem->loc < 8)
return -EINVAL;
addr[0] = mem->loc;
msgs[1].len = mem->nr;
return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
}
static int
pcf8583_write_mem(struct i2c_client *client, struct mem *mem)
{
unsigned char addr[1];
struct i2c_msg msgs[2] = {
{ client->addr, 0, 1, addr },
{ client->addr, 0, 0, mem->data }
};
if (mem->loc < 8)
return -EINVAL;
addr[0] = mem->loc;
msgs[1].len = mem->nr;
return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
}
static int
pcf8583_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
switch (cmd) {
case RTC_GETDATETIME:
return pcf8583_get_datetime(client, arg);
case RTC_SETTIME:
return pcf8583_set_datetime(client, arg, 0);
case RTC_SETDATETIME:
return pcf8583_set_datetime(client, arg, 1);
case RTC_GETCTRL:
return pcf8583_get_ctrl(client, arg);
case RTC_SETCTRL:
return pcf8583_set_ctrl(client, arg);
case MEM_READ:
return pcf8583_read_mem(client, arg);
case MEM_WRITE:
return pcf8583_write_mem(client, arg);
default:
return -EINVAL;
}
}
static struct i2c_driver pcf8583_driver = {
.name = "PCF8583",
.id = I2C_DRIVERID_PCF8583,
.flags = I2C_DF_NOTIFY,
.attach_adapter = pcf8583_probe,
.detach_client = pcf8583_detach,
.command = pcf8583_command
};
static __init int pcf8583_init(void)
{
return i2c_add_driver(&pcf8583_driver);
}
__initcall(pcf8583_init);

View File

@@ -0,0 +1,41 @@
/*
* linux/drivers/acorn/char/pcf8583.h
*
* Copyright (C) 2000 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
struct rtc_tm {
unsigned char cs;
unsigned char secs;
unsigned char mins;
unsigned char hours;
unsigned char mday;
unsigned char mon;
unsigned char year_off;
unsigned char wday;
};
struct mem {
unsigned int loc;
unsigned int nr;
unsigned char *data;
};
#define RTC_GETDATETIME 0
#define RTC_SETTIME 1
#define RTC_SETDATETIME 2
#define RTC_GETCTRL 3
#define RTC_SETCTRL 4
#define MEM_READ 5
#define MEM_WRITE 6
#define CTRL_STOP 0x80
#define CTRL_HOLD 0x40
#define CTRL_32KHZ 0x00
#define CTRL_MASK 0x08
#define CTRL_ALARMEN 0x04
#define CTRL_ALARM 0x02
#define CTRL_TIMER 0x01

356
drivers/acpi/Kconfig Normal file
View File

@@ -0,0 +1,356 @@
#
# ACPI Configuration
#
menu "ACPI (Advanced Configuration and Power Interface) Support"
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
config ACPI
bool "ACPI Support"
depends on IA64 || X86
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>
config ACPI_BOOT
bool
depends on ACPI || X86_HT
default y
if ACPI
config ACPI_INTERPRETER
bool
depends on !IA64_SGI_SN
default y
if ACPI_INTERPRETER
config ACPI_SLEEP
bool "Sleep States (EXPERIMENTAL)"
depends on X86
depends on EXPERIMENTAL && 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_AC
tristate "AC Adapter"
depends on X86
default m
help
This driver adds support for the AC Adapter object, which indicates
whether a system is on AC, or not. Typically, only mobile systems
have this object, since desktops are always on AC.
config ACPI_BATTERY
tristate "Battery"
depends on X86
default m
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 !IA64_SGI_SN
default m
help
This driver registers for events based on buttons, such as the
power, sleep, and lid switch. In the future, a daemon will read
/proc/acpi/event and perform user-defined actions such as shutting
down the system. Until then, you can cat it, and see output when
a button is pressed.
config ACPI_VIDEO
tristate "Video"
depends on EXPERIMENTAL
depends on !IA64_SGI_SN
default m
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"
depends on !IA64_SGI_SN
default m
help
This driver adds support for ACPI fan devices, allowing user-mode
applications to perform basic fan control (on, off, status).
config ACPI_PROCESSOR
tristate "Processor"
depends on !IA64_SGI_SN
default m
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.
config ACPI_HOTPLUG_CPU
bool "Processor Hotplug (EXPERIMENTAL)"
depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
depends on !IA64_SGI_SN
select ACPI_CONTAINER
default n
---help---
Select this option if your platform support physical CPU hotplug.
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
default m
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 (IA64 || X86_64)
default y if IA64_GENERIC || IA64_SGI_SN2
config ACPI_ASUS
tristate "ASUS/Medion Laptop Extras"
depends on X86
default m
---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)
config ACPI_IBM
tristate "IBM ThinkPad Laptop Extras"
depends on X86
default m
---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_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on X86
default m
---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
Thist 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 wich includes the AmlCode declaration.
config ACPI_BLACKLIST_YEAR
int "Disable ACPI for systems before Jan 1st this year"
depends on ACPI_INTERPRETER
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"
depends on !IA64_SGI_SN
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_BUS
bool
depends on !IA64_SGI_SN
default y
config ACPI_EC
bool
depends on X86
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
depends on !IA64_SGI_SN
default y
config ACPI_PCI
bool
depends on !IA64_SGI_SN
default PCI
config ACPI_SYSTEM
bool
depends on !IA64_SGI_SN
default y
help
This driver will enable your system to shut down using ACPI, and
dump your ACPI DSDT table using /proc/acpi/dsdt.
endif # ACPI_INTERPRETER
config X86_PM_TIMER
bool "Power Management Timer Support"
depends on X86
depends on ACPI_BOOT && EXPERIMENTAL
depends on !X86_64
default n
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 powermanagement features
like aggressive processor idling, throttling, frequency and/or
voltage scaling, unlike the commonly used Time Stamp Counter
(TSC) timing source.
So, if you see messages like 'Losing too many ticks!' in the
kernel logs, and/or you are using this on a notebook which
does not yet have an HPET, you should say "Y" here.
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 is the ACPI generic container driver which supports
ACPI0004, PNP0A05 and PNP0A06 devices
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 platfrom 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
endif # ACPI
endmenu

58
drivers/acpi/Makefile Normal file
View File

@@ -0,0 +1,58 @@
#
# 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-$(CONFIG_ACPI_BOOT) += tables.o
obj-$(CONFIG_ACPI_INTERPRETER) += blacklist.o
#
# ACPI Core Subsystem (Interpreter)
#
obj-$(CONFIG_ACPI_INTERPRETER) += 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-$(CONFIG_ACPI_BUS) += sleep/
obj-$(CONFIG_ACPI_BUS) += bus.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_VIDEO) += video.o
obj-$(CONFIG_ACPI_PCI) += 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_BUS) += scan.o motherboard.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o

354
drivers/acpi/ac.c Normal file
View File

@@ -0,0 +1,354 @@
/*
* acpi_ac.c - ACPI AC Adapter Driver ($Revision: 27 $)
*
* 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_DRIVER_NAME "ACPI AC Adapter Driver"
#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 ("acpi_ac")
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
MODULE_LICENSE("GPL");
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 = ACPI_AC_DRIVER_NAME,
.class = ACPI_AC_CLASS,
.ids = ACPI_AC_HID,
.ops = {
.add = acpi_ac_add,
.remove = acpi_ac_remove,
},
};
struct acpi_ac {
acpi_handle handle;
unsigned long state;
};
static 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;
ACPI_FUNCTION_TRACE("acpi_ac_get_state");
if (!ac)
return_VALUE(-EINVAL);
status = acpi_evaluate_integer(ac->handle, "_PSR", NULL, &ac->state);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error reading AC Adapter state\n"));
ac->state = ACPI_AC_STATUS_UNKNOWN;
return_VALUE(-ENODEV);
}
return_VALUE(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 = (struct acpi_ac *) seq->private;
ACPI_FUNCTION_TRACE("acpi_ac_seq_show");
if (!ac)
return_VALUE(0);
if (acpi_ac_get_state(ac)) {
seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
return_VALUE(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_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_ac_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ac_dir);
if (!acpi_device_dir(device))
return_VALUE(-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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_AC_FILE_STATE));
else {
entry->proc_fops = &acpi_ac_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
return_VALUE(0);
}
static int
acpi_ac_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_ac_remove_fs");
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_VALUE(0);
}
/* --------------------------------------------------------------------------
Driver Model
-------------------------------------------------------------------------- */
static void
acpi_ac_notify (
acpi_handle handle,
u32 event,
void *data)
{
struct acpi_ac *ac = (struct acpi_ac *) data;
struct acpi_device *device = NULL;
ACPI_FUNCTION_TRACE("acpi_ac_notify");
if (!ac)
return_VOID;
if (acpi_bus_get_device(ac->handle, &device))
return_VOID;
switch (event) {
case ACPI_AC_NOTIFY_STATUS:
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_VOID;
}
static int
acpi_ac_add (
struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL;
ACPI_FUNCTION_TRACE("acpi_ac_add");
if (!device)
return_VALUE(-EINVAL);
ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
if (!ac)
return_VALUE(-ENOMEM);
memset(ac, 0, sizeof(struct acpi_ac));
ac->handle = device->handle;
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(ac->handle,
ACPI_DEVICE_NOTIFY, acpi_ac_notify, ac);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing notify handler\n"));
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_VALUE(result);
}
static int
acpi_ac_remove (
struct acpi_device *device,
int type)
{
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL;
ACPI_FUNCTION_TRACE("acpi_ac_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
ac = (struct acpi_ac *) acpi_driver_data(device);
status = acpi_remove_notify_handler(ac->handle,
ACPI_DEVICE_NOTIFY, acpi_ac_notify);
if (ACPI_FAILURE(status))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error removing notify handler\n"));
acpi_ac_remove_fs(device);
kfree(ac);
return_VALUE(0);
}
static int __init
acpi_ac_init (void)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_ac_init");
acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
if (!acpi_ac_dir)
return_VALUE(-ENODEV);
acpi_ac_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_ac_driver);
if (result < 0) {
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
static void __exit
acpi_ac_exit (void)
{
ACPI_FUNCTION_TRACE("acpi_ac_exit");
acpi_bus_unregister_driver(&acpi_ac_driver);
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
return_VOID;
}
module_init(acpi_ac_init);
module_exit(acpi_ac_exit);

View File

@@ -0,0 +1,542 @@
/*
* 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_DRIVER_NAME "Hotplug Mem Driver"
#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
ACPI_MODULE_NAME ("acpi_memory")
MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME);
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 struct acpi_driver acpi_memory_device_driver = {
.name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
.class = ACPI_MEMORY_DEVICE_CLASS,
.ids = ACPI_MEMORY_DEVICE_HID,
.ops = {
.add = acpi_memory_device_add,
.remove = acpi_memory_device_remove,
},
};
struct acpi_memory_device {
acpi_handle handle;
unsigned int state; /* State of the memory device */
unsigned short cache_attribute; /* memory cache attribute */
unsigned short read_write_attribute;/* memory read/write attribute */
u64 start_addr; /* Memory Range start physical addr */
u64 end_addr; /* Memory Range end physical addr */
};
static int
acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
{
acpi_status status;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_resource *resource = NULL;
struct acpi_resource_address64 address64;
ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources");
/* Get the range from the _CRS */
status = acpi_get_current_resources(mem_device->handle, &buffer);
if (ACPI_FAILURE(status))
return_VALUE(-EINVAL);
resource = (struct acpi_resource *) buffer.pointer;
status = acpi_resource_to_address64(resource, &address64);
if (ACPI_SUCCESS(status)) {
if (address64.resource_type == ACPI_MEMORY_RANGE) {
/* Populate the structure */
mem_device->cache_attribute =
address64.attribute.memory.cache_attribute;
mem_device->read_write_attribute =
address64.attribute.memory.read_write_attribute;
mem_device->start_addr = address64.min_address_range;
mem_device->end_addr = address64.max_address_range;
}
}
acpi_os_free(buffer.pointer);
return_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_memory_get_device");
if (!acpi_bus_get_device(handle, &device) && device)
goto end;
status = acpi_get_parent(handle, &phandle);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error in acpi_get_parent\n"));
return_VALUE(-EINVAL);
}
/* Get the parent device */
status = acpi_bus_get_device(phandle, &pdevice);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error in acpi_bus_get_device\n"));
return_VALUE(-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_DEBUG_PRINT((ACPI_DB_ERROR,
"Error in acpi_bus_add\n"));
return_VALUE(-EINVAL);
}
end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
printk(KERN_ERR "\n driver data not found" );
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
static int
acpi_memory_check_device(struct acpi_memory_device *mem_device)
{
unsigned long current_status;
ACPI_FUNCTION_TRACE("acpi_memory_check_device");
/* Get device present/absent information from the _STA */
if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->handle, "_STA",
NULL, &current_status)))
return_VALUE(-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_VALUE(-ENODEV);
return_VALUE(0);
}
static int
acpi_memory_enable_device(struct acpi_memory_device *mem_device)
{
int result;
ACPI_FUNCTION_TRACE("acpi_memory_enable_device");
/* Get the range from the _CRS */
result = acpi_memory_get_device_resources(mem_device);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"\nget_device_resources failed\n"));
mem_device->state = MEMORY_INVALID_STATE;
return result;
}
/*
* Tell the VM there is more memory here...
* Note: Assume that this function returns zero on success
*/
result = add_memory(mem_device->start_addr,
(mem_device->end_addr - mem_device->start_addr) + 1,
mem_device->read_write_attribute);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"\nadd_memory failed\n"));
mem_device->state = MEMORY_INVALID_STATE;
return result;
}
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;
ACPI_FUNCTION_TRACE("acpi_memory_powerdown_device");
/* 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->handle,
"_EJ0", &arg_list, NULL);
/* Return on _EJ0 failure */
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"_EJ0 failed.\n"));
return_VALUE(-ENODEV);
}
/* Evalute _STA to check if the device is disabled */
status = acpi_evaluate_integer(mem_device->handle, "_STA",
NULL, &current_status);
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
/* Check for device status. Device should be disabled */
if (current_status & ACPI_MEMORY_STA_ENABLED)
return_VALUE(-EINVAL);
return_VALUE(0);
}
static int
acpi_memory_disable_device(struct acpi_memory_device *mem_device)
{
int result;
u64 start = mem_device->start_addr;
u64 len = mem_device->end_addr - start + 1;
unsigned long attr = mem_device->read_write_attribute;
ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
/*
* Ask the VM to offline this memory range.
* Note: Assume that this function returns zero on success
*/
result = remove_memory(start, len, attr);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
return_VALUE(result);
}
/* Power-off and eject the device */
result = acpi_memory_powerdown_device(mem_device);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device Power Down failed.\n"));
/* 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;
ACPI_FUNCTION_TRACE("acpi_memory_device_notify");
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)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error in finding driver data\n"));
return_VOID;
}
if (!acpi_memory_check_device(mem_device)) {
if (acpi_memory_enable_device(mem_device))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error in acpi_memory_enable_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)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device doesn't exist\n"));
break;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"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))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error in acpi_memory_disable_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_VOID;
}
static int
acpi_memory_device_add(struct acpi_device *device)
{
int result;
struct acpi_memory_device *mem_device = NULL;
ACPI_FUNCTION_TRACE("acpi_memory_device_add");
if (!device)
return_VALUE(-EINVAL);
mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
if (!mem_device)
return_VALUE(-ENOMEM);
memset(mem_device, 0, sizeof(struct acpi_memory_device));
mem_device->handle = device->handle;
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_VALUE(result);
}
/* Set the device state */
mem_device->state = MEMORY_POWER_ON_STATE;
printk(KERN_INFO "%s \n", acpi_device_name(device));
return_VALUE(result);
}
static int
acpi_memory_device_remove (struct acpi_device *device, int type)
{
struct acpi_memory_device *mem_device = NULL;
ACPI_FUNCTION_TRACE("acpi_memory_device_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
mem_device = (struct acpi_memory_device *) acpi_driver_data(device);
kfree(mem_device);
return_VALUE(0);
}
/*
* 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;
ACPI_FUNCTION_TRACE("is_memory_device");
status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(AE_ERROR);
info = buffer.pointer;
if (!(info->valid & ACPI_VALID_HID)) {
acpi_os_free(buffer.pointer);
return_ACPI_STATUS(AE_ERROR);
}
hardware_id = info->hardware_id.value;
if ((hardware_id == NULL) ||
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
status = AE_ERROR;
acpi_os_free(buffer.pointer);
return_ACPI_STATUS(status);
}
static acpi_status
acpi_memory_register_notify_handler (acpi_handle handle,
u32 level, void *ctxt, void **retv)
{
acpi_status status;
ACPI_FUNCTION_TRACE("acpi_memory_register_notify_handler");
status = is_memory_device(handle);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(AE_OK); /* continue */
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_memory_device_notify, NULL);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing notify handler\n"));
return_ACPI_STATUS(AE_OK); /* continue */
}
return_ACPI_STATUS(status);
}
static acpi_status
acpi_memory_deregister_notify_handler (acpi_handle handle,
u32 level, void *ctxt, void **retv)
{
acpi_status status;
ACPI_FUNCTION_TRACE("acpi_memory_deregister_notify_handler");
status = is_memory_device(handle);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(AE_OK); /* continue */
status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY, acpi_memory_device_notify);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error removing notify handler\n"));
return_ACPI_STATUS(AE_OK); /* continue */
}
return_ACPI_STATUS(status);
}
static int __init
acpi_memory_device_init (void)
{
int result;
acpi_status status;
ACPI_FUNCTION_TRACE("acpi_memory_device_init");
result = acpi_bus_register_driver(&acpi_memory_device_driver);
if (result < 0)
return_VALUE(-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_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed\n"));
acpi_bus_unregister_driver(&acpi_memory_device_driver);
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
static void __exit
acpi_memory_device_exit (void)
{
acpi_status status;
ACPI_FUNCTION_TRACE("acpi_memory_device_exit");
/*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed\n"));
acpi_bus_unregister_driver(&acpi_memory_device_driver);
return_VOID;
}
module_init(acpi_memory_device_init);
module_exit(acpi_memory_device_exit);

1236
drivers/acpi/asus_acpi.c Normal file

File diff suppressed because it is too large Load Diff

846
drivers/acpi/battery.c Normal file
View File

@@ -0,0 +1,846 @@
/*
* acpi_battery.c - ACPI Battery Driver ($Revision: 37 $)
*
* 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_DRIVER_NAME "ACPI Battery Driver"
#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 ("acpi_battery")
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
MODULE_LICENSE("GPL");
static int acpi_battery_add (struct acpi_device *device);
static int acpi_battery_remove (struct acpi_device *device, int type);
static struct acpi_driver acpi_battery_driver = {
.name = ACPI_BATTERY_DRIVER_NAME,
.class = ACPI_BATTERY_CLASS,
.ids = ACPI_BATTERY_HID,
.ops = {
.add = acpi_battery_add,
.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 {
acpi_handle handle;
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;
ACPI_FUNCTION_TRACE("acpi_battery_get_info");
if (!battery || !bif)
return_VALUE(-EINVAL);
/* Evalute _BIF */
status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n"));
return_VALUE(-ENODEV);
}
package = (union acpi_object *) buffer.pointer;
/* Extract Package Data */
status = acpi_extract_package(package, &format, &data);
if (status != AE_BUFFER_OVERFLOW) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
result = -ENODEV;
goto end;
}
data.pointer = kmalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
result = -ENOMEM;
goto end;
}
memset(data.pointer, 0, data.length);
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
kfree(data.pointer);
result = -ENODEV;
goto end;
}
end:
acpi_os_free(buffer.pointer);
if (!result)
(*bif) = (struct acpi_battery_info *) data.pointer;
return_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_battery_get_status");
if (!battery || !bst)
return_VALUE(-EINVAL);
/* Evalute _BST */
status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n"));
return_VALUE(-ENODEV);
}
package = (union acpi_object *) buffer.pointer;
/* Extract Package Data */
status = acpi_extract_package(package, &format, &data);
if (status != AE_BUFFER_OVERFLOW) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
result = -ENODEV;
goto end;
}
data.pointer = kmalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
result = -ENOMEM;
goto end;
}
memset(data.pointer, 0, data.length);
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
kfree(data.pointer);
result = -ENODEV;
goto end;
}
end:
acpi_os_free(buffer.pointer);
if (!result)
(*bst) = (struct acpi_battery_status *) data.pointer;
return_VALUE(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};
ACPI_FUNCTION_TRACE("acpi_battery_set_alarm");
if (!battery)
return_VALUE(-EINVAL);
if (!battery->flags.alarm)
return_VALUE(-ENODEV);
arg0.integer.value = alarm;
status = acpi_evaluate_object(battery->handle, "_BTP", &arg_list, NULL);
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
battery->alarm = alarm;
return_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_battery_check");
if (!battery)
return_VALUE(-EINVAL);
result = acpi_bus_get_device(battery->handle, &device);
if (result)
return_VALUE(result);
result = acpi_bus_get_status(device);
if (result)
return_VALUE(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_VALUE(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->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_VALUE(result);
}
/* --------------------------------------------------------------------------
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 = (struct acpi_battery *) seq->private;
struct acpi_battery_info *bif = NULL;
char *units = "?";
ACPI_FUNCTION_TRACE("acpi_battery_read_info");
if (!battery)
goto end;
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_VALUE(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 = (struct acpi_battery *) seq->private;
struct acpi_battery_status *bst = NULL;
char *units = "?";
ACPI_FUNCTION_TRACE("acpi_battery_read_state");
if (!battery)
goto end;
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");
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Battery Charging and 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_VALUE(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 = (struct acpi_battery *) seq->private;
char *units = "?";
ACPI_FUNCTION_TRACE("acpi_battery_read_alarm");
if (!battery)
goto end;
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_VALUE(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 = (struct seq_file *)file->private_data;
struct acpi_battery *battery = (struct acpi_battery *)m->private;
ACPI_FUNCTION_TRACE("acpi_battery_write_alarm");
if (!battery || (count > sizeof(alarm_string) - 1))
return_VALUE(-EINVAL);
if (!battery->flags.present)
return_VALUE(-ENODEV);
if (copy_from_user(alarm_string, buffer, count))
return_VALUE(-EFAULT);
alarm_string[count] = '\0';
result = acpi_battery_set_alarm(battery,
simple_strtoul(alarm_string, NULL, 0));
if (result)
return_VALUE(result);
return_VALUE(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 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 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 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;
ACPI_FUNCTION_TRACE("acpi_battery_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_battery_dir);
if (!acpi_device_dir(device))
return_VALUE(-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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_BATTERY_FILE_INFO));
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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_BATTERY_FILE_STATUS));
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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_BATTERY_FILE_ALARM));
else {
entry->proc_fops = &acpi_battery_alarm_ops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
return_VALUE(0);
}
static int
acpi_battery_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_battery_remove_fs");
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_VALUE(0);
}
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static void
acpi_battery_notify (
acpi_handle handle,
u32 event,
void *data)
{
struct acpi_battery *battery = (struct acpi_battery *) data;
struct acpi_device *device = NULL;
ACPI_FUNCTION_TRACE("acpi_battery_notify");
if (!battery)
return_VOID;
if (acpi_bus_get_device(handle, &device))
return_VOID;
switch (event) {
case ACPI_BATTERY_NOTIFY_STATUS:
case ACPI_BATTERY_NOTIFY_INFO:
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_VOID;
}
static int
acpi_battery_add (
struct acpi_device *device)
{
int result = 0;
acpi_status status = 0;
struct acpi_battery *battery = NULL;
ACPI_FUNCTION_TRACE("acpi_battery_add");
if (!device)
return_VALUE(-EINVAL);
battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
return_VALUE(-ENOMEM);
memset(battery, 0, sizeof(struct acpi_battery));
battery->handle = device->handle;
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(battery->handle,
ACPI_DEVICE_NOTIFY, acpi_battery_notify, battery);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing notify handler\n"));
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_VALUE(result);
}
static int
acpi_battery_remove (
struct acpi_device *device,
int type)
{
acpi_status status = 0;
struct acpi_battery *battery = NULL;
ACPI_FUNCTION_TRACE("acpi_battery_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
battery = (struct acpi_battery *) acpi_driver_data(device);
status = acpi_remove_notify_handler(battery->handle,
ACPI_DEVICE_NOTIFY, acpi_battery_notify);
if (ACPI_FAILURE(status))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error removing notify handler\n"));
acpi_battery_remove_fs(device);
kfree(battery);
return_VALUE(0);
}
static int __init
acpi_battery_init (void)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_battery_init");
acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
if (!acpi_battery_dir)
return_VALUE(-ENODEV);
acpi_battery_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_battery_driver);
if (result < 0) {
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
static void __exit
acpi_battery_exit (void)
{
ACPI_FUNCTION_TRACE("acpi_battery_exit");
acpi_bus_unregister_driver(&acpi_battery_driver);
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
return_VOID;
}
module_init(acpi_battery_init);
module_exit(acpi_battery_exit);

169
drivers/acpi/blacklist.c Normal file
View 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;
acpi_table_type 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_DSDT, less_than_or_equal, "Multiple problems", 1},
/* Sony FX120, FX140, FX150? */
{"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal, "ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
{"INT440", "SYSFexxx", 0x00001001, ACPI_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_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
{"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions, "Bogus PCI routing", 1},
{""}
};
#if CONFIG_ACPI_BLACKLIST_YEAR
static int __init
blacklist_by_year(void)
{
int year;
char *s = dmi_get_system_info(DMI_BIOS_DATE);
if (!s)
return 0;
if (!*s)
return 0;
s = strrchr(s, '/');
if (!s)
return 0;
s += 1;
year = simple_strtoul(s,NULL,0);
if (year < 100) { /* 2-digit year */
year += 1900;
if (year < 1996) /* no dates < spec 1.0 */
year += 100;
}
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_early(acpi_blacklist[i].table, &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;
}

775
drivers/acpi/bus.c Normal file
View File

@@ -0,0 +1,775 @@
/*
* acpi_bus.c - ACPI Bus Driver ($Revision: 80 $)
*
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* 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/list.h>
#include <linux/sched.h>
#include <linux/pm.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 ("acpi_bus")
#ifdef CONFIG_X86
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif
FADT_DESCRIPTOR acpi_fadt;
EXPORT_SYMBOL(acpi_fadt);
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;
ACPI_FUNCTION_TRACE("acpi_bus_get_device");
if (!device)
return_VALUE(-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_WARN, "No context for object [%p]\n",
handle));
return_VALUE(-ENODEV);
}
return_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_bus_get_status");
if (!device)
return_VALUE(-EINVAL);
/*
* Evaluate _STA if present.
*/
if (device->flags.dynamic_status) {
status = acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return_VALUE(-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_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_bus_get_power");
result = acpi_bus_get_device(handle, &device);
if (result)
return_VALUE(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_VALUE(-ENODEV);
device->power.state = (int) psc;
}
else if (device->power.flags.power_resources) {
result = acpi_power_get_inferred_state(device);
if (result)
return_VALUE(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_VALUE(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'};
ACPI_FUNCTION_TRACE("acpi_bus_set_power");
result = acpi_bus_get_device(handle, &device);
if (result)
return_VALUE(result);
if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
return_VALUE(-EINVAL);
/* Make sure this is a valid target state */
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n"));
return_VALUE(-ENODEV);
}
if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state));
return_VALUE(0);
}
if (!device->power.states[state].flags.valid) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", state));
return_VALUE(-ENODEV);
}
if (device->parent && (state < device->parent->power.state)) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Cannot set device to a higher-powered state than parent\n"));
return_VALUE(-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)
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error 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_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_bus_generate_event");
if (!device)
return_VALUE(-EINVAL);
/* drop event on the floor if no one's listening */
if (!event_is_open)
return_VALUE(0);
event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
if (!event)
return_VALUE(-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_VALUE(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);
ACPI_FUNCTION_TRACE("acpi_bus_receive_event");
if (!event)
return_VALUE(-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_VALUE(-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_VALUE(-ENODEV);
memcpy(event, entry, sizeof(struct acpi_bus_event));
kfree(entry);
return_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_bus_check_device");
if (!device)
return_VALUE(-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_VALUE(0);
}
status = acpi_bus_get_status(device);
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
return_VALUE(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_VALUE(0);
}
static int
acpi_bus_check_scope (
struct acpi_device *device)
{
int result = 0;
int status_changed = 0;
ACPI_FUNCTION_TRACE("acpi_bus_check_scope");
if (!device)
return_VALUE(-EINVAL);
/* Status Change? */
result = acpi_bus_check_device(device, &status_changed);
if (result)
return_VALUE(result);
if (!status_changed)
return_VALUE(0);
/*
* TBD: Enumerate child devices within this device's scope and
* run acpi_bus_check_device()'s on them.
*/
return_VALUE(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;
ACPI_FUNCTION_TRACE("acpi_bus_notify");
if (acpi_bus_get_device(handle, &device))
return_VOID;
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_VOID;
}
/* --------------------------------------------------------------------------
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;
ACPI_FUNCTION_TRACE("acpi_bus_init_irq");
/*
* 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;
default:
printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
return_VALUE(-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_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
void __init
acpi_early_init (void)
{
acpi_status status = AE_OK;
struct acpi_buffer buffer = {sizeof(acpi_fadt), &acpi_fadt};
ACPI_FUNCTION_TRACE("acpi_early_init");
if (acpi_disabled)
return_VOID;
/* enable workarounds, unless strict ACPI spec. compliance */
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
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;
}
/*
* Get a separate copy of the FADT for use by other drivers.
*/
status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "Unable to get the FADT\n");
goto error0;
}
#ifdef CONFIG_X86
if (!acpi_ioapic) {
extern acpi_interrupt_flags acpi_sci_flags;
/* compatible (0) means level (3) */
if (acpi_sci_flags.trigger == 0)
acpi_sci_flags.trigger = 3;
/* Set PIC-mode SCI trigger type */
acpi_pic_sci_set_trigger(acpi_fadt.sci_int, acpi_sci_flags.trigger);
} else {
extern int acpi_sci_override_gsi;
/*
* now that acpi_fadt is initialized,
* update it with result from INT_SRC_OVR parsing
*/
acpi_fadt.sci_int = 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_VOID;
error0:
disable_acpi();
return_VOID;
}
static int __init
acpi_bus_init (void)
{
int result = 0;
acpi_status status = AE_OK;
extern acpi_status acpi_os_initialize1(void);
ACPI_FUNCTION_TRACE("acpi_bus_init");
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");
/*
* 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_VALUE(0);
/* Mimic structured exception handling */
error1:
acpi_terminate();
return_VALUE(-ENODEV);
}
decl_subsys(acpi,NULL,NULL);
static int __init acpi_init (void)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_init");
printk(KERN_INFO PREFIX "Subsystem revision %08x\n",
ACPI_CA_VERSION);
if (acpi_disabled) {
printk(KERN_INFO PREFIX "Interpreter disabled.\n");
return_VALUE(-ENODEV);
}
firmware_register(&acpi_subsys);
result = acpi_bus_init();
if (!result) {
#ifdef CONFIG_PM
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_VALUE(result);
}
subsys_initcall(acpi_init);

558
drivers/acpi/button.c Normal file
View File

@@ -0,0 +1,558 @@
/*
* acpi_button.c - ACPI Button Driver ($Revision: 30 $)
*
* 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_BUTTON_COMPONENT 0x00080000
#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver"
#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 ("acpi_button")
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
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 = ACPI_BUTTON_DRIVER_NAME,
.class = ACPI_BUTTON_CLASS,
.ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
.ops = {
.add = acpi_button_add,
.remove = acpi_button_remove,
},
};
struct acpi_button {
acpi_handle handle;
struct acpi_device *device; /* Fixed button kludge */
u8 type;
unsigned long pushed;
};
static struct file_operations acpi_button_info_fops = {
.open = acpi_button_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static 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 = (struct acpi_button *) seq->private;
ACPI_FUNCTION_TRACE("acpi_button_info_seq_show");
if (!button || !button->device)
return_VALUE(0);
seq_printf(seq, "type: %s\n",
acpi_device_name(button->device));
return_VALUE(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 = (struct acpi_button *) seq->private;
acpi_status status;
unsigned long state;
ACPI_FUNCTION_TRACE("acpi_button_state_seq_show");
if (!button || !button->device)
return_VALUE(0);
status = acpi_evaluate_integer(button->handle,"_LID",NULL,&state);
if (ACPI_FAILURE(status)) {
seq_printf(seq, "state: unsupported\n");
}
else{
seq_printf(seq, "state: %s\n", (state ? "open" : "closed"));
}
return_VALUE(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 int
acpi_button_add_fs (
struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
struct acpi_button *button = NULL;
ACPI_FUNCTION_TRACE("acpi_button_add_fs");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
button = acpi_driver_data(device);
switch (button->type) {
case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
acpi_button_dir);
break;
case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
acpi_button_dir);
break;
case ACPI_BUTTON_TYPE_LID:
entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
acpi_button_dir);
break;
}
if (!entry)
return_VALUE(-ENODEV);
entry->owner = THIS_MODULE;
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
if (!acpi_device_dir(device))
return_VALUE(-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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_BUTTON_FILE_INFO));
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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_BUTTON_FILE_INFO));
else {
entry->proc_fops = &acpi_button_state_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
}
return_VALUE(0);
}
static int
acpi_button_remove_fs (
struct acpi_device *device)
{
struct acpi_button *button = NULL;
ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
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);
switch (button->type) {
case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER,
acpi_button_dir);
break;
case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP,
acpi_button_dir);
break;
case ACPI_BUTTON_TYPE_LID:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID,
acpi_button_dir);
break;
}
acpi_device_dir(device) = NULL;
}
return_VALUE(0);
}
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static void
acpi_button_notify (
acpi_handle handle,
u32 event,
void *data)
{
struct acpi_button *button = (struct acpi_button *) data;
ACPI_FUNCTION_TRACE("acpi_button_notify");
if (!button || !button->device)
return_VOID;
switch (event) {
case ACPI_BUTTON_NOTIFY_STATUS:
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_VOID;
}
static acpi_status
acpi_button_notify_fixed (
void *data)
{
struct acpi_button *button = (struct acpi_button *) data;
ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
if (!button)
return_ACPI_STATUS(AE_BAD_PARAMETER);
acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
return_ACPI_STATUS(AE_OK);
}
static int
acpi_button_add (
struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_button *button = NULL;
static struct acpi_device *power_button;
static struct acpi_device *sleep_button;
static struct acpi_device *lid_button;
ACPI_FUNCTION_TRACE("acpi_button_add");
if (!device)
return_VALUE(-EINVAL);
button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
if (!button)
return_VALUE(-ENOMEM);
memset(button, 0, sizeof(struct acpi_button));
button->device = device;
button->handle = device->handle;
acpi_driver_data(device) = 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 {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
acpi_device_hid(device)));
result = -ENODEV;
goto end;
}
/*
* Ensure only one button of each type is used.
*/
switch (button->type) {
case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
if (!power_button)
power_button = device;
else {
kfree(button);
return_VALUE(-ENODEV);
}
break;
case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
if (!sleep_button)
sleep_button = device;
else {
kfree(button);
return_VALUE(-ENODEV);
}
break;
case ACPI_BUTTON_TYPE_LID:
if (!lid_button)
lid_button = device;
else {
kfree(button);
return_VALUE(-ENODEV);
}
break;
}
result = acpi_button_add_fs(device);
if (result)
goto end;
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->handle,
ACPI_DEVICE_NOTIFY,
acpi_button_notify,
button);
break;
}
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing notify handler\n"));
result = -ENODEV;
goto end;
}
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));
end:
if (result) {
acpi_button_remove_fs(device);
kfree(button);
}
return_VALUE(result);
}
static int
acpi_button_remove (struct acpi_device *device, int type)
{
acpi_status status = 0;
struct acpi_button *button = NULL;
ACPI_FUNCTION_TRACE("acpi_button_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
button = acpi_driver_data(device);
/* Unregister for device notifications. */
switch (button->type) {
case ACPI_BUTTON_TYPE_POWERF:
status = acpi_remove_fixed_event_handler(
ACPI_EVENT_POWER_BUTTON, acpi_button_notify_fixed);
break;
case ACPI_BUTTON_TYPE_SLEEPF:
status = acpi_remove_fixed_event_handler(
ACPI_EVENT_SLEEP_BUTTON, acpi_button_notify_fixed);
break;
default:
status = acpi_remove_notify_handler(button->handle,
ACPI_DEVICE_NOTIFY, acpi_button_notify);
break;
}
if (ACPI_FAILURE(status))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error removing notify handler\n"));
acpi_button_remove_fs(device);
kfree(button);
return_VALUE(0);
}
static int __init
acpi_button_init (void)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_button_init");
acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
if (!acpi_button_dir)
return_VALUE(-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_VALUE(-ENODEV);
}
return_VALUE(0);
}
static void __exit
acpi_button_exit (void)
{
ACPI_FUNCTION_TRACE("acpi_button_exit");
acpi_bus_unregister_driver(&acpi_button_driver);
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
return_VOID;
}
module_init(acpi_button_init);
module_exit(acpi_button_exit);

303
drivers/acpi/container.c Normal file
View File

@@ -0,0 +1,303 @@
/*
* 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_DRIVER_NAME "ACPI container driver"
#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 ("acpi_container")
MODULE_AUTHOR("Anil S Keshavamurthy");
MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME);
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 = ACPI_CONTAINER_DRIVER_NAME,
.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;
ACPI_FUNCTION_TRACE("is_device_present");
status = acpi_get_handle(handle, "_STA", &temp);
if (ACPI_FAILURE(status))
return_VALUE(1); /* _STA not found, assmue device present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return_VALUE(0); /* Firmware error */
return_VALUE((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
}
/*******************************************************************/
static int
acpi_container_add(struct acpi_device *device)
{
struct acpi_container *container;
ACPI_FUNCTION_TRACE("acpi_container_add");
if (!device) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "device is NULL\n"));
return_VALUE(-EINVAL);
}
container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
if(!container)
return_VALUE(-ENOMEM);
memset(container, 0, sizeof(struct acpi_container));
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_VALUE(0);
}
static int
acpi_container_remove(struct acpi_device *device, int type)
{
acpi_status status = AE_OK;
struct acpi_container *pc = NULL;
pc = (struct acpi_container*) acpi_driver_data(device);
if (pc)
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;
ACPI_FUNCTION_TRACE("container_device_add");
if (acpi_get_parent(handle, &phandle)) {
return_VALUE(-ENODEV);
}
if (acpi_bus_get_device(phandle, &pdev)) {
return_VALUE(-ENODEV);
}
if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
return_VALUE(-ENODEV);
}
result = acpi_bus_scan(*device);
return_VALUE(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;
ACPI_FUNCTION_TRACE("container_notify_cb");
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_hotplug(&device->kobj,
KOBJ_ONLINE);
else
printk("Failed to add container\n");
}
} else {
if (ACPI_SUCCESS(status)) {
/* device exist and this is a remove request */
kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
}
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
}
break;
default:
break;
}
return_VOID;
}
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;
ACPI_FUNCTION_TRACE("container_walk_namespace_cb");
status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status) || !buffer.pointer) {
return_ACPI_STATUS(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:
acpi_os_free(buffer.pointer);
return_ACPI_STATUS(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_FUNCTION_TRACE("acpi_container_exit");
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_VOID;
}
module_init(acpi_container_init);
module_exit(acpi_container_exit);

233
drivers/acpi/debug.c Normal file
View File

@@ -0,0 +1,233 @@
/*
* 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")
#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
#define MODULE_PARAM_PREFIX
module_param(acpi_dbg_layer, uint, 0400);
module_param(acpi_dbg_level, uint, 0400);
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),
};
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'};
ACPI_FUNCTION_TRACE("acpi_system_write_debug");
if (count > sizeof(debug_string) - 1)
return_VALUE(-EINVAL);
if (copy_from_user(debug_string, buffer, count))
return_VALUE(-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_VALUE(-EINVAL);
}
return_VALUE(count);
}
static int __init acpi_debug_init(void)
{
struct proc_dir_entry *entry;
int error = 0;
char * name;
ACPI_FUNCTION_TRACE("acpi_debug_init");
if (acpi_disabled)
return_VALUE(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_VALUE(error);
Error:
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' proc fs entry\n", name));
remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir);
error = -EFAULT;
goto Done;
}
subsys_initcall(acpi_debug_init);

View 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)

View File

@@ -0,0 +1,601 @@
/******************************************************************************
*
* Module Name: dsfield - Dispatcher field routines
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* FUNCTION: acpi_ds_create_buffer_field
*
* PARAMETERS: Opcode - The opcode to be executed
* Operands - List of operands for the opcode
* 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 fields in buffers)
*
******************************************************************************/
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_REPORT_NSERROR (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.
*
******************************************************************************/
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_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n"));
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_REPORT_NSERROR ((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_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n",
(char *) &info->field_node->name));
return_ACPI_STATUS (AE_SUPPORT);
}
info->field_bit_position += info->field_bit_length;
break;
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n",
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, &region_node);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR (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_REPORT_NSERROR ((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, &region_node);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR (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_REPORT_NSERROR (arg->common.value.string, status);
return_ACPI_STATUS (status);
}
/* Third arg is the bank_value */
arg = arg->common.next;
info.bank_value = (u32) arg->common.value.integer;
/* 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_REPORT_NSERROR (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_REPORT_NSERROR (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);
}

View File

@@ -0,0 +1,235 @@
/******************************************************************************
*
* Module Name: dsinit - Object initialization namespace walk
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsinit")
/*******************************************************************************
*
* FUNCTION: acpi_ds_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) Operation Regions
*
******************************************************************************/
acpi_status
acpi_ds_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;
ACPI_FUNCTION_NAME ("ds_init_one_object");
/*
* We are only interested in objects owned by the table that
* was just loaded
*/
if (((struct acpi_namespace_node *) obj_handle)->owner_id !=
info->table_desc->table_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_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n",
obj_handle, acpi_ut_get_node_name (obj_handle),
acpi_format_exception (status)));
}
info->op_region_count++;
break;
case ACPI_TYPE_METHOD:
info->method_count++;
/* Print a dot for each method unless we are going to print the entire pathname */
if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
}
/*
* Set the execution data width (32 or 64) based upon the
* revision number of the parent ACPI table.
* TBD: This is really for possible future support of integer width
* on a per-table basis. Currently, we just use a global for the width.
*/
if (info->table_desc->pointer->revision == 1) {
((struct acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32;
}
/*
* Always parse methods to detect errors, we will delete
* the parse tree below
*/
status = acpi_ds_parse_method (obj_handle);
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n",
obj_handle, acpi_ut_get_node_name (obj_handle),
acpi_format_exception (status)));
/* This parse failed, but we will continue parsing more methods */
break;
}
/*
* Delete the parse tree. We simply re-parse the method
* for every execution since there isn't much overhead
*/
acpi_ns_delete_namespace_subtree (obj_handle);
acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id);
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 "start_node" and perform any
* necessary initialization on the objects found therein
*
******************************************************************************/
acpi_status
acpi_ds_initialize_objects (
struct acpi_table_desc *table_desc,
struct acpi_namespace_node *start_node)
{
acpi_status status;
struct acpi_init_walk_info info;
ACPI_FUNCTION_TRACE ("ds_initialize_objects");
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_desc = table_desc;
/* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed, %s\n",
acpi_format_exception (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_desc->pointer->signature, table_desc->table_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);
}

View File

@@ -0,0 +1,597 @@
/******************************************************************************
*
* Module Name: dsmethod - Parser/Interpreter interface - control method parsing
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsmethod")
/*******************************************************************************
*
* FUNCTION: acpi_ds_parse_method
*
* PARAMETERS: obj_handle - Method node
*
* RETURN: Status
*
* DESCRIPTION: Call the parser and parse the AML that is associated with the
* method.
*
* MUTEX: Assumes parser is locked
*
******************************************************************************/
acpi_status
acpi_ds_parse_method (
acpi_handle obj_handle)
{
acpi_status status;
union acpi_operand_object *obj_desc;
union acpi_parse_object *op;
struct acpi_namespace_node *node;
acpi_owner_id owner_id;
struct acpi_walk_state *walk_state;
ACPI_FUNCTION_TRACE_PTR ("ds_parse_method", obj_handle);
/* Parameter Validation */
if (!obj_handle) {
return_ACPI_STATUS (AE_NULL_ENTRY);
}
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n",
acpi_ut_get_node_name (obj_handle), obj_handle));
/* Extract the method object from the method Node */
node = (struct acpi_namespace_node *) obj_handle;
obj_desc = acpi_ns_get_attached_object (node);
if (!obj_desc) {
return_ACPI_STATUS (AE_NULL_OBJECT);
}
/* Create a mutex for the method if there is a concurrency limit */
if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
(!obj_desc->method.semaphore)) {
status = acpi_os_create_semaphore (obj_desc->method.concurrency,
obj_desc->method.concurrency,
&obj_desc->method.semaphore);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
/*
* Allocate a new parser op to be the root of the parsed
* method tree
*/
op = acpi_ps_alloc_op (AML_METHOD_OP);
if (!op) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/* Init new op with the method name and pointer back to the Node */
acpi_ps_set_name (op, node->name.integer);
op->common.node = node;
/*
* Get a new owner_id for objects created by this method. Namespace
* objects (such as Operation Regions) can be created during the
* first pass parse.
*/
owner_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
obj_desc->method.owning_id = owner_id;
/* Create and initialize a new walk state */
walk_state = acpi_ds_create_walk_state (owner_id, NULL, NULL, NULL);
if (!walk_state) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
status = acpi_ds_init_aml_walk (walk_state, op, node,
obj_desc->method.aml_start,
obj_desc->method.aml_length, NULL, 1);
if (ACPI_FAILURE (status)) {
acpi_ds_delete_walk_state (walk_state);
return_ACPI_STATUS (status);
}
/*
* Parse the method, first pass
*
* The first pass load is where newly declared named objects are
* added into the namespace. Actual evaluation of
* the named objects (what would be called a "second
* pass") happens during the actual execution of the
* method so that operands to the named objects can
* take on dynamic run-time values.
*/
status = acpi_ps_parse_aml (walk_state);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
"**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
acpi_ut_get_node_name (obj_handle), obj_handle, op));
acpi_ps_delete_parse_tree (op);
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ds_begin_method_execution
*
* PARAMETERS: method_node - Node of the method
* obj_desc - The method object
* calling_method_node - Caller of this method (if non-null)
*
* 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_namespace_node *calling_method_node)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE_PTR ("ds_begin_method_execution", method_node);
if (!method_node) {
return_ACPI_STATUS (AE_NULL_ENTRY);
}
/*
* If there is a concurrency limit on this method, we need to
* obtain a unit from the method semaphore.
*/
if (obj_desc->method.semaphore) {
/*
* Allow recursive method calls, up to the reentrancy/concurrency
* limit imposed by the SERIALIZED rule and the sync_level method
* parameter.
*
* The point of this code is to avoid permanently blocking a
* thread that is making recursive method calls.
*/
if (method_node == calling_method_node) {
if (obj_desc->method.thread_count >= obj_desc->method.concurrency) {
return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
}
}
/*
* Get a unit from the method semaphore. This releases the
* interpreter if we block
*/
status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore,
ACPI_WAIT_FOREVER);
}
/*
* 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);
}
/*******************************************************************************
*
* 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;
union acpi_operand_object *obj_desc;
struct acpi_parameter_info info;
u32 i;
ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state);
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute 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);
}
obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
/* Init for new method, wait on concurrency semaphore */
status = acpi_ds_begin_method_execution (method_node, obj_desc,
this_walk_state->method_node);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
/* 1) Parse: Create a new walk state for the preempting walk */
next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
op, obj_desc, NULL);
if (!next_walk_state) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/* Create and init a Root Node */
op = acpi_ps_create_scope_op ();
if (!op) {
status = AE_NO_MEMORY;
goto cleanup;
}
status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
obj_desc->method.aml_start, obj_desc->method.aml_length,
NULL, 1);
if (ACPI_FAILURE (status)) {
acpi_ds_delete_walk_state (next_walk_state);
goto cleanup;
}
/* Begin AML parse */
status = acpi_ps_parse_aml (next_walk_state);
acpi_ps_delete_parse_tree (op);
}
/* 2) Execute: Create a new state for the preempting walk */
next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_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.
* Null terminate the list of arguments
*/
this_walk_state->operands [this_walk_state->num_operands] = NULL;
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, 3);
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,
"Starting nested execution, newstate=%p\n", next_walk_state));
if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
status = obj_desc->method.implementation (next_walk_state);
return_ACPI_STATUS (status);
}
return_ACPI_STATUS (AE_OK);
/* On error, we must delete the new walk state */
cleanup:
if (next_walk_state && (next_walk_state->method_desc)) {
/* Decrement the thread count on the method parse tree */
next_walk_state->method_desc->method.thread_count--;
}
(void) acpi_ds_terminate_control_method (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;
ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state);
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"****Restart [%4.4s] Op %p return_value_from_callee %p\n",
(char *) &walk_state->method_node->name, walk_state->method_call_op,
return_desc));
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
" return_from_this_method_used?=%X res_stack %p Walk %p\n",
walk_state->return_used,
walk_state->results, walk_state));
/* Did the called method return a value? */
if (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 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.
*/
else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) {
/*
* Delete the return value if it will not be used by the
* calling method
*/
acpi_ut_remove_reference (return_desc);
}
}
return_ACPI_STATUS (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ds_terminate_control_method
*
* PARAMETERS: walk_state - State of the method
*
* RETURN: Status
*
* DESCRIPTION: Terminate a control method. Delete everything that the method
* created, delete all locals and arguments, and delete the parse
* tree if requested.
*
******************************************************************************/
acpi_status
acpi_ds_terminate_control_method (
struct acpi_walk_state *walk_state)
{
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *method_node;
acpi_status status;
ACPI_FUNCTION_TRACE_PTR ("ds_terminate_control_method", walk_state);
if (!walk_state) {
return (AE_BAD_PARAMETER);
}
/* The current method object was saved in the walk state */
obj_desc = walk_state->method_desc;
if (!obj_desc) {
return_ACPI_STATUS (AE_OK);
}
/* Delete all arguments and locals */
acpi_ds_method_data_delete_all (walk_state);
/*
* Lock the parser while we terminate this method.
* If this is the last thread executing the method,
* we have additional cleanup to perform
*/
status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* Signal completion of the execution of this method if necessary */
if (walk_state->method_desc->method.semaphore) {
status = acpi_os_signal_semaphore (
walk_state->method_desc->method.semaphore, 1);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Could not signal method semaphore\n"));
status = AE_OK;
/* Ignore error and continue cleanup */
}
}
if (walk_state->method_desc->method.thread_count) {
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"*** Not deleting method namespace, there are still %d threads\n",
walk_state->method_desc->method.thread_count));
}
if (!walk_state->method_desc->method.thread_count) {
/*
* Support to dynamically change a method from not_serialized to
* Serialized if it appears that the method is written foolishly 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 ((walk_state->method_desc->method.concurrency == 1) &&
(!walk_state->method_desc->method.semaphore)) {
status = acpi_os_create_semaphore (1,
1,
&walk_state->method_desc->method.semaphore);
}
/*
* There are no more threads executing this method. Perform
* additional cleanup.
*
* The method Node is stored in the walk state
*/
method_node = walk_state->method_node;
/*
* Delete any namespace entries created immediately underneath
* the method
*/
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
if (method_node->child) {
acpi_ns_delete_namespace_subtree (method_node);
}
/*
* Delete any namespace entries created anywhere else within
* the namespace
*/
acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id);
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
status = acpi_ut_release_mutex (ACPI_MTX_PARSER);
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,715 @@
/*******************************************************************************
*
* Module Name: dsmthdat - control method arguments and local variables
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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 NTEs 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_MEM_CALLOCATE().
*
* 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 = 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 = 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_var or argument whose type
* to get
* walk_state - Current walk state object
*
* RETURN: 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", 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_var or argument 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.
*
******************************************************************************/
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,
"new_obj %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_type
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
* Index - which local_var or argument whose type
* to get
* walk_state - Current walk state object
*
* RETURN: Data type of current value of the selected Arg or Local
*
******************************************************************************/
#ifdef ACPI_FUTURE_USAGE
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 /* ACPI_FUTURE_USAGE */
/*******************************************************************************
*
* 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 - Ptr to Descriptor into which selected Arg
* or Local value should be copied
*
* RETURN: Status
*
* DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
* at the current top of the method stack.
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Null object descriptor pointer\n"));
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n",
index, node));
return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG);
case AML_LOCAL_OP:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n",
index, node));
return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL);
default:
ACPI_REPORT_ERROR (("Not Arg/Local opcode: %X\n", 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 on the method stack. Inserts
* a null into the stack slot after the object is deleted.
*
******************************************************************************/
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_var or argument 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) {
/*
* Make sure that the object is the correct type. This may be overkill, but
* it is here because references were NS nodes in the past. Now they are
* operand objects of type Reference.
*/
if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) {
ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n",
acpi_ut_get_descriptor_name (current_obj_desc)));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
/*
* If we have a valid reference object that came from ref_of(), do the
* indirect store
*/
if ((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 obj_ref(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);
}

View File

@@ -0,0 +1,618 @@
/******************************************************************************
*
* Module Name: dsobject - Dispatcher object management routines
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
#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!
*
****************************************************************************/
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 an 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,
(struct acpi_namespace_node **) &(op->common.node));
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR (op->common.value.string, status);
return_ACPI_STATUS (status);
}
}
}
/* Create and init the 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");
obj_desc = *obj_desc_ptr;
if (obj_desc) {
/*
* We are evaluating a Named buffer object "Name (xxxx, Buffer)".
* The buffer object already exists (from the NS node)
*/
}
else {
/* 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Expecting bytelist, got AML opcode %X in op %p\n",
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_MEM_CALLOCATE (
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 = (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
* package_length - Number of elements in the 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
*
****************************************************************************/
acpi_status
acpi_ds_build_internal_package_obj (
struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
u32 package_length,
union acpi_operand_object **obj_desc_ptr)
{
union acpi_parse_object *arg;
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
u32 package_list_length;
acpi_status status = AE_OK;
u32 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;
}
obj_desc = *obj_desc_ptr;
if (obj_desc) {
/*
* We are evaluating a Named package object "Name (xxxx, Package)".
* Get the existing package object from the NS node
*/
}
else {
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;
}
obj_desc->package.count = package_length;
/* Count the number of items in the package list */
package_list_length = 0;
arg = op->common.value.arg;
arg = arg->common.next;
while (arg) {
package_list_length++;
arg = arg->common.next;
}
/*
* The package length (number of elements) will be the greater
* of the specified length and the length of the initializer list
*/
if (package_list_length > package_length) {
obj_desc->package.count = package_list_length;
}
/*
* Allocate the pointer array (array of pointers to the
* individual objects). Add an extra pointer slot so
* that the list is always null terminated.
*/
obj_desc->package.elements = ACPI_MEM_CALLOCATE (
((acpi_size) obj_desc->package.count + 1) * sizeof (void *));
if (!obj_desc->package.elements) {
acpi_ut_delete_object_desc (obj_desc);
return_ACPI_STATUS (AE_NO_MEMORY);
}
/*
* Now init the elements of the package
*/
i = 0;
arg = op->common.value.arg;
arg = arg->common.next;
while (arg) {
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
/* Object (package or buffer) is already built */
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]);
}
i++;
arg = arg->common.next;
}
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
op->common.node = (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 = (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 = (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_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode));
status = AE_AML_OPERAND_TYPE;
break;
}
break;
case AML_TYPE_LITERAL:
obj_desc->integer.value = op->common.value.integer;
break;
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n",
ACPI_GET_OBJECT_TYPE (obj_desc)));
status = AE_AML_OPERAND_TYPE;
break;
}
return_ACPI_STATUS (status);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,744 @@
/*******************************************************************************
*
* Module Name: dsutils - Dispatcher utilities
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n"));
return_VALUE (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.
*/
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_VALUE (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_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op));
return_VALUE (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_VALUE (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_VALUE (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_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n"));
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 != 0)) {
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_REPORT_NSERROR (name_string, status);
}
}
/* Free the namestring created above */
ACPI_MEM_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_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n",
acpi_format_exception (status)));
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_DEBUG_PRINT ((ACPI_DB_ERROR, "While creating Arg %d - %s\n",
(arg_count + 1), acpi_format_exception (status)));
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,751 @@
/******************************************************************************
*
* Module Name: dswexec - Dispatcher method execution callbacks;
* dispatch to interpreter.
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#include <acpi/acdisasm.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
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not get result from predicate evaluation, %s\n",
acpi_format_exception (status)));
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_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Bad predicate (not an integer) obj_desc=%p State=%p Type=%X\n",
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 - 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)) {
return_ACPI_STATUS (status);
}
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)) {
return_ACPI_STATUS (status);
}
}
}
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)) {
return_ACPI_STATUS (status);
}
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.
* Start a new result/operand state
*/
status = acpi_ds_result_stack_push (walk_state);
break;
default:
break;
}
/* Nothing to do here during method execution */
return_ACPI_STATUS (status);
}
/*****************************************************************************
*
* FUNCTION: acpi_ds_exec_end_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
* Op - Op that has been just been completed in the
* walk; Arguments have now been evaluated.
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode %X\n", 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 ex_resolve_operands");
}
}
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(local_x,local_x)" 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"[%s]: Could not resolve operands, %s\n",
acpi_ps_get_opcode_name (walk_state->opcode),
acpi_format_exception (status)));
}
}
/* 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 create_field 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 create_object (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 this 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 (ACPI_SUCCESS (status) &&
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 op_region 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Unimplemented opcode, class=%X type=%X Opcode=%X Op=%p\n",
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:
/* Invoke exception handler on error */
if (ACPI_FAILURE (status) &&
acpi_gbl_exception_handler &&
!(status & AE_CODE_CONTROL)) {
acpi_ex_exit_interpreter ();
status = acpi_gbl_exception_handler (status,
walk_state->method_node->name.integer, walk_state->opcode,
walk_state->aml_offset, NULL);
acpi_ex_enter_interpreter ();
}
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
/* Always clear the object stack */
walk_state->num_operands = 0;
#ifdef ACPI_DISASSEMBLER
/* On error, display method locals/args */
if (ACPI_FAILURE (status)) {
acpi_dm_dump_method_info (status, walk_state, op);
}
#endif
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,976 @@
/******************************************************************************
*
* Module Name: dswload - Dispatcher namespace load callbacks
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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/acevents.h>
#ifdef _ACPI_ASL_COMPILER
#include <acpi/acdisasm.h>
#endif
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dswload")
/*******************************************************************************
*
* FUNCTION: acpi_ds_init_callbacks
*
* PARAMETERS: walk_state - Current state of the parse tree walk
* pass_number - 1, 2, or 3
*
* RETURN: Status
*
* DESCRIPTION: Init walk state callbacks
*
******************************************************************************/
acpi_status
acpi_ds_init_callbacks (
struct acpi_walk_state *walk_state,
u32 pass_number)
{
switch (pass_number) {
case 1:
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load1_begin_op;
walk_state->ascending_callback = acpi_ds_load1_end_op;
break;
case 2:
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load2_begin_op;
walk_state->ascending_callback = acpi_ds_load2_end_op;
break;
case 3:
#ifndef ACPI_NO_METHOD_EXECUTION
walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_exec_begin_op;
walk_state->ascending_callback = acpi_ds_exec_end_op;
#endif
break;
default:
return (AE_BAD_PARAMETER);
}
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ds_load1_begin_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
* Op - Op that has been just been reached in the
* walk; Arguments have not been evaluated yet.
*
* RETURN: Status
*
* DESCRIPTION: Descending callback used during the loading of ACPI tables.
*
******************************************************************************/
acpi_status
acpi_ds_load1_begin_op (
struct acpi_walk_state *walk_state,
union acpi_parse_object **out_op)
{
union acpi_parse_object *op;
struct acpi_namespace_node *node;
acpi_status status;
acpi_object_type object_type;
char *path;
u32 flags;
ACPI_FUNCTION_NAME ("ds_load1_begin_op");
op = walk_state->op;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));
/* We are only interested in opcodes that have an associated name */
if (op) {
if (!(walk_state->op_info->flags & AML_NAMED)) {
#if 0
if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
(walk_state->op_info->class == AML_CLASS_CONTROL)) {
acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name);
*out_op = op;
return (AE_CTRL_SKIP);
}
#endif
*out_op = op;
return (AE_OK);
}
/* Check if this object has already been installed in the namespace */
if (op->common.node) {
*out_op = op;
return (AE_OK);
}
}
path = acpi_ps_get_next_namestring (&walk_state->parser_state);
/* Map the raw opcode into an internal object type */
object_type = walk_state->op_info->object_type;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"State=%p Op=%p [%s]\n", walk_state, op, acpi_ut_get_type_name (object_type)));
switch (walk_state->opcode) {
case AML_SCOPE_OP:
/*
* The target name of the Scope() operator must exist at this point so
* that we can actually open the scope to enter new names underneath it.
* Allow search-to-root for single namesegs.
*/
status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
#ifdef _ACPI_ASL_COMPILER
if (status == AE_NOT_FOUND) {
/*
* Table disassembly:
* Target of Scope() not found. Generate an External for it, and
* insert the name into the namespace.
*/
acpi_dm_add_to_external_list (path);
status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
}
#endif
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR (path, status);
return (status);
}
/*
* Check to make sure that the target is
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL:
/* These are acceptable types */
break;
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
/*
* These types we will allow, but we will change the type. This
* enables some existing code of the form:
*
* Name (DEB, 0)
* Scope (DEB) { ... }
*
* Note: silently change the type here. On the second pass, we will report a warning
*/
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
path, acpi_ut_get_type_name (node->type)));
node->type = ACPI_TYPE_ANY;
walk_state->scope_info->common.value = ACPI_TYPE_ANY;
break;
default:
/* All other types are an error */
ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n",
acpi_ut_get_type_name (node->type), path));
return (AE_AML_OPERAND_TYPE);
}
break;
default:
/*
* For all other named opcodes, we will enter the name into the namespace.
*
* Setup the search flags.
* Since we are entering a name into the namespace, we do not want to
* enable the search-to-root upsearch.
*
* There are only two conditions where it is acceptable that the name
* already exists:
* 1) the Scope() operator can reopen a scoping object that was
* previously defined (Scope, Method, Device, etc.)
* 2) Whenever we are parsing a deferred opcode (op_region, Buffer,
* buffer_field, or Package), the name of the object is already
* in the namespace.
*/
if (walk_state->deferred_node) {
/* This name is already in the namespace, get the node */
node = walk_state->deferred_node;
status = AE_OK;
break;
}
flags = ACPI_NS_NO_UPSEARCH;
if ((walk_state->opcode != AML_SCOPE_OP) &&
(!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) {
flags |= ACPI_NS_ERROR_IF_FOUND;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n",
acpi_ut_get_type_name (object_type)));
}
else {
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n",
acpi_ut_get_type_name (object_type)));
}
/*
* Enter the named type into the internal namespace. We enter the name
* as we go downward in the parse tree. Any necessary subobjects that involve
* arguments to the opcode must be created as we go back up the parse tree later.
*/
status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node));
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR (path, status);
return (status);
}
break;
}
/* Common exit */
if (!op) {
/* Create a new op */
op = acpi_ps_alloc_op (walk_state->opcode);
if (!op) {
return (AE_NO_MEMORY);
}
}
/* Initialize */
op->named.name = node->name.integer;
#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY))
op->named.path = (u8 *) path;
#endif
/*
* Put the Node in the "op" object that the parser uses, so we
* can get it again quickly when this scope is closed
*/
op->common.node = node;
acpi_ps_append_arg (acpi_ps_get_parent_scope (&walk_state->parser_state), op);
*out_op = op;
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ds_load1_end_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
* Op - Op that has been just been completed in the
* walk; Arguments have now been evaluated.
*
* RETURN: Status
*
* DESCRIPTION: Ascending callback used during the loading of the namespace,
* both control methods and everything else.
*
******************************************************************************/
acpi_status
acpi_ds_load1_end_op (
struct acpi_walk_state *walk_state)
{
union acpi_parse_object *op;
acpi_object_type object_type;
acpi_status status = AE_OK;
ACPI_FUNCTION_NAME ("ds_load1_end_op");
op = walk_state->op;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));
/* We are only interested in opcodes that have an associated name */
if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) {
return (AE_OK);
}
/* Get the object type to determine if we should pop the scope */
object_type = walk_state->op_info->object_type;
#ifndef ACPI_NO_METHOD_EXECUTION
if (walk_state->op_info->flags & AML_FIELD) {
if (walk_state->opcode == AML_FIELD_OP ||
walk_state->opcode == AML_BANK_FIELD_OP ||
walk_state->opcode == AML_INDEX_FIELD_OP) {
status = acpi_ds_init_field_objects (op, walk_state);
}
return (status);
}
if (op->common.aml_opcode == AML_REGION_OP) {
status = acpi_ex_create_region (op->named.data, op->named.length,
(acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state);
if (ACPI_FAILURE (status)) {
return (status);
}
}
#endif
if (op->common.aml_opcode == AML_NAME_OP) {
/* For Name opcode, get the object type from the argument */
if (op->common.value.arg) {
object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type;
op->common.node->type = (u8) object_type;
}
}
if (op->common.aml_opcode == AML_METHOD_OP) {
/*
* method_op pkg_length name_string method_flags term_list
*
* Note: We must create the method node/object pair as soon as we
* see the method declaration. This allows later pass1 parsing
* of invocations of the method (need to know the number of
* arguments.)
*/
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"LOADING-Method: State=%p Op=%p named_obj=%p\n",
walk_state, op, op->named.node));
if (!acpi_ns_get_attached_object (op->named.node)) {
walk_state->operands[0] = (void *) op->named.node;
walk_state->num_operands = 1;
status = acpi_ds_create_operands (walk_state, op->common.value.arg);
if (ACPI_SUCCESS (status)) {
status = acpi_ex_create_method (op->named.data,
op->named.length, walk_state);
}
walk_state->operands[0] = NULL;
walk_state->num_operands = 0;
if (ACPI_FAILURE (status)) {
return (status);
}
}
}
/* Pop the scope stack */
if (acpi_ns_opens_scope (object_type)) {
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n",
acpi_ut_get_type_name (object_type), op));
status = acpi_ds_scope_stack_pop (walk_state);
}
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ds_load2_begin_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
* Op - Op that has been just been reached in the
* walk; Arguments have not been evaluated yet.
*
* RETURN: Status
*
* DESCRIPTION: Descending callback used during the loading of ACPI tables.
*
******************************************************************************/
acpi_status
acpi_ds_load2_begin_op (
struct acpi_walk_state *walk_state,
union acpi_parse_object **out_op)
{
union acpi_parse_object *op;
struct acpi_namespace_node *node;
acpi_status status;
acpi_object_type object_type;
char *buffer_ptr;
ACPI_FUNCTION_TRACE ("ds_load2_begin_op");
op = walk_state->op;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));
if (op) {
/* We only care about Namespace opcodes here */
if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
(!(walk_state->op_info->flags & AML_NAMED))) {
return_ACPI_STATUS (AE_OK);
}
/*
* Get the name we are going to enter or lookup in the namespace
*/
if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
/* For Namepath op, get the path string */
buffer_ptr = op->common.value.string;
if (!buffer_ptr) {
/* No name, just exit */
return_ACPI_STATUS (AE_OK);
}
}
else {
/* Get name from the op */
buffer_ptr = (char *) &op->named.name;
}
}
else {
/* Get the namestring from the raw AML */
buffer_ptr = acpi_ps_get_next_namestring (&walk_state->parser_state);
}
/* Map the opcode into an internal object type */
object_type = walk_state->op_info->object_type;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"State=%p Op=%p Type=%X\n", walk_state, op, object_type));
switch (walk_state->opcode) {
case AML_FIELD_OP:
case AML_BANK_FIELD_OP:
case AML_INDEX_FIELD_OP:
node = NULL;
status = AE_OK;
break;
case AML_INT_NAMEPATH_OP:
/*
* The name_path is an object reference to an existing object. Don't enter the
* name into the namespace, but look it up for use later
*/
status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
break;
case AML_SCOPE_OP:
/*
* The Path is an object reference to an existing object. Don't enter the
* name into the namespace, but look it up for use later
*/
status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
if (ACPI_FAILURE (status)) {
#ifdef _ACPI_ASL_COMPILER
if (status == AE_NOT_FOUND) {
status = AE_OK;
}
else {
ACPI_REPORT_NSERROR (buffer_ptr, status);
}
#else
ACPI_REPORT_NSERROR (buffer_ptr, status);
#endif
return_ACPI_STATUS (status);
}
/*
* We must check to make sure that the target is
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL:
/* These are acceptable types */
break;
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
/*
* These types we will allow, but we will change the type. This
* enables some existing code of the form:
*
* Name (DEB, 0)
* Scope (DEB) { ... }
*/
ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
buffer_ptr, acpi_ut_get_type_name (node->type)));
node->type = ACPI_TYPE_ANY;
walk_state->scope_info->common.value = ACPI_TYPE_ANY;
break;
default:
/* All other types are an error */
ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
acpi_ut_get_type_name (node->type), buffer_ptr));
return (AE_AML_OPERAND_TYPE);
}
break;
default:
/* All other opcodes */
if (op && op->common.node) {
/* This op/node was previously entered into the namespace */
node = op->common.node;
if (acpi_ns_opens_scope (object_type)) {
status = acpi_ds_scope_stack_push (node, object_type, walk_state);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
return_ACPI_STATUS (AE_OK);
}
/*
* Enter the named type into the internal namespace. We enter the name
* as we go downward in the parse tree. Any necessary subobjects that involve
* arguments to the opcode must be created as we go back up the parse tree later.
*
* Note: Name may already exist if we are executing a deferred opcode.
*/
if (walk_state->deferred_node) {
/* This name is already in the namespace, get the node */
node = walk_state->deferred_node;
status = AE_OK;
break;
}
status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node));
break;
}
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR (buffer_ptr, status);
return_ACPI_STATUS (status);
}
if (!op) {
/* Create a new op */
op = acpi_ps_alloc_op (walk_state->opcode);
if (!op) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/* Initialize the new op */
if (node) {
op->named.name = node->name.integer;
}
if (out_op) {
*out_op = op;
}
}
/*
* Put the Node in the "op" object that the parser uses, so we
* can get it again quickly when this scope is closed
*/
op->common.node = node;
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ds_load2_end_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
* Op - Op that has been just been completed in the
* walk; Arguments have now been evaluated.
*
* RETURN: Status
*
* DESCRIPTION: Ascending callback used during the loading of the namespace,
* both control methods and everything else.
*
******************************************************************************/
acpi_status
acpi_ds_load2_end_op (
struct acpi_walk_state *walk_state)
{
union acpi_parse_object *op;
acpi_status status = AE_OK;
acpi_object_type object_type;
struct acpi_namespace_node *node;
union acpi_parse_object *arg;
struct acpi_namespace_node *new_node;
#ifndef ACPI_NO_METHOD_EXECUTION
u32 i;
#endif
ACPI_FUNCTION_TRACE ("ds_load2_end_op");
op = walk_state->op;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
walk_state->op_info->name, op, walk_state));
/* Only interested in opcodes that have namespace objects */
if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
return_ACPI_STATUS (AE_OK);
}
if (op->common.aml_opcode == AML_SCOPE_OP) {
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"Ending scope Op=%p State=%p\n", op, walk_state));
}
object_type = walk_state->op_info->object_type;
/*
* Get the Node/name from the earlier lookup
* (It was saved in the *op structure)
*/
node = op->common.node;
/*
* Put the Node on the object stack (Contains the ACPI Name of
* this object)
*/
walk_state->operands[0] = (void *) node;
walk_state->num_operands = 1;
/* Pop the scope stack */
if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n",
acpi_ut_get_type_name (object_type), op));
status = acpi_ds_scope_stack_pop (walk_state);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
}
/*
* Named operations are as follows:
*
* AML_ALIAS
* AML_BANKFIELD
* AML_CREATEBITFIELD
* AML_CREATEBYTEFIELD
* AML_CREATEDWORDFIELD
* AML_CREATEFIELD
* AML_CREATEQWORDFIELD
* AML_CREATEWORDFIELD
* AML_DATA_REGION
* AML_DEVICE
* AML_EVENT
* AML_FIELD
* AML_INDEXFIELD
* AML_METHOD
* AML_METHODCALL
* AML_MUTEX
* AML_NAME
* AML_NAMEDFIELD
* AML_OPREGION
* AML_POWERRES
* AML_PROCESSOR
* AML_SCOPE
* AML_THERMALZONE
*/
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"Create-Load [%s] State=%p Op=%p named_obj=%p\n",
acpi_ps_get_opcode_name (op->common.aml_opcode), walk_state, op, node));
/* Decode the opcode */
arg = op->common.value.arg;
switch (walk_state->op_info->type) {
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_TYPE_CREATE_FIELD:
/*
* Create the field object, but the field buffer and index must
* be evaluated later during the execution phase
*/
status = acpi_ds_create_buffer_field (op, walk_state);
break;
case AML_TYPE_NAMED_FIELD:
switch (op->common.aml_opcode) {
case AML_INDEX_FIELD_OP:
status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node,
walk_state);
break;
case AML_BANK_FIELD_OP:
status = acpi_ds_create_bank_field (op, arg->common.node, walk_state);
break;
case AML_FIELD_OP:
status = acpi_ds_create_field (op, arg->common.node, walk_state);
break;
default:
/* All NAMED_FIELD opcodes must be handled above */
break;
}
break;
case AML_TYPE_NAMED_SIMPLE:
status = acpi_ds_create_operands (walk_state, arg);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
switch (op->common.aml_opcode) {
case AML_PROCESSOR_OP:
status = acpi_ex_create_processor (walk_state);
break;
case AML_POWER_RES_OP:
status = acpi_ex_create_power_resource (walk_state);
break;
case AML_MUTEX_OP:
status = acpi_ex_create_mutex (walk_state);
break;
case AML_EVENT_OP:
status = acpi_ex_create_event (walk_state);
break;
case AML_DATA_REGION_OP:
status = acpi_ex_create_table_region (walk_state);
break;
case AML_ALIAS_OP:
status = acpi_ex_create_alias (walk_state);
break;
default:
/* Unknown opcode */
status = AE_OK;
goto cleanup;
}
/* Delete operands */
for (i = 1; i < walk_state->num_operands; i++) {
acpi_ut_remove_reference (walk_state->operands[i]);
walk_state->operands[i] = NULL;
}
break;
#endif /* ACPI_NO_METHOD_EXECUTION */
case AML_TYPE_NAMED_COMPLEX:
switch (op->common.aml_opcode) {
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_REGION_OP:
/*
* The op_region is not fully parsed at this time. Only valid argument is the space_id.
* (We must save the address of the AML of the address and length operands)
*/
/*
* If we have a valid region, initialize it
* Namespace is NOT locked at this point.
*/
status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE);
if (ACPI_FAILURE (status)) {
/*
* If AE_NOT_EXIST is returned, it is not fatal
* because many regions get created before a handler
* is installed for said region.
*/
if (AE_NOT_EXIST == status) {
status = AE_OK;
}
}
break;
case AML_NAME_OP:
status = acpi_ds_create_node (walk_state, node, op);
break;
#endif /* ACPI_NO_METHOD_EXECUTION */
default:
/* All NAMED_COMPLEX opcodes must be handled above */
/* Note: Method objects were already created in Pass 1 */
break;
}
break;
case AML_CLASS_INTERNAL:
/* case AML_INT_NAMEPATH_OP: */
break;
case AML_CLASS_METHOD_CALL:
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"RESOLVING-method_call: State=%p Op=%p named_obj=%p\n",
walk_state, op, node));
/*
* Lookup the method name and save the Node
*/
status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS2,
ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
walk_state, &(new_node));
if (ACPI_SUCCESS (status)) {
/*
* Make sure that what we found is indeed a method
* We didn't search for a method on purpose, to see if the name would resolve
*/
if (new_node->type != ACPI_TYPE_METHOD) {
status = AE_AML_OPERAND_TYPE;
}
/* We could put the returned object (Node) on the object stack for later, but
* for now, we will put it in the "op" object that the parser uses, so we
* can get it again at the end of this scope
*/
op->common.node = new_node;
}
else {
ACPI_REPORT_NSERROR (arg->common.value.string, status);
}
break;
default:
break;
}
cleanup:
/* Remove the Node pushed at the very beginning */
walk_state->operands[0] = NULL;
walk_state->num_operands = 0;
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,229 @@
/******************************************************************************
*
* Module Name: dswscope - Scope stack manipulation
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
#define STACK_POP(head) head
/****************************************************************************
*
* FUNCTION: acpi_ds_scope_stack_clear
*
* PARAMETERS: 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
*
* 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_REPORT_ERROR (("ds_scope_stack_push: null scope passed\n"));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/* Make sure object type is valid */
if (!acpi_ut_valid_object_type (type)) {
ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", 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.data_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: Type - The type of frame to be found
*
* DESCRIPTION: Pop the scope stack until a frame of the requested type
* is found.
*
* RETURN: Count of frames popped. If no frame of the requested type
* was found, the count is returned as a negative number and
* the scope stack is emptied (which sets the current scope
* to the root). If the scope stack was empty at entry, the
* function is a no-op and returns 0.
*
***************************************************************************/
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);
}

File diff suppressed because it is too large Load Diff

1024
drivers/acpi/ec.c Normal file

File diff suppressed because it is too large Load Diff

140
drivers/acpi/event.c Normal file
View File

@@ -0,0 +1,140 @@
/*
* 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;
ACPI_FUNCTION_TRACE("acpi_system_read_event");
if (!chars_remaining) {
memset(&event, 0, sizeof(struct acpi_bus_event));
if ((file->f_flags & O_NONBLOCK)
&& (list_empty(&acpi_bus_event_list)))
return_VALUE(-EAGAIN);
result = acpi_bus_receive_event(&event);
if (result) {
return_VALUE(-EIO);
}
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_VALUE(-EFAULT);
*ppos += count;
chars_remaining -= count;
ptr += count;
return_VALUE(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 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;
ACPI_FUNCTION_TRACE("acpi_event_init");
if (acpi_disabled)
return_VALUE(0);
/* 'event' [R] */
entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
if (entry)
entry->proc_fops = &acpi_system_event_ops;
else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' proc fs entry\n","event" ));
error = -EFAULT;
}
return_VALUE(error);
}
subsys_initcall(acpi_event_init);

View 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)

View File

@@ -0,0 +1,297 @@
/******************************************************************************
*
* Module Name: evevent - Fixed Event handling and dispatch
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* FUNCTION: acpi_ev_initialize_events
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Initialize global data structures for events.
*
******************************************************************************/
acpi_status
acpi_ev_initialize_events (
void)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("ev_initialize_events");
/* Make sure we have ACPI tables */
if (!acpi_gbl_DSDT) {
ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No ACPI tables present!\n"));
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
/*
* Initialize the Fixed and General Purpose Events. This is
* done prior to enabling SCIs to prevent interrupts from
* occurring before handers are installed.
*/
status = acpi_ev_fixed_event_initialize ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Unable to initialize fixed events, %s\n",
acpi_format_exception (status)));
return_ACPI_STATUS (status);
}
status = acpi_ev_gpe_initialize ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Unable to initialize general purpose events, %s\n",
acpi_format_exception (status)));
return_ACPI_STATUS (status);
}
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ev_install_xrupt_handlers
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Install interrupt handlers for the SCI and Global Lock
*
******************************************************************************/
acpi_status
acpi_ev_install_xrupt_handlers (
void)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("ev_install_xrupt_handlers");
/* Install the SCI handler */
status = acpi_ev_install_sci_handler ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Unable to install System Control Interrupt Handler, %s\n",
acpi_format_exception (status)));
return_ACPI_STATUS (status);
}
/* Install the handler for the Global Lock */
status = acpi_ev_init_global_lock_handler ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Unable to initialize Global Lock handler, %s\n",
acpi_format_exception (status)));
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.
*
******************************************************************************/
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, ACPI_MTX_LOCK);
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 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.
*
******************************************************************************/
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, ACPI_MTX_DO_NOT_LOCK);
/*
* 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_MTX_DO_NOT_LOCK);
ACPI_REPORT_ERROR (
("No installed handler for fixed event [%08X]\n",
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));
}

756
drivers/acpi/events/evgpe.c Normal file
View File

@@ -0,0 +1,756 @@
/******************************************************************************
*
* Module Name: evgpe - General Purpose Event handling and dispatch
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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 = gpe_event_info->register_bit;
/* 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)
{
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
u8 enabled_status_byte;
struct acpi_gpe_register_info *gpe_register_info;
u32 status_reg;
u32 enable_reg;
acpi_status status;
struct acpi_gpe_block_info *gpe_block;
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);
}
/* Examine all GPE blocks attached to this interrupt level */
acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR);
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));
/* First 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 & acpi_gbl_decode_to8bit[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, ACPI_ISR);
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_queue_for_execution
* (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;
u32 gpe_number = 0;
acpi_status status;
struct acpi_gpe_event_info local_gpe_event_info;
struct acpi_parameter_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) {
/*
* Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
* control method that corresponds to this GPE
*/
info.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;
status = acpi_ns_evaluate_by_handle (&info);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"%s while evaluating method [%4.4s] for GPE[%2X]\n",
acpi_format_exception (status),
acpi_ut_get_node_name (local_gpe_event_info.dispatch.method_node),
gpe_number));
}
}
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");
/*
* 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_REPORT_ERROR (("acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n",
acpi_format_exception (status), gpe_number));
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
}
}
/* Save current system state */
if (acpi_gbl_system_awake_and_running) {
ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
}
else {
ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
}
/*
* 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 the level to
* prevent further events from coming in here.
*/
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_REPORT_ERROR ((
"acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n",
acpi_format_exception (status), gpe_number));
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
}
}
break;
case ACPI_GPE_DISPATCH_METHOD:
/*
* Disable GPE, so it doesn't keep firing before the method has a
* chance to run.
*/
status = acpi_ev_disable_gpe (gpe_event_info);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"acpi_ev_gpe_dispatch: %s, Unable to disable GPE[%2X]\n",
acpi_format_exception (status), gpe_number));
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
}
/*
* Execute the method associated with the GPE
* NOTE: Level-triggered GPEs are cleared after the method completes.
*/
status = acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
acpi_ev_asynch_execute_gpe_method, gpe_event_info);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"acpi_ev_gpe_dispatch: %s, Unable to queue handler for GPE[%2X] - event disabled\n",
acpi_format_exception (status), gpe_number));
}
break;
default:
/* No handler or method to run! */
ACPI_REPORT_ERROR ((
"acpi_ev_gpe_dispatch: No handler or method for GPE[%2X], disabling event\n",
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_REPORT_ERROR ((
"acpi_ev_gpe_dispatch: %s, Unable to disable GPE[%2X]\n",
acpi_format_exception (status), gpe_number));
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
}
break;
}
return_VALUE (ACPI_INTERRUPT_HANDLED);
}
#ifdef ACPI_GPE_NOTIFY_CHECK
/*******************************************************************************
* TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
*
* FUNCTION: acpi_ev_check_for_wake_only_gpe
*
* PARAMETERS: gpe_event_info - info for this GPE
*
* RETURN: Status
*
* DESCRIPTION: Determine if a a GPE is "wake-only".
*
* Called from Notify() code in interpreter when a "device_wake"
* Notify comes in.
*
******************************************************************************/
acpi_status
acpi_ev_check_for_wake_only_gpe (
struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("ev_check_for_wake_only_gpe");
if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) /* System state at GPE time */ {
/* This must be a wake-only GPE, disable it */
status = acpi_ev_disable_gpe (gpe_event_info);
/* Set GPE to wake-only. Do not change wake disabled/enabled status */
acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE);
ACPI_REPORT_INFO (("GPE %p was updated from wake/run to wake-only\n",
gpe_event_info));
/* This was a wake-only GPE */
return_ACPI_STATUS (AE_WAKE_ONLY_GPE);
}
return_ACPI_STATUS (AE_OK);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,588 @@
/******************************************************************************
*
* Module Name: evmisc - Miscellaneous event manager support functions
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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.
*
******************************************************************************/
#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
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.data_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;
status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
acpi_ev_notify_dispatch, notify_info);
if (ACPI_FAILURE (status)) {
acpi_ut_delete_generic_state (notify_info);
}
}
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 passsed to the notify handler
*
* RETURN: None.
*
* DESCRIPTION: Dispatch a device notification event to a previously
* installed handler.
*
******************************************************************************/
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_thread
*
* PARAMETERS: Context - From thread interface, not used
*
* RETURN: None
*
* DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
* Global Lock. Simply signal all threads that are waiting
* for the lock.
*
******************************************************************************/
static void ACPI_SYSTEM_XFACE
acpi_ev_global_lock_thread (
void *context)
{
acpi_status status;
/* Signal threads that are waiting for the lock */
if (acpi_gbl_global_lock_thread_count) {
/* Send sufficient units to the semaphore */
status = acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore,
acpi_gbl_global_lock_thread_count);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Could not signal Global Lock semaphore\n"));
}
}
}
/*******************************************************************************
*
* FUNCTION: acpi_ev_global_lock_handler
*
* PARAMETERS: Context - From thread interface, not used
*
* RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
*
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
* release interrupt occurs. Grab the global lock and queue
* the global lock thread for execution
*
******************************************************************************/
static u32
acpi_ev_global_lock_handler (
void *context)
{
u8 acquired = FALSE;
acpi_status status;
/*
* 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 (acpi_gbl_common_fACS.global_lock, acquired);
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
acpi_gbl_global_lock_acquired = TRUE;
/* Run the Global Lock thread which will signal all waiting threads */
status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
acpi_ev_global_lock_thread, context);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Could not queue Global Lock thread, %s\n",
acpi_format_exception (status)));
return (ACPI_INTERRUPT_NOT_HANDLED);
}
}
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");
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_gbl_global_lock_present = FALSE;
status = AE_OK;
}
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.
*
*****************************************************************************/
acpi_status
acpi_ev_acquire_global_lock (
u16 timeout)
{
acpi_status status = AE_OK;
u8 acquired = FALSE;
ACPI_FUNCTION_TRACE ("ev_acquire_global_lock");
#ifndef ACPI_APPLICATION
/* Make sure that we actually have a global lock */
if (!acpi_gbl_global_lock_present) {
return_ACPI_STATUS (AE_NO_GLOBAL_LOCK);
}
#endif
/* One more thread wants the global lock */
acpi_gbl_global_lock_thread_count++;
/* If we (OS side vs. BIOS side) have the hardware lock already, we are done */
if (acpi_gbl_global_lock_acquired) {
return_ACPI_STATUS (AE_OK);
}
/* We must acquire the actual hardware lock */
ACPI_ACQUIRE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, acquired);
if (acquired) {
/* We got the lock */
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Acquired the HW 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 the HW Global Lock\n"));
/*
* Acquire the global lock semaphore first.
* Since this wait will block, we must release the interpreter
*/
status = acpi_ex_system_wait_semaphore (acpi_gbl_global_lock_semaphore,
timeout);
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");
if (!acpi_gbl_global_lock_thread_count) {
ACPI_REPORT_WARNING(("Cannot release HW Global Lock, it has not been acquired\n"));
return_ACPI_STATUS (AE_NOT_ACQUIRED);
}
/* One fewer thread has the global lock */
acpi_gbl_global_lock_thread_count--;
if (acpi_gbl_global_lock_thread_count) {
/* There are still some threads holding the lock, cannot release */
return_ACPI_STATUS (AE_OK);
}
/*
* No more threads holding lock, we can do the actual hardware
* release
*/
ACPI_RELEASE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, pending);
acpi_gbl_global_lock_acquired = FALSE;
/*
* 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_MTX_LOCK);
}
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", (u32) i));
}
}
/* Disable all GPEs in all GPE blocks */
status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, ACPI_NOT_ISR);
/* Remove SCI handler */
status = acpi_ev_remove_sci_handler ();
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n"));
}
}
/* Deallocate all handler objects installed within GPE info structs */
status = acpi_ev_walk_gpe_list (acpi_ev_delete_gpe_handlers, ACPI_NOT_ISR);
/* Return to original mode if necessary */
if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
status = acpi_disable ();
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "acpi_disable failed\n"));
}
}
return_VOID;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,580 @@
/******************************************************************************
*
* Module Name: evrgnini- ACPI address_space (op_region) init
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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: Do any prep work for region handling, a nop for now
*
******************************************************************************/
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) {
ACPI_MEM_FREE (*region_context);
*region_context = NULL;
}
return_ACPI_STATUS (AE_OK);
}
/* Create a new context */
local_region_context = ACPI_MEM_CALLOCATE (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: Do any prep work for region handling
*
******************************************************************************/
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: Do any prep work for region handling
*
* 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;
union acpi_operand_object *region_obj = (union acpi_operand_object *) handle;
struct acpi_device_id object_hID;
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_MEM_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) {
status = acpi_ut_execute_HID (pci_root_node, &object_hID);
if (ACPI_SUCCESS (status)) {
/* Got a valid _HID, check if this is a PCI root */
if (!(ACPI_STRNCMP (object_hID.value, PCI_ROOT_HID_STRING,
sizeof (PCI_ROOT_HID_STRING)))) {
/* 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_REPORT_ERROR ((
"Could not install pci_config handler for Root Bridge %4.4s, %s\n",
acpi_ut_get_node_name (pci_root_node), acpi_format_exception (status)));
}
}
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_MEM_CALLOCATE (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.
*/
/*
* 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, parent_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_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: Do any prep work for region handling
*
* 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: Do any prep work for region handling
*
* 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: Do any prep work for region handling
*
******************************************************************************/
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.
*
******************************************************************************/
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_node (*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 region_type %s(%X) (region_obj %p)\n",
acpi_ut_get_region_name (space_id), space_id, region_obj));
return_ACPI_STATUS (AE_NOT_EXIST);
}

199
drivers/acpi/events/evsci.c Normal file
View File

@@ -0,0 +1,199 @@
/*******************************************************************************
*
* Module Name: evsci - System Control Interrupt configuration and
* legacy to ACPI mode state transition functions
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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_VALUE (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_VALUE (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_int,
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_int,
acpi_ev_sci_xrupt_handler);
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,834 @@
/******************************************************************************
*
* Module Name: evxface - External interfaces for ACPI events
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#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);
}
#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_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n"));
/* 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);
}
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_DEBUG_PRINT ((ACPI_DB_WARN,
"Could not write to fixed event enable register.\n"));
}
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);
}
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);
}
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)) {
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 */
if (device == ACPI_ROOT_OBJECT) {
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for 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)) {
return_ACPI_STATUS (status);
}
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) ||
(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)) {
return_ACPI_STATUS (status);
}
/* 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) ||
(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)) {
return_ACPI_STATUS (status);
}
/* 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);
return_ACPI_STATUS (status);
}
EXPORT_SYMBOL(acpi_remove_notify_handler);
/*******************************************************************************
*
* FUNCTION: acpi_install_gpe_handler
*
* PARAMETERS: gpe_number - The GPE number within the GPE block
* gpe_block - GPE block (NULL == FADT GPEs)
* 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_FUNCTION_TRACE ("acpi_install_gpe_handler");
/* Parameter validation */
if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* 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_MEM_CALLOCATE (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 */
acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
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, ACPI_NOT_ISR);
unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
return_ACPI_STATUS (status);
}
EXPORT_SYMBOL(acpi_install_gpe_handler);
/*******************************************************************************
*
* FUNCTION: acpi_remove_gpe_handler
*
* PARAMETERS: gpe_number - The event to remove a handler
* gpe_block - GPE block (NULL == FADT GPEs)
* 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_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 */
acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
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, ACPI_NOT_ISR);
/* Now we can free the handler object */
ACPI_MEM_FREE (handler);
unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
return_ACPI_STATUS (status);
}
EXPORT_SYMBOL(acpi_remove_gpe_handler);
/*******************************************************************************
*
* FUNCTION: acpi_acquire_global_lock
*
* PARAMETERS: Timeout - How long the caller is willing to wait
* out_handle - A handle to the lock 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);
}
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
*
******************************************************************************/
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);
}
EXPORT_SYMBOL(acpi_release_global_lock);

View File

@@ -0,0 +1,778 @@
/******************************************************************************
*
* Module Name: evxfevnt - External Interfaces, ACPI event disable/enable
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#include <acpi/acpi.h>
#include <acpi/acevents.h>
#include <acpi/acnamesp.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");
/* Make sure we have the FADT*/
if (!acpi_gbl_FADT) {
ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n"));
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
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_REPORT_ERROR (("Could not transition to ACPI mode.\n"));
return_ACPI_STATUS (status);
}
ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Transition to ACPI mode successful\n"));
}
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_disable
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Transfers the system into LEGACY mode.
*
******************************************************************************/
acpi_status
acpi_disable (void)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE ("acpi_disable");
if (!acpi_gbl_FADT) {
ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n"));
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
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_DEBUG_PRINT ((ACPI_DB_ERROR, "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);
}
/*******************************************************************************
*
* 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, ACPI_MTX_LOCK);
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, ACPI_MTX_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
if (value != 1) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not enable %s event\n", acpi_ut_get_event_name (event)));
return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
}
return_ACPI_STATUS (status);
}
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: Enable an ACPI event (general purpose)
*
******************************************************************************/
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);
}
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);
}
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);
}
/*******************************************************************************
*
* 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, ACPI_MTX_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id,
&value, ACPI_MTX_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
if (value != 0) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not disable %s events\n", acpi_ut_get_event_name (event)));
return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
}
return_ACPI_STATUS (status);
}
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, ACPI_MTX_LOCK);
return_ACPI_STATUS (status);
}
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);
}
#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, ACPI_MTX_LOCK);
return_ACPI_STATUS (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);
}
#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_level - 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_level)
{
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_level, &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);
}
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);
}
EXPORT_SYMBOL(acpi_remove_gpe_block);

View File

@@ -0,0 +1,247 @@
/******************************************************************************
*
* Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
* Address Spaces.
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#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);
}
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) {
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) {
/* 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), dev_node %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);
}
EXPORT_SYMBOL(acpi_remove_address_space_handler);

View 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)

View File

@@ -0,0 +1,487 @@
/******************************************************************************
*
* Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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.
*
******************************************************************************/
acpi_status
acpi_ex_add_table (
struct acpi_table_header *table,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle)
{
acpi_status status;
struct acpi_table_desc table_info;
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);
}
/* Install the new table into the local data structures */
ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc));
table_info.type = ACPI_TABLE_SSDT;
table_info.pointer = table;
table_info.length = (acpi_size) table->length;
table_info.allocation = ACPI_MEM_ALLOCATED;
status = acpi_tb_install_table (&table_info);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
/* Add the table to the namespace */
status = acpi_ns_load_table (table_info.installed_desc, parent_node);
if (ACPI_FAILURE (status)) {
/* Uninstall table on error */
(void) acpi_tb_uninstall_table (table_info.installed_desc);
goto cleanup;
}
/* Init the table handle */
obj_desc->reference.opcode = AML_LOAD_OP;
obj_desc->reference.object = table_info.installed_desc;
*ddb_handle = obj_desc;
return_ACPI_STATUS (AE_OK);
cleanup:
acpi_ut_remove_reference (obj_desc);
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
*
******************************************************************************/
acpi_status
acpi_ex_load_table_op (
struct acpi_walk_state *walk_state,
union acpi_operand_object **return_desc)
{
acpi_status status;
union acpi_operand_object **operand = &walk_state->operands[0];
struct acpi_table_header *table;
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;
ACPI_FUNCTION_TRACE ("ex_load_table_op");
#if 0
/*
* Make sure that the signature does not match one of the tables that
* is already loaded.
*/
status = acpi_tb_match_signature (operand[0]->string.pointer, NULL);
if (status == AE_OK) {
/* Signature matched -- don't allow override */
return_ACPI_STATUS (AE_ALREADY_EXISTS);
}
#endif
/* Find the ACPI table */
status = acpi_tb_find_table (operand[0]->string.pointer,
operand[1]->string.pointer,
operand[2]->string.pointer, &table);
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_by_path (operand[3]->string.pointer, start_node,
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_by_path (operand[4]->string.pointer, start_node,
ACPI_NS_SEARCH_PARENT, &parameter_node);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
/* Load the table into the namespace */
status = acpi_ex_add_table (table, 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);
}
}
*return_desc = ddb_handle;
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_load_op
*
* PARAMETERS: obj_desc - Region or 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
*
******************************************************************************/
acpi_status
acpi_ex_load_op (
union acpi_operand_object *obj_desc,
union acpi_operand_object *target,
struct acpi_walk_state *walk_state)
{
acpi_status status;
union acpi_operand_object *ddb_handle;
union acpi_operand_object *buffer_desc = NULL;
struct acpi_table_header *table_ptr = NULL;
acpi_physical_address address;
struct acpi_table_header table_header;
u32 i;
ACPI_FUNCTION_TRACE ("ex_load_op");
/* Object can be either an op_region or a Field */
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_REGION:
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);
}
}
/* Get the base physical address of the region */
address = obj_desc->region.address;
/* Get the table length from the table header */
table_header.length = 0;
for (i = 0; i < 8; i++) {
status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ,
(acpi_physical_address) (i + address), 8,
((u8 *) &table_header) + i);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
/* Sanity check the table length */
if (table_header.length < sizeof (struct acpi_table_header)) {
return_ACPI_STATUS (AE_BAD_HEADER);
}
/* Allocate a buffer for the entire table */
table_ptr = ACPI_MEM_ALLOCATE (table_header.length);
if (!table_ptr) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/* Get the entire table from the op region */
for (i = 0; i < table_header.length; i++) {
status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ,
(acpi_physical_address) (i + address), 8,
((u8 *) table_ptr + i));
if (ACPI_FAILURE (status)) {
goto cleanup;
}
}
break;
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
case ACPI_TYPE_LOCAL_INDEX_FIELD:
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Field %p %s\n",
obj_desc, acpi_ut_get_object_type_name (obj_desc)));
/*
* The length of the field must be at least as large as the table.
* Read the entire field and thus the entire table. Buffer is
* allocated during the read.
*/
status = acpi_ex_read_data_from_field (walk_state, obj_desc, &buffer_desc);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer);
/* Sanity check the table length */
if (table_ptr->length < sizeof (struct acpi_table_header)) {
return_ACPI_STATUS (AE_BAD_HEADER);
}
break;
default:
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
/* The table must be either an SSDT or a PSDT */
if ((!ACPI_STRNCMP (table_ptr->signature,
acpi_gbl_table_data[ACPI_TABLE_PSDT].signature,
acpi_gbl_table_data[ACPI_TABLE_PSDT].sig_length)) &&
(!ACPI_STRNCMP (table_ptr->signature,
acpi_gbl_table_data[ACPI_TABLE_SSDT].signature,
acpi_gbl_table_data[ACPI_TABLE_SSDT].sig_length))) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Table has invalid signature [%4.4s], must be SSDT or PSDT\n",
table_ptr->signature));
status = AE_BAD_SIGNATURE;
goto cleanup;
}
/* Install the new table into the local data structures */
status = acpi_ex_add_table (table_ptr, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
/* 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);
}
return_ACPI_STATUS (status);
cleanup:
if (buffer_desc) {
acpi_ut_remove_reference (buffer_desc);
}
else {
ACPI_MEM_FREE (table_ptr);
}
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;
struct acpi_table_desc *table_info;
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 actual table descriptor from the ddb_handle */
table_info = (struct acpi_table_desc *) table_desc->reference.object;
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
acpi_ns_delete_namespace_by_owner (table_info->table_id);
/* Delete the table itself */
(void) acpi_tb_uninstall_table (table_info->installed_desc);
/* Delete the table descriptor (ddb_handle) */
acpi_ut_remove_reference (table_desc);
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,708 @@
/******************************************************************************
*
* Module Name: exconvrt - Object conversion routines
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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);
}
/* 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
*
******************************************************************************/
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 = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */
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 operator */
/*
* 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 operator */
/*
* 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);
}
/*
* Perform the conversion.
* (-1 because of extra separator included in string_length from above)
*/
string_length--;
if (string_length > ACPI_MAX_STRING_CONVERSION) /* ACPI limit */ {
return_ACPI_STATUS (AE_AML_STRING_LIMIT);
}
/*
* Create a new string object and string buffer
*/
return_desc = acpi_ut_create_string_object ((acpi_size) string_length);
if (!return_desc) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
new_buf = return_desc->buffer.pointer;
/*
* Convert buffer bytes to hex or decimal values
* (separated by commas or spaces)
*/
for (i = 0; i < obj_desc->buffer.length; i++) {
new_buf += acpi_ex_convert_to_ascii (
(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_REPORT_ERROR (("Bad destination type during conversion: %X\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Unknown Target type ID 0x%X Op %s dest_type %s\n",
GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args),
walk_state->op_info->name, acpi_ut_get_type_name (destination_type)));
ACPI_REPORT_ERROR (("Bad Target Type (ARGI): %X\n",
GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)))
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);
}

View File

@@ -0,0 +1,646 @@
/******************************************************************************
*
* Module Name: excreate - Named object creation
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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.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 semaphore.
* One unit max to make it a mutex, with one initial unit to allow
* the mutex to be acquired.
*/
status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore);
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
* Operands - List of operands for the opcode
* 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_REPORT_ERROR (("Invalid address_space type %X\n", 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;
struct acpi_table_header *table;
union acpi_operand_object *region_obj2;
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);
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;
/* 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.address = (acpi_io_address) operand[2]->integer.value;
obj_desc->processor.length = (u8) operand[3]->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) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/* 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 concurrency count. If required, a semaphore will be
* created for this method when it is parsed.
*/
if (acpi_gbl_all_methods_serialized) {
obj_desc->method.concurrency = 1;
obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
}
else if (method_flags & AML_METHOD_SERIALIZED) {
/*
* ACPI 1.0: Concurrency = 1
* ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1)
*/
obj_desc->method.concurrency = (u8)
(((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1);
}
else {
obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY;
}
/* 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);
/* Remove a reference to the operand */
acpi_ut_remove_reference (operand[1]);
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,793 @@
/******************************************************************************
*
* Module Name: exdump - Interpreter debug output routines
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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/acparser.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exdump")
/*
* The following routines are used for debug output only
*/
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/*****************************************************************************
*
* FUNCTION: acpi_ex_dump_operand
*
* PARAMETERS: *obj_desc - Pointer to entry to be dumped
*
* RETURN: None
*
* DESCRIPTION: Dump an operand object
*
****************************************************************************/
void
acpi_ex_dump_operand (
union acpi_operand_object *obj_desc,
u32 depth)
{
u32 length;
u32 index;
ACPI_FUNCTION_NAME ("ex_dump_operand")
if (!((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
return;
}
if (!obj_desc) {
/*
* This could be a null element of a package
*/
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n"));
return;
}
if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is a NS Node: ", obj_desc));
ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_EXEC);
return;
}
if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
"%p is not a node or operand object: [%s]\n",
obj_desc, acpi_ut_get_descriptor_name (obj_desc)));
ACPI_DUMP_BUFFER (obj_desc, sizeof (union acpi_operand_object));
return;
}
/* obj_desc is a valid object */
if (depth > 0) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%*s[%u] %p ",
depth, " ", depth, obj_desc));
}
else {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc));
}
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
switch (obj_desc->reference.opcode) {
case AML_DEBUG_OP:
acpi_os_printf ("Reference: Debug\n");
break;
case AML_NAME_OP:
ACPI_DUMP_PATHNAME (obj_desc->reference.object,
"Reference: Name: ", ACPI_LV_INFO, _COMPONENT);
ACPI_DUMP_ENTRY (obj_desc->reference.object, ACPI_LV_INFO);
break;
case AML_INDEX_OP:
acpi_os_printf ("Reference: Index %p\n",
obj_desc->reference.object);
break;
case AML_REF_OF_OP:
acpi_os_printf ("Reference: (ref_of) %p\n",
obj_desc->reference.object);
break;
case AML_ARG_OP:
acpi_os_printf ("Reference: Arg%d",
obj_desc->reference.offset);
if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
/* Value is an Integer */
acpi_os_printf (" value is [%8.8X%8.8x]",
ACPI_FORMAT_UINT64 (obj_desc->integer.value));
}
acpi_os_printf ("\n");
break;
case AML_LOCAL_OP:
acpi_os_printf ("Reference: Local%d",
obj_desc->reference.offset);
if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
/* Value is an Integer */
acpi_os_printf (" value is [%8.8X%8.8x]",
ACPI_FORMAT_UINT64 (obj_desc->integer.value));
}
acpi_os_printf ("\n");
break;
case AML_INT_NAMEPATH_OP:
acpi_os_printf ("Reference.Node->Name %X\n",
obj_desc->reference.node->name.integer);
break;
default:
/* Unknown opcode */
acpi_os_printf ("Unknown Reference opcode=%X\n",
obj_desc->reference.opcode);
break;
}
break;
case ACPI_TYPE_BUFFER:
acpi_os_printf ("Buffer len %X @ %p \n",
obj_desc->buffer.length, obj_desc->buffer.pointer);
length = obj_desc->buffer.length;
if (length > 64) {
length = 64;
}
/* Debug only -- dump the buffer contents */
if (obj_desc->buffer.pointer) {
acpi_os_printf ("Buffer Contents: ");
for (index = 0; index < length; index++) {
acpi_os_printf (" %02x", obj_desc->buffer.pointer[index]);
}
acpi_os_printf ("\n");
}
break;
case ACPI_TYPE_INTEGER:
acpi_os_printf ("Integer %8.8X%8.8X\n",
ACPI_FORMAT_UINT64 (obj_desc->integer.value));
break;
case ACPI_TYPE_PACKAGE:
acpi_os_printf ("Package [Len %X] element_array %p\n",
obj_desc->package.count, obj_desc->package.elements);
/*
* If elements exist, package element pointer is valid,
* and debug_level exceeds 1, dump package's elements.
*/
if (obj_desc->package.count &&
obj_desc->package.elements &&
acpi_dbg_level > 1) {
for (index = 0; index < obj_desc->package.count; index++) {
acpi_ex_dump_operand (obj_desc->package.elements[index], depth+1);
}
}
break;
case ACPI_TYPE_REGION:
acpi_os_printf ("Region %s (%X)",
acpi_ut_get_region_name (obj_desc->region.space_id),
obj_desc->region.space_id);
/*
* If the address and length have not been evaluated,
* don't print them.
*/
if (!(obj_desc->region.flags & AOPOBJ_DATA_VALID)) {
acpi_os_printf ("\n");
}
else {
acpi_os_printf (" base %8.8X%8.8X Length %X\n",
ACPI_FORMAT_UINT64 (obj_desc->region.address),
obj_desc->region.length);
}
break;
case ACPI_TYPE_STRING:
acpi_os_printf ("String length %X @ %p ",
obj_desc->string.length, obj_desc->string.pointer);
acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
acpi_os_printf ("\n");
break;
case ACPI_TYPE_LOCAL_BANK_FIELD:
acpi_os_printf ("bank_field\n");
break;
case ACPI_TYPE_LOCAL_REGION_FIELD:
acpi_os_printf (
"region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n",
obj_desc->field.bit_length, obj_desc->field.access_byte_width,
obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK,
obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK,
obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset);
acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1);
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
acpi_os_printf ("index_field\n");
break;
case ACPI_TYPE_BUFFER_FIELD:
acpi_os_printf (
"buffer_field: %X bits at byte %X bit %X of \n",
obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset,
obj_desc->buffer_field.start_field_bit_offset);
if (!obj_desc->buffer_field.buffer_obj) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n"));
}
else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) {
acpi_os_printf ("*not a Buffer* \n");
}
else {
acpi_ex_dump_operand (obj_desc->buffer_field.buffer_obj, depth+1);
}
break;
case ACPI_TYPE_EVENT:
acpi_os_printf ("Event\n");
break;
case ACPI_TYPE_METHOD:
acpi_os_printf (
"Method(%X) @ %p:%X\n",
obj_desc->method.param_count,
obj_desc->method.aml_start, obj_desc->method.aml_length);
break;
case ACPI_TYPE_MUTEX:
acpi_os_printf ("Mutex\n");
break;
case ACPI_TYPE_DEVICE:
acpi_os_printf ("Device\n");
break;
case ACPI_TYPE_POWER:
acpi_os_printf ("Power\n");
break;
case ACPI_TYPE_PROCESSOR:
acpi_os_printf ("Processor\n");
break;
case ACPI_TYPE_THERMAL:
acpi_os_printf ("Thermal\n");
break;
default:
/* Unknown Type */
acpi_os_printf ("Unknown Type %X\n", ACPI_GET_OBJECT_TYPE (obj_desc));
break;
}
return;
}
/*****************************************************************************
*
* FUNCTION: acpi_ex_dump_operands
*
* PARAMETERS: Operands - Operand list
* interpreter_mode - Load or Exec
* Ident - Identification
* num_levels - # of stack entries to dump above line
* Note - Output notation
* module_name - Caller's module name
* line_number - Caller's invocation line number
*
* DESCRIPTION: Dump the object stack
*
****************************************************************************/
void
acpi_ex_dump_operands (
union acpi_operand_object **operands,
acpi_interpreter_mode interpreter_mode,
char *ident,
u32 num_levels,
char *note,
char *module_name,
u32 line_number)
{
acpi_native_uint i;
ACPI_FUNCTION_NAME ("ex_dump_operands");
if (!ident) {
ident = "?";
}
if (!note) {
note = "?";
}
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
"************* Operand Stack Contents (Opcode [%s], %d Operands)\n",
ident, num_levels));
if (num_levels == 0) {
num_levels = 1;
}
/* Dump the operand stack starting at the top */
for (i = 0; num_levels > 0; i--, num_levels--) {
acpi_ex_dump_operand (operands[i], 0);
}
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
"************* Stack dump from %s(%d), %s\n",
module_name, line_number, note));
return;
}
#ifdef ACPI_FUTURE_USAGE
/*****************************************************************************
*
* FUNCTION: acpi_ex_out*
*
* PARAMETERS: Title - Descriptive text
* Value - Value to be displayed
*
* DESCRIPTION: Object dump output formatting functions. These functions
* reduce the number of format strings required and keeps them
* all in one place for easy modification.
*
****************************************************************************/
void
acpi_ex_out_string (
char *title,
char *value)
{
acpi_os_printf ("%20s : %s\n", title, value);
}
void
acpi_ex_out_pointer (
char *title,
void *value)
{
acpi_os_printf ("%20s : %p\n", title, value);
}
void
acpi_ex_out_integer (
char *title,
u32 value)
{
acpi_os_printf ("%20s : %X\n", title, value);
}
void
acpi_ex_out_address (
char *title,
acpi_physical_address value)
{
#if ACPI_MACHINE_WIDTH == 16
acpi_os_printf ("%20s : %p\n", title, value);
#else
acpi_os_printf ("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64 (value));
#endif
}
/*****************************************************************************
*
* FUNCTION: acpi_ex_dump_node
*
* PARAMETERS: *Node - Descriptor to dump
* Flags - Force display
*
* DESCRIPTION: Dumps the members of the given.Node
*
****************************************************************************/
void
acpi_ex_dump_node (
struct acpi_namespace_node *node,
u32 flags)
{
ACPI_FUNCTION_ENTRY ();
if (!flags) {
if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
return;
}
}
acpi_os_printf ("%20s : %4.4s\n", "Name", acpi_ut_get_node_name (node));
acpi_ex_out_string ("Type", acpi_ut_get_type_name (node->type));
acpi_ex_out_integer ("Flags", node->flags);
acpi_ex_out_integer ("Owner Id", node->owner_id);
acpi_ex_out_integer ("Reference Count", node->reference_count);
acpi_ex_out_pointer ("Attached Object", acpi_ns_get_attached_object (node));
acpi_ex_out_pointer ("child_list", node->child);
acpi_ex_out_pointer ("next_peer", node->peer);
acpi_ex_out_pointer ("Parent", acpi_ns_get_parent_node (node));
}
/*****************************************************************************
*
* FUNCTION: acpi_ex_dump_object_descriptor
*
* PARAMETERS: *Object - Descriptor to dump
* Flags - Force display
*
* DESCRIPTION: Dumps the members of the object descriptor given.
*
****************************************************************************/
void
acpi_ex_dump_object_descriptor (
union acpi_operand_object *obj_desc,
u32 flags)
{
u32 i;
ACPI_FUNCTION_TRACE ("ex_dump_object_descriptor");
if (!flags) {
if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
return_VOID;
}
}
if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
acpi_ex_dump_node ((struct acpi_namespace_node *) obj_desc, flags);
acpi_os_printf ("\nAttached Object (%p):\n",
((struct acpi_namespace_node *) obj_desc)->object);
acpi_ex_dump_object_descriptor (
((struct acpi_namespace_node *) obj_desc)->object, flags);
return_VOID;
}
if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
acpi_os_printf (
"ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n",
obj_desc, acpi_ut_get_descriptor_name (obj_desc));
return_VOID;
}
/* Common Fields */
acpi_ex_out_string ("Type", acpi_ut_get_object_type_name (obj_desc));
acpi_ex_out_integer ("Reference Count", obj_desc->common.reference_count);
acpi_ex_out_integer ("Flags", obj_desc->common.flags);
/* Object-specific Fields */
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_INTEGER:
acpi_os_printf ("%20s : %8.8X%8.8X\n", "Value",
ACPI_FORMAT_UINT64 (obj_desc->integer.value));
break;
case ACPI_TYPE_STRING:
acpi_ex_out_integer ("Length", obj_desc->string.length);
acpi_os_printf ("%20s : %p ", "Pointer", obj_desc->string.pointer);
acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
acpi_os_printf ("\n");
break;
case ACPI_TYPE_BUFFER:
acpi_ex_out_integer ("Length", obj_desc->buffer.length);
acpi_ex_out_pointer ("Pointer", obj_desc->buffer.pointer);
ACPI_DUMP_BUFFER (obj_desc->buffer.pointer, obj_desc->buffer.length);
break;
case ACPI_TYPE_PACKAGE:
acpi_ex_out_integer ("Flags", obj_desc->package.flags);
acpi_ex_out_integer ("Count", obj_desc->package.count);
acpi_ex_out_pointer ("Elements", obj_desc->package.elements);
/* Dump the package contents */
if (obj_desc->package.count > 0) {
acpi_os_printf ("\nPackage Contents:\n");
for (i = 0; i < obj_desc->package.count; i++) {
acpi_os_printf ("[%.3d] %p", i, obj_desc->package.elements[i]);
if (obj_desc->package.elements[i]) {
acpi_os_printf (" %s",
acpi_ut_get_object_type_name (obj_desc->package.elements[i]));
}
acpi_os_printf ("\n");
}
}
break;
case ACPI_TYPE_DEVICE:
acpi_ex_out_pointer ("Handler", obj_desc->device.handler);
acpi_ex_out_pointer ("system_notify", obj_desc->device.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->device.device_notify);
break;
case ACPI_TYPE_EVENT:
acpi_ex_out_pointer ("Semaphore", obj_desc->event.semaphore);
break;
case ACPI_TYPE_METHOD:
acpi_ex_out_integer ("param_count", obj_desc->method.param_count);
acpi_ex_out_integer ("Concurrency", obj_desc->method.concurrency);
acpi_ex_out_pointer ("Semaphore", obj_desc->method.semaphore);
acpi_ex_out_integer ("owning_id", obj_desc->method.owning_id);
acpi_ex_out_integer ("aml_length", obj_desc->method.aml_length);
acpi_ex_out_pointer ("aml_start", obj_desc->method.aml_start);
break;
case ACPI_TYPE_MUTEX:
acpi_ex_out_integer ("sync_level", obj_desc->mutex.sync_level);
acpi_ex_out_pointer ("owner_thread", obj_desc->mutex.owner_thread);
acpi_ex_out_integer ("acquire_depth", obj_desc->mutex.acquisition_depth);
acpi_ex_out_pointer ("Semaphore", obj_desc->mutex.semaphore);
break;
case ACPI_TYPE_REGION:
acpi_ex_out_integer ("space_id", obj_desc->region.space_id);
acpi_ex_out_integer ("Flags", obj_desc->region.flags);
acpi_ex_out_address ("Address", obj_desc->region.address);
acpi_ex_out_integer ("Length", obj_desc->region.length);
acpi_ex_out_pointer ("Handler", obj_desc->region.handler);
acpi_ex_out_pointer ("Next", obj_desc->region.next);
break;
case ACPI_TYPE_POWER:
acpi_ex_out_integer ("system_level", obj_desc->power_resource.system_level);
acpi_ex_out_integer ("resource_order", obj_desc->power_resource.resource_order);
acpi_ex_out_pointer ("system_notify", obj_desc->power_resource.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->power_resource.device_notify);
break;
case ACPI_TYPE_PROCESSOR:
acpi_ex_out_integer ("Processor ID", obj_desc->processor.proc_id);
acpi_ex_out_integer ("Length", obj_desc->processor.length);
acpi_ex_out_address ("Address", (acpi_physical_address) obj_desc->processor.address);
acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify);
acpi_ex_out_pointer ("Handler", obj_desc->processor.handler);
break;
case ACPI_TYPE_THERMAL:
acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify);
acpi_ex_out_pointer ("Handler", obj_desc->thermal_zone.handler);
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_ex_out_integer ("field_flags", obj_desc->common_field.field_flags);
acpi_ex_out_integer ("access_byte_width",obj_desc->common_field.access_byte_width);
acpi_ex_out_integer ("bit_length", obj_desc->common_field.bit_length);
acpi_ex_out_integer ("fld_bit_offset", obj_desc->common_field.start_field_bit_offset);
acpi_ex_out_integer ("base_byte_offset", obj_desc->common_field.base_byte_offset);
acpi_ex_out_pointer ("parent_node", obj_desc->common_field.node);
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_BUFFER_FIELD:
acpi_ex_out_pointer ("buffer_obj", obj_desc->buffer_field.buffer_obj);
break;
case ACPI_TYPE_LOCAL_REGION_FIELD:
acpi_ex_out_pointer ("region_obj", obj_desc->field.region_obj);
break;
case ACPI_TYPE_LOCAL_BANK_FIELD:
acpi_ex_out_integer ("Value", obj_desc->bank_field.value);
acpi_ex_out_pointer ("region_obj", obj_desc->bank_field.region_obj);
acpi_ex_out_pointer ("bank_obj", obj_desc->bank_field.bank_obj);
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
acpi_ex_out_integer ("Value", obj_desc->index_field.value);
acpi_ex_out_pointer ("Index", obj_desc->index_field.index_obj);
acpi_ex_out_pointer ("Data", obj_desc->index_field.data_obj);
break;
default:
/* All object types covered above */
break;
}
break;
case ACPI_TYPE_LOCAL_REFERENCE:
acpi_ex_out_integer ("target_type", obj_desc->reference.target_type);
acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name);
acpi_ex_out_integer ("Offset", obj_desc->reference.offset);
acpi_ex_out_pointer ("obj_desc", obj_desc->reference.object);
acpi_ex_out_pointer ("Node", obj_desc->reference.node);
acpi_ex_out_pointer ("Where", obj_desc->reference.where);
break;
case ACPI_TYPE_LOCAL_ADDRESS_HANDLER:
acpi_ex_out_integer ("space_id", obj_desc->address_space.space_id);
acpi_ex_out_pointer ("Next", obj_desc->address_space.next);
acpi_ex_out_pointer ("region_list", obj_desc->address_space.region_list);
acpi_ex_out_pointer ("Node", obj_desc->address_space.node);
acpi_ex_out_pointer ("Context", obj_desc->address_space.context);
break;
case ACPI_TYPE_LOCAL_NOTIFY:
acpi_ex_out_pointer ("Node", obj_desc->notify.node);
acpi_ex_out_pointer ("Context", obj_desc->notify.context);
break;
case ACPI_TYPE_LOCAL_ALIAS:
case ACPI_TYPE_LOCAL_METHOD_ALIAS:
case ACPI_TYPE_LOCAL_EXTRA:
case ACPI_TYPE_LOCAL_DATA:
default:
acpi_os_printf (
"ex_dump_object_descriptor: Display not implemented for object type %s\n",
acpi_ut_get_object_type_name (obj_desc));
break;
}
return_VOID;
}
#endif /* ACPI_FUTURE_USAGE */
#endif

View File

@@ -0,0 +1,367 @@
/******************************************************************************
*
* Module Name: exfield - ACPI AML (p-code) execution - field manipulation
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 (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,
"field_read [TO]: Obj %p, Type %X, Buf %p, byte_len %X\n",
obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc), buffer, (u32) length));
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"field_read [FROM]: bit_len %X, bit_off %X, byte_off %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 if (ret_buffer_desc) {
*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
*
* 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_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n",
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_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n",
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_MEM_CALLOCATE (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,
"field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %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,
"field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %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_MEM_FREE (new_buffer);
}
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,835 @@
/******************************************************************************
*
* Module Name: exfldio - Aml Field I/O
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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.
*
******************************************************************************/
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
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);
}
}
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
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, byte_base %X, Offset %X at %8.8X%8.8X\n",
acpi_ut_get_region_name (rgn_desc->region.space_id),
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
field_datum_byte_offset,
ACPI_FORMAT_UINT64 (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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Region %s(%X) not implemented\n",
acpi_ut_get_region_name (rgn_desc->region.space_id),
rgn_desc->region.space_id));
}
else if (status == AE_NOT_EXIST) {
ACPI_REPORT_ERROR ((
"Region %s(%X) has no handler\n",
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.
*
******************************************************************************/
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)
*
******************************************************************************/
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;
value = &local_value; /* To support reads without saving return 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 op_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: value_ptr %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_REPORT_ERROR (("Wrong object type in field I/O %X\n",
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 set
* Value - Value to store
*
* 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,
&current_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_DEBUG_PRINT ((ACPI_DB_ERROR,
"write_with_update_rule: Unknown update_rule setting: %X\n",
(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, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Field size %X (bits) is too large for buffer (%X)\n",
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 */
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 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Field size %X (bits) is too large for buffer (%X)\n",
obj_desc->common_field.bit_length, buffer_length));
return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
}
/* Compute the number of datums (access width data items) */
mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset);
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);
}
/* Start new output datum by merging with previous input datum */
field_offset += obj_desc->common_field.access_byte_width;
merged_datum = raw_datum >>
(obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
mask = ACPI_INTEGER_MAX;
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);
}

View File

@@ -0,0 +1,738 @@
/******************************************************************************
*
* Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 ("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_REPORT_ERROR (("Unknown Reference opcode in get_reference %X\n",
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_REPORT_ERROR (("Invalid descriptor type in get_reference: %X\n",
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)
{
union acpi_operand_object *return_desc;
u8 *new_buf;
u8 *end_tag1;
u8 *end_tag2;
acpi_size length1;
acpi_size length2;
ACPI_FUNCTION_TRACE ("ex_concat_template");
/* Find the end_tags in each resource template */
end_tag1 = acpi_ut_get_resource_end_tag (operand0);
end_tag2 = acpi_ut_get_resource_end_tag (operand1);
if (!end_tag1 || !end_tag2) {
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
/* Compute the length of each part */
length1 = ACPI_PTR_DIFF (end_tag1, operand0->buffer.pointer);
length2 = ACPI_PTR_DIFF (end_tag2, operand1->buffer.pointer) +
2; /* Size of END_TAG */
/* Create a new buffer object for the result */
return_desc = acpi_ut_create_buffer_object (length1 + length2);
if (!return_desc) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/* Copy the templates to the new descriptor */
new_buf = return_desc->buffer.pointer;
ACPI_MEMCPY (new_buf, operand0->buffer.pointer, length1);
ACPI_MEMCPY (new_buf + length1, operand1->buffer.pointer, length2);
/* Compute the new checksum */
new_buf[return_desc->buffer.length - 1] =
acpi_ut_generate_checksum (return_desc->buffer.pointer,
(return_desc->buffer.length - 1));
/* Return the completed template descriptor */
*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_size new_length;
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_REPORT_ERROR (("Concat - invalid obj type: %X\n",
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_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 */
new_length = (acpi_size) operand0->string.length +
(acpi_size) local_operand1->string.length;
if (new_length > ACPI_MAX_STRING_CONVERSION) {
status = AE_AML_STRING_LIMIT;
goto cleanup;
}
return_desc = acpi_ut_create_string_object (new_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 +
(acpi_size) 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_REPORT_ERROR (("Concatenate - Invalid object type: %X\n",
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) */
return (integer0 << integer1);
case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */
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 ((const char * ) operand0->buffer.pointer,
(const char * ) 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);
}

View File

@@ -0,0 +1,363 @@
/******************************************************************************
*
* Module Name: exmutex - ASL Mutex Acquire/Release functions
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 ("exmutex")
/*******************************************************************************
*
* FUNCTION: acpi_ex_unlink_mutex
*
* PARAMETERS: obj_desc - The mutex to be unlinked
*
* RETURN: Status
*
* DESCRIPTION: Remove a mutex from the "acquired_mutex" list
*
******************************************************************************/
void
acpi_ex_unlink_mutex (
union acpi_operand_object *obj_desc)
{
struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
if (!thread) {
return;
}
/* Doubly linked list */
if (obj_desc->mutex.next) {
(obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev;
}
if (obj_desc->mutex.prev) {
(obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
}
else {
thread->acquired_mutex_list = obj_desc->mutex.next;
}
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_link_mutex
*
* PARAMETERS: obj_desc - The mutex to be linked
* list_head - head of the "acquired_mutex" list
*
* RETURN: Status
*
* DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk
*
******************************************************************************/
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 - The 'time to delay' object descriptor
* obj_desc - The object descriptor for this op
*
* 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_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n",
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_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n",
acpi_ut_get_node_name (obj_desc->mutex.node)));
return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
}
/* Support for multiple acquires by the owning thread */
if (obj_desc->mutex.owner_thread) {
/* Special case for Global Lock, allow all threads */
if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) ||
(obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) {
/*
* 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 */
status = acpi_ex_system_acquire_mutex (time_desc, obj_desc);
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 = walk_state->thread;
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
*
* 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;
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) {
ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], not acquired\n",
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_REPORT_ERROR (("Cannot release Mutex [%4.4s], null thread info\n",
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->thread_id != walk_state->thread->thread_id) &&
(obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) {
ACPI_REPORT_ERROR ((
"Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n",
walk_state->thread->thread_id,
acpi_ut_get_node_name (obj_desc->mutex.node),
obj_desc->mutex.owner_thread->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_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n",
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);
/* Release the mutex */
status = acpi_ex_system_release_mutex (obj_desc);
/* Update the mutex and walk state, restore sync_level before acquire */
obj_desc->mutex.owner_thread = NULL;
walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level;
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_release_all_mutexes
*
* PARAMETERS: mutex_list - Head of the mutex list
*
* RETURN: Status
*
* DESCRIPTION: Release all mutexes in the list
*
******************************************************************************/
void
acpi_ex_release_all_mutexes (
struct acpi_thread_state *thread)
{
union acpi_operand_object *next = thread->acquired_mutex_list;
union acpi_operand_object *this;
acpi_status status;
ACPI_FUNCTION_ENTRY ();
/* Traverse the list of owned mutexes, releasing each one */
while (next) {
this = next;
next = this->mutex.next;
this->mutex.acquisition_depth = 1;
this->mutex.prev = NULL;
this->mutex.next = NULL;
/* Release the mutex */
status = acpi_ex_system_release_mutex (this);
if (ACPI_FAILURE (status)) {
continue;
}
/* Mark mutex unowned */
this->mutex.owner_thread = NULL;
/* Update Thread sync_level (Last mutex is the important one) */
thread->current_sync_level = this->mutex.original_sync_level;
}
}

View File

@@ -0,0 +1,427 @@
/******************************************************************************
*
* Module Name: exnames - interpreter/scanner name load/execute
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/* AML Package Length encodings */
#define ACPI_AML_PACKAGE_TYPE1 0x40
#define ACPI_AML_PACKAGE_TYPE2 0x4000
#define ACPI_AML_PACKAGE_TYPE3 0x400000
#define ACPI_AML_PACKAGE_TYPE4 0x40000000
/*******************************************************************************
*
* 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.
*
******************************************************************************/
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_MEM_ALLOCATE (size_needed);
if (!name_string) {
ACPI_REPORT_ERROR (("ex_allocate_name_string: Could not allocate size %d\n", 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: interpreter_mode - Current running mode (load1/Load2/Exec)
*
* RETURN: Status
*
* DESCRIPTION: Execute a name segment (4 bytes)
*
******************************************************************************/
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_DEBUG_PRINT ((ACPI_DB_ERROR, "leading digit: %c\n", 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_character (*aml_address));
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 4 */
status = AE_AML_BAD_NAME;
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n",
*aml_address, aml_address));
}
*in_aml_address = (u8 *) aml_address;
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_get_name_string
*
* PARAMETERS: data_type - Data type to be associated with this name
*
* RETURN: Status
*
* DESCRIPTION: Get a name, 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, "root_prefix(\\) 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, "parent_prefix (^) 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, "dual_name_prefix 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, "multi_name_prefix 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, "name_seg 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_REPORT_ERROR (
("ex_do_name: Malformed Name at %p\n", name_string));
status = AE_AML_BAD_NAME;
}
*out_name_string = name_string;
*out_name_length = (u32) (aml_address - in_aml_address);
return_ACPI_STATUS (status);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,608 @@
/******************************************************************************
*
* Module Name: exoparg2 - AML execution - opcodes with 2 arguments
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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;
/* Notifies allowed on this object? */
if (!acpi_ev_is_notify_object (node)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Unexpected notify object type [%s]\n",
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 "device_wake" 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_REPORT_ERROR (("acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n",
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_REPORT_ERROR (("acpi_ex_opcode_2A_2T_1R: Unknown opcode %X\n",
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;
u32 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++;
if (length > ACPI_MAX_STRING_CONVERSION) {
status = AE_AML_STRING_LIMIT;
goto cleanup;
}
}
/* 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;
}
index = (u32) operand[1]->integer.value;
/*
* At this point, the Source operand is a Package, Buffer, or String
*/
if (ACPI_GET_OBJECT_TYPE (operand[0]) == ACPI_TYPE_PACKAGE) {
/* Object to be indexed is a Package */
if (index >= operand[0]->package.count) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Index value (%X) beyond package end (%X)\n",
index, operand[0]->package.count));
status = AE_AML_PACKAGE_LIMIT;
goto cleanup;
}
return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
return_desc->reference.object = operand[0];
return_desc->reference.where = &operand[0]->package.elements [index];
}
else {
/* Object to be indexed is a Buffer/String */
if (index >= operand[0]->buffer.length) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Index value (%X) beyond end of buffer (%X)\n",
index, operand[0]->buffer.length));
status = AE_AML_BUFFER_LIMIT;
goto cleanup;
}
return_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
return_desc->reference.object = operand[0];
}
/*
* Add a reference to the target package/buffer/string for the life
* of the index.
*/
acpi_ut_add_reference (operand[0]);
/* Complete the Index reference object */
return_desc->reference.opcode = AML_INDEX_OP;
return_desc->reference.offset = index;
/* 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_REPORT_ERROR (("acpi_ex_opcode_2A_1T_1R: Unknown opcode %X\n",
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_REPORT_ERROR (("acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n",
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);
}

View File

@@ -0,0 +1,256 @@
/******************************************************************************
*
* Module Name: exoparg3 - AML execution - opcodes with 3 arguments
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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,
"fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
(u32) operand[0]->integer.value,
(u32) operand[1]->integer.value,
(u32) operand[2]->integer.value));
fatal = ACPI_MEM_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_MEM_FREE (fatal);
break;
default:
ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
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;
acpi_status status = AE_OK;
acpi_native_uint 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 = (acpi_native_uint) 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 */
if ((index + length) >
operand[0]->string.length) {
length = (acpi_size) operand[0]->string.length - index;
}
/* Allocate a new buffer for the String/Buffer */
buffer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1);
if (!buffer) {
status = AE_NO_MEMORY;
goto cleanup;
}
/* 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_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
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)) {
acpi_ut_remove_reference (return_desc);
}
/* Set the return object and exit */
if (!walk_state->result_obj) {
walk_state->result_obj = return_desc;
}
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,336 @@
/******************************************************************************
*
* Module Name: exoparg6 - AML execution - opcodes with 6 arguments
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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.
!*/
/*******************************************************************************
*
* 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).
*
******************************************************************************/
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;
u32 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Match operator out of range\n"));
status = AE_AML_OPERAND_VALUE;
goto cleanup;
}
/* Get the package start_index, validate against the package length */
index = (u32) operand[5]->integer.value;
if (index >= (u32) operand[0]->package.count) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n"));
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_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
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);
}

View File

@@ -0,0 +1,530 @@
/******************************************************************************
*
* Module Name: exprep - ACPI AML (p-code) execution - field prep utilities
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
#ifdef ACPI_UNDER_DEVELOPMENT
/*******************************************************************************
*
* 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,
"access_width %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,
"access_width %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"));
return_VALUE (0); /* Field does not fit in the region at all */
}
/* 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: Access - Encoded field access bits
* Length - Field length.
*
* 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 param */);
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Unknown field access type %X\n",
access));
return_VALUE (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_VALUE (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_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: Node - Owning Node
* region_node - Region in which field is being defined
* field_flags - Access, lock_rule, and update_rule.
* field_bit_position - Field start position
* field_bit_length - Field length in number of bits
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Null region_node\n"));
return_ACPI_STATUS (AE_AML_NO_OPERAND);
}
type = acpi_ns_get_type (info->region_node);
if (type != ACPI_TYPE_REGION) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed Region, found type %X (%s)\n",
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,
"region_field: bit_off %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: bit_off %X, Off %X, Gran %X, Region %p, bank_reg %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:
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);
obj_desc->index_field.value = (u32)
(info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width));
if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
ACPI_REPORT_ERROR (("Null Index Object during field prep\n"));
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);
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"index_field: bit_off %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 named_obj %p [%4.4s], obj_desc %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);
}

View File

@@ -0,0 +1,528 @@
/******************************************************************************
*
* Module Name: exregion - ACPI default op_region (address space) handlers
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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;
#ifndef ACPI_MISALIGNED_TRANSFERS
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid system_memory width %d\n",
bit_width));
return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
}
#ifndef ACPI_MISALIGNED_TRANSFERS
/*
* 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 */
status = acpi_os_map_memory (address, window_size,
(void **) &mem_info->mapped_logical_address);
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n",
ACPI_FORMAT_UINT64 (address), (u32) window_size));
mem_info->mapped_length = 0;
return_ACPI_STATUS (status);
}
/* 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 %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
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) *((u8 *) logical_addr_ptr);
break;
case 16:
*value = (acpi_integer) *((u16 *) logical_addr_ptr);
break;
case 32:
*value = (acpi_integer) *((u32 *) logical_addr_ptr);
break;
#if ACPI_MACHINE_WIDTH != 16
case 64:
*value = (acpi_integer) *((u64 *) logical_addr_ptr);
break;
#endif
default:
/* bit_width was already validated */
break;
}
break;
case ACPI_WRITE:
switch (bit_width) {
case 8:
*(u8 *) logical_addr_ptr = (u8) *value;
break;
case 16:
*(u16 *) logical_addr_ptr = (u16) *value;
break;
case 32:
*(u32 *) logical_addr_ptr = (u32) *value;
break;
#if ACPI_MACHINE_WIDTH != 16
case 64:
*(u64 *) logical_addr_ptr = (u64) *value;
break;
#endif
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 %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
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_status status = AE_OK;
u32 byte_width = ACPI_DIV_8 (bit_width);
u32 i;
char *logical_addr_ptr;
ACPI_FUNCTION_TRACE ("ex_data_table_space_handler");
logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address);
/* Perform the memory read or write */
switch (function) {
case ACPI_READ:
for (i = 0; i < byte_width; i++) {
((char *) value) [i] = logical_addr_ptr[i];
}
break;
case ACPI_WRITE:
default:
return_ACPI_STATUS (AE_SUPPORT);
}
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,289 @@
/******************************************************************************
*
* Module Name: exresnte - AML Interpreter object resolution
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 source_desc=%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) Devices rarely have an attached object, return the Node
* 2) Method locals and arguments have a pseudo-Node
*/
if (entry_type == ACPI_TYPE_DEVICE ||
(node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) {
return_ACPI_STATUS (AE_OK);
}
if (!source_desc) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No object attached to node %p\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Package, type %s\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Buffer, type %s\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a String, type %s\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Integer, type %s\n",
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, "field_read Node=%p source_desc=%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_THERMAL:
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Untyped entry %p, no attached object!\n",
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 */
obj_desc = source_desc;
acpi_ut_add_reference (obj_desc);
break;
default:
/* No named references are allowed here */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n",
source_desc->reference.opcode,
acpi_ps_get_opcode_name (source_desc->reference.opcode)));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
break;
/* Default case is for unknown types */
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Node %p - Unknown object type %X\n",
node, entry_type));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
} /* switch (entry_type) */
/* Put the object descriptor on the stack */
*object_ptr = (void *) obj_desc;
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,546 @@
/******************************************************************************
*
* Module Name: exresolv - AML Interpreter object resolution
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n"));
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);
}
}
/*
* 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 a stack location that contains a
* ptr 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.
*
******************************************************************************/
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;
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 indirect name ptr to a direct name ptr.
* 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);
/* Put direct name pointer onto stack and exit */
(*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] value_obj 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Attempt to deref an Index to NULL pkg element Idx=%p\n",
stack_desc));
status = AE_AML_UNINITIALIZED_ELEMENT;
}
break;
default:
/* Invalid reference object */
ACPI_REPORT_ERROR ((
"During resolve, Unknown target_type %X in Index/Reference obj %p\n",
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;
default:
ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n",
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;
/*
* These cases may never happen here, but just in case..
*/
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, "field_read source_desc=%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);
*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:
/* Dereference the reference pointer */
node = obj_desc->reference.object;
/* All "References" point to a NS node */
if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
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_INT_NAMEPATH_OP:
/* Dereference the reference pointer */
node = obj_desc->reference.node;
/* All "References" point to a NS node */
if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
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_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 "debug_object" */
type = ACPI_TYPE_DEBUG_OBJECT;
goto exit;
default:
ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
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);
}

View File

@@ -0,0 +1,661 @@
/******************************************************************************
*
* Module Name: exresop - AML Interpreter operand/object resolution
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exresop")
/*******************************************************************************
*
* 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
*
******************************************************************************/
acpi_status
acpi_ex_check_object_type (
acpi_object_type type_needed,
acpi_object_type this_type,
void *object)
{
ACPI_FUNCTION_NAME ("ex_check_object_type");
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [%s], found [%s] %p\n",
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;
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_REPORT_ERROR (("resolve_operands: %X is not a valid AML opcode\n",
opcode));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%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_REPORT_ERROR (("resolve_operands: Null stack entry at %p\n",
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:
/* Node */
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad operand object type [%X]\n",
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:
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 */
ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
"Operand is a Reference, ref_opcode [%s]\n",
(acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name)));
break;
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Operand is a Reference, Unknown Reference Opcode %X [%s]\n",
obj_desc->reference.opcode,
(acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
}
break;
default:
/* Invalid descriptor */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Invalid descriptor %p [%s]\n",
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 */
if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ {
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 (AML_NAME_OP == obj_desc->reference.opcode) {
/*
* Convert an indirect name ptr to direct name ptr and put
* it on the stack
*/
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: /* Number */
/*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Integer/String/Buffer], found [%s] %p\n",
acpi_ut_get_object_type_name (obj_desc), obj_desc));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
return_ACPI_STATUS (status);
}
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Integer/String/Buffer], found [%s] %p\n",
acpi_ut_get_object_type_name (obj_desc), obj_desc));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
return_ACPI_STATUS (status);
}
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Integer/String/Buffer], found [%s] %p\n",
acpi_ut_get_object_type_name (obj_desc), obj_desc));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
return_ACPI_STATUS (status);
}
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Integer/String/Buffer], found [%s] %p\n",
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);
}
break;
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Integer/String/Buffer], found [%s] %p\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Buffer/String/Package/Reference], found [%s] %p\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Buffer/String/Package], found [%s] %p\n",
acpi_ut_get_object_type_name (obj_desc), obj_desc));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
goto next_operand;
case ARGI_REGION_OR_FIELD:
/* Need an operand of type ACPI_TYPE_REGION or a FIELD in a region */
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_REGION:
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
case ACPI_TYPE_LOCAL_INDEX_FIELD:
/* Valid operand */
break;
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed [Region/region_field], found [%s] %p\n",
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;
}
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p\n",
acpi_ut_get_object_type_name (obj_desc), obj_desc));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
goto next_operand;
default:
/* Unknown type */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Internal - Unknown ARGI (required operand) type %X\n",
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--;
}
} /* while (*Types) */
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,536 @@
/******************************************************************************
*
* Module Name: exstore - AML Interpreter object store support
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exstore")
/*******************************************************************************
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "Null parameter\n"));
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Target is not a Reference or Constant object - %s [%p]\n",
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, "ex_store",
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_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %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));
break;
}
switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
case ACPI_TYPE_INTEGER:
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]",
(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 Ptr - %p\n",
source_desc->package.count, source_desc->package.elements));
break;
default:
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n",
source_desc));
break;
}
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n"));
break;
default:
ACPI_REPORT_ERROR (("ex_store: Unknown Reference opcode %X\n",
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
*
******************************************************************************/
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 reference 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Source must be Integer/Buffer/String type, not %s\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Target is not a Package or buffer_field\n"));
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) {
/* 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), 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);
}

View File

@@ -0,0 +1,306 @@
/******************************************************************************
*
* Module Name: exstoren - AML Interpreter object store support,
* Store to Node (namespace object)
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Cannot assign type %s to %s (must be type Int/Str/Buf)\n",
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:
/*
* Aliases are resolved by acpi_ex_prep_operands
*/
ACPI_REPORT_ERROR (("Store into Alias - should never happen\n"));
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:
/*
* Note: There is different store behavior depending on the original
* source type
*/
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_DEBUG_PRINT ((ACPI_DB_WARN, "Store into type %s not implemented\n",
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);
}

View File

@@ -0,0 +1,216 @@
/******************************************************************************
*
* Module Name: exstorob - AML Interpreter object store support, store to object
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 = (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_MEM_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 = (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_MEM_FREE (target_desc->string.pointer);
}
target_desc->string.pointer = ACPI_MEM_CALLOCATE ((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);
}

View File

@@ -0,0 +1,378 @@
/******************************************************************************
*
* Module Name: exsystem - Interface to OS services
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 - OSD 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.
*
******************************************************************************/
acpi_status
acpi_ex_system_wait_semaphore (
acpi_handle semaphore,
u16 timeout)
{
acpi_status status;
acpi_status status2;
ACPI_FUNCTION_TRACE ("ex_system_wait_semaphore");
status = acpi_os_wait_semaphore (semaphore, 1, 0);
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_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_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", 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_acquire_mutex
*
* 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 function will cause a lock to be generated
* for the Mutex pointed to by obj_desc.
*
******************************************************************************/
acpi_status
acpi_ex_system_acquire_mutex (
union acpi_operand_object *time_desc,
union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE_PTR ("ex_system_acquire_mutex", obj_desc);
if (!obj_desc) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/*
* Support for the _GL_ Mutex object -- go get the global lock
*/
if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value);
return_ACPI_STATUS (status);
}
status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore,
(u16) time_desc->integer.value);
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_release_mutex
*
* PARAMETERS: *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 release a
* previously acquired Mutex. If the Mutex variable is set then
* it will be decremented.
*
******************************************************************************/
acpi_status
acpi_ex_system_release_mutex (
union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE ("ex_system_release_mutex");
if (!obj_desc) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/*
* Support for the _GL_ Mutex object -- release the global lock
*/
if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
status = acpi_ev_release_global_lock ();
return_ACPI_STATUS (status);
}
status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1);
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_system_signal_event
*
* PARAMETERS: *obj_desc - The object descriptor for this op
*
* RETURN: AE_OK
*
* 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.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.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;
void *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.semaphore);
obj_desc->event.semaphore = temp_semaphore;
}
return (status);
}

View File

@@ -0,0 +1,378 @@
/******************************************************************************
*
* Module Name: exutils - interpreter/scanner utilities
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
#ifndef ACPI_NO_METHOD_EXECUTION
/*******************************************************************************
*
* FUNCTION: acpi_ex_enter_interpreter
*
* PARAMETERS: None
*
* 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_EXECUTE);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Could not acquire interpreter mutex\n"));
}
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_exit_interpreter
*
* PARAMETERS: 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_EXECUTE);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Could not release interpreter mutex\n"));
}
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_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n",
acpi_format_exception (status)));
}
}
return_VALUE (locked);
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_release_global_lock
*
* PARAMETERS: locked_by_me - Return value from corresponding call to
* acquire_global_lock.
*
* RETURN: Status
*
* 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_REPORT_ERROR (("Could not release ACPI Global Lock, %s\n",
acpi_format_exception (status)));
}
}
return_VOID;
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_digits_needed
*
* PARAMETERS: Value - Value to be represented
* Base - Base of representation
*
* RETURN: the number of digits needed to represent Value in Base
*
******************************************************************************/
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_VALUE (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, &current_value, NULL);
num_digits++;
}
return_VALUE (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)
*
* 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: Convert a number to string representation
*
******************************************************************************/
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

302
drivers/acpi/fan.c Normal file
View File

@@ -0,0 +1,302 @@
/*
* acpi_fan.c - ACPI Fan Driver ($Revision: 29 $)
*
* 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_HID "PNP0C0B"
#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver"
#define ACPI_FAN_DEVICE_NAME "Fan"
#define ACPI_FAN_FILE_STATE "state"
#define ACPI_FAN_NOTIFY_STATUS 0x80
#define _COMPONENT ACPI_FAN_COMPONENT
ACPI_MODULE_NAME ("acpi_fan")
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME);
MODULE_LICENSE("GPL");
static int acpi_fan_add (struct acpi_device *device);
static int acpi_fan_remove (struct acpi_device *device, int type);
static struct acpi_driver acpi_fan_driver = {
.name = ACPI_FAN_DRIVER_NAME,
.class = ACPI_FAN_CLASS,
.ids = ACPI_FAN_HID,
.ops = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
},
};
struct acpi_fan {
acpi_handle handle;
};
/* --------------------------------------------------------------------------
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;
ACPI_FUNCTION_TRACE("acpi_fan_read_state");
if (fan) {
if (acpi_bus_get_power(fan->handle, &state))
seq_printf(seq, "status: ERROR\n");
else
seq_printf(seq, "status: %s\n",
!state?"on":"off");
}
return_VALUE(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 = (struct seq_file *)file->private_data;
struct acpi_fan *fan = (struct acpi_fan *) m->private;
char state_string[12] = {'\0'};
ACPI_FUNCTION_TRACE("acpi_fan_write_state");
if (!fan || (count > sizeof(state_string) - 1))
return_VALUE(-EINVAL);
if (copy_from_user(state_string, buffer, count))
return_VALUE(-EFAULT);
state_string[count] = '\0';
result = acpi_bus_set_power(fan->handle,
simple_strtoul(state_string, NULL, 0));
if (result)
return_VALUE(result);
return_VALUE(count);
}
static 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;
ACPI_FUNCTION_TRACE("acpi_fan_add_fs");
if (!device)
return_VALUE(-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_VALUE(-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)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_FAN_FILE_STATE));
else {
entry->proc_fops = &acpi_fan_state_ops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
return_VALUE(0);
}
static int
acpi_fan_remove_fs (
struct acpi_device *device)
{
ACPI_FUNCTION_TRACE("acpi_fan_remove_fs");
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_VALUE(0);
}
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static int
acpi_fan_add (
struct acpi_device *device)
{
int result = 0;
struct acpi_fan *fan = NULL;
int state = 0;
ACPI_FUNCTION_TRACE("acpi_fan_add");
if (!device)
return_VALUE(-EINVAL);
fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL);
if (!fan)
return_VALUE(-ENOMEM);
memset(fan, 0, sizeof(struct acpi_fan));
fan->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_FAN_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
acpi_driver_data(device) = fan;
result = acpi_bus_get_power(fan->handle, &state);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error reading power state\n"));
goto end;
}
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_VALUE(result);
}
static int
acpi_fan_remove (
struct acpi_device *device,
int type)
{
struct acpi_fan *fan = NULL;
ACPI_FUNCTION_TRACE("acpi_fan_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
fan = (struct acpi_fan *) acpi_driver_data(device);
acpi_fan_remove_fs(device);
kfree(fan);
return_VALUE(0);
}
static int __init
acpi_fan_init (void)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_fan_init");
acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
if (!acpi_fan_dir)
return_VALUE(-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_VALUE(-ENODEV);
}
return_VALUE(0);
}
static void __exit
acpi_fan_exit (void)
{
ACPI_FUNCTION_TRACE("acpi_fan_exit");
acpi_bus_unregister_driver(&acpi_fan_driver);
remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
return_VOID;
}
module_init(acpi_fan_init);
module_exit(acpi_fan_exit);

View 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)

View File

@@ -0,0 +1,230 @@
/******************************************************************************
*
* Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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_initialize
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Initialize and validate various ACPI registers
*
******************************************************************************/
acpi_status
acpi_hw_initialize (
void)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("hw_initialize");
/* We must have the ACPI tables by the time we get here */
if (!acpi_gbl_FADT) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "A FADT is not loaded\n"));
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
/* Sanity check the FADT for valid values */
status = acpi_ut_validate_fadt ();
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
return_ACPI_STATUS (AE_OK);
}
/******************************************************************************
*
* 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_cmd) {
ACPI_REPORT_ERROR (("No SMI_CMD in FADT, mode transition failed.\n"));
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_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n"));
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_cmd,
(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_cmd,
(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_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status)));
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_REPORT_ERROR (("Hardware never changed modes\n"));
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_cmd) {
return_VALUE (ACPI_SYS_MODE_ACPI);
}
status = acpi_get_register (ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
if (ACPI_FAILURE (status)) {
return_VALUE (ACPI_SYS_MODE_LEGACY);
}
if (value) {
return_VALUE (ACPI_SYS_MODE_ACPI);
}
else {
return_VALUE (ACPI_SYS_MODE_LEGACY);
}
}

View File

@@ -0,0 +1,444 @@
/******************************************************************************
*
* Module Name: hwgpe - Low level GPE enable/disable/clear functions
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/******************************************************************************
*
* 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;
ACPI_FUNCTION_ENTRY ();
/*
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
status = acpi_hw_low_level_write (8, gpe_event_info->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 = gpe_event_info->register_bit;
/* 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 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 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 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 GPE block. (Includes
* combination wake/run GPEs.)
*
******************************************************************************/
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: Flags - ACPI_NOT_ISR or ACPI_ISR
*
* RETURN: Status
*
* DESCRIPTION: Disable and clear all GPEs
*
******************************************************************************/
acpi_status
acpi_hw_disable_all_gpes (
u32 flags)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("hw_disable_all_gpes");
status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, flags);
status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, flags);
return_ACPI_STATUS (status);
}
/******************************************************************************
*
* FUNCTION: acpi_hw_enable_all_runtime_gpes
*
* PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR
*
* RETURN: Status
*
* DESCRIPTION: Enable all GPEs of the given type
*
******************************************************************************/
acpi_status
acpi_hw_enable_all_runtime_gpes (
u32 flags)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("hw_enable_all_runtime_gpes");
status = acpi_ev_walk_gpe_list (acpi_hw_enable_runtime_gpe_block, flags);
return_ACPI_STATUS (status);
}
/******************************************************************************
*
* FUNCTION: acpi_hw_enable_all_wakeup_gpes
*
* PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR
*
* RETURN: Status
*
* DESCRIPTION: Enable all GPEs of the given type
*
******************************************************************************/
acpi_status
acpi_hw_enable_all_wakeup_gpes (
u32 flags)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("hw_enable_all_wakeup_gpes");
status = acpi_ev_walk_gpe_list (acpi_hw_enable_wakeup_gpe_block, flags);
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,850 @@
/*******************************************************************************
*
* Module Name: hwregs - Read/write access functions for the various ACPI
* control and status registers.
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#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: Flags - Lock the hardware or not
*
* 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 (
u32 flags)
{
acpi_status status;
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_evt_blk.address));
if (flags & ACPI_MTX_LOCK) {
status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
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_evt_blk.address) {
status = acpi_hw_low_level_write (16, ACPI_BITMASK_ALL_FIXED_STATUS,
&acpi_gbl_FADT->xpm1b_evt_blk);
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, ACPI_ISR);
unlock_and_exit:
if (flags & ACPI_MTX_LOCK) {
(void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
}
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_parameter_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);
}
/*
* Evaluate the namespace object containing the values for this state
*/
info.parameters = NULL;
status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state],
&info);
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n",
acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state]));
return_ACPI_STATUS (status);
}
/* Must have a return object */
if (!info.return_object) {
ACPI_REPORT_ERROR (("Missing Sleep State object\n"));
status = AE_NOT_EXIST;
}
/* It must be of type Package */
else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) {
ACPI_REPORT_ERROR (("Sleep State object not a Package\n"));
status = AE_AML_OPERAND_TYPE;
}
/* The package must have at least two elements */
else if (info.return_object->package.count < 2) {
ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n"));
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_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n",
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"While evaluating sleep_state [%s], bad Sleep object %p type %s\n",
acpi_gbl_sleep_state_names[sleep_state], info.return_object,
acpi_ut_get_object_type_name (info.return_object)));
}
acpi_ut_remove_reference (info.return_object);
return_ACPI_STATUS (status);
}
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 bit mask to be used when accessing the register
*
* DESCRIPTION: Map register_id into a register bit mask.
*
******************************************************************************/
struct acpi_bit_register_info *
acpi_hw_get_bit_register_info (
u32 register_id)
{
ACPI_FUNCTION_NAME ("hw_get_bit_register_info");
if (register_id > ACPI_BITREG_MAX) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid bit_register ID: %X\n", 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
* Flags - Lock the hardware or not
*
* 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 flags)
{
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);
}
if (flags & ACPI_MTX_LOCK) {
status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
/* Read from the register */
status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
bit_reg_info->parent_register, &register_value);
if (flags & ACPI_MTX_LOCK) {
(void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
}
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);
}
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
* Flags - Lock the hardware or not
*
* RETURN: Status
*
* DESCRIPTION: ACPI Bit Register write function.
*
******************************************************************************/
acpi_status
acpi_set_register (
u32 register_id,
u32 value,
u32 flags)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
acpi_status status;
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_REPORT_ERROR (("Bad ACPI HW register_id: %X\n", register_id));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
if (flags & ACPI_MTX_LOCK) {
status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
/* 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, &register_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, &register_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_cnt_blk.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_cnt_blk.address)));
status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM2_CONTROL, (u8) (register_value));
break;
default:
break;
}
unlock_and_exit:
if (flags & ACPI_MTX_LOCK) {
(void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
}
/* 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);
}
EXPORT_SYMBOL(acpi_set_register);
/******************************************************************************
*
* FUNCTION: acpi_hw_register_read
*
* PARAMETERS: use_lock - Mutex hw access
* register_id - register_iD + Offset
* return_value - Value that was read from the register
*
* RETURN: Status and the value read.
*
* DESCRIPTION: Acpi register read function. Registers are read at the
* given offset.
*
******************************************************************************/
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_FUNCTION_TRACE ("hw_register_read");
if (ACPI_MTX_LOCK == use_lock) {
status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
switch (register_id) {
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->xpm1a_evt_blk);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
/* PM1B is optional */
status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->xpm1b_evt_blk);
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_cnt_blk);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->xpm1b_cnt_blk);
value1 |= value2;
break;
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
status = acpi_hw_low_level_read (8, &value1, &acpi_gbl_FADT->xpm2_cnt_blk);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status = acpi_hw_low_level_read (32, &value1, &acpi_gbl_FADT->xpm_tmr_blk);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
status = acpi_os_read_port (acpi_gbl_FADT->smi_cmd, &value1, 8);
break;
default:
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id));
status = AE_BAD_PARAMETER;
break;
}
unlock_and_exit:
if (ACPI_MTX_LOCK == use_lock) {
(void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
}
if (ACPI_SUCCESS (status)) {
*return_value = value1;
}
return_ACPI_STATUS (status);
}
/******************************************************************************
*
* FUNCTION: acpi_hw_register_write
*
* PARAMETERS: use_lock - Mutex hw access
* register_id - register_iD + Offset
* Value - The value to write
*
* RETURN: Status
*
* DESCRIPTION: Acpi register Write function. Registers are written at the
* given offset.
*
******************************************************************************/
acpi_status
acpi_hw_register_write (
u8 use_lock,
u32 register_id,
u32 value)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("hw_register_write");
if (ACPI_MTX_LOCK == use_lock) {
status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
switch (register_id) {
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_evt_blk);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
/* PM1B is optional */
status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_evt_blk);
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 */
status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_cnt_blk);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_cnt_blk);
break;
case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_cnt_blk);
break;
case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_cnt_blk);
break;
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
status = acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->xpm2_cnt_blk);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status = acpi_hw_low_level_write (32, value, &acpi_gbl_FADT->xpm_tmr_blk);
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_cmd, value, 8);
break;
default:
status = AE_BAD_PARAMETER;
break;
}
unlock_and_exit:
if (ACPI_MTX_LOCK == use_lock) {
(void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
}
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, &reg->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->address_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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Unsupported address space: %X\n", reg->address_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->address_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, &reg->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->address_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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Unsupported address space: %X\n", reg->address_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->address_space_id)));
return (status);
}

View File

@@ -0,0 +1,582 @@
/******************************************************************************
*
* Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#include <acpi/acpi.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME ("hwsleep")
#define METHOD_NAME__BFS "\\_BFS"
#define METHOD_NAME__GTS "\\_GTS"
#define METHOD_NAME__PTS "\\_PTS"
#define METHOD_NAME__SST "\\_SI._SST"
#define METHOD_NAME__WAK "\\_WAK"
#define ACPI_SST_INDICATOR_OFF 0
#define ACPI_SST_WORKING 1
#define ACPI_SST_WAKING 2
#define ACPI_SST_SLEEPING 3
#define ACPI_SST_SLEEP_CONTEXT 4
/******************************************************************************
*
* FUNCTION: acpi_set_firmware_waking_vector
*
* PARAMETERS: physical_address - Physical address of ACPI real mode
* entry point.
*
* RETURN: Status
*
* DESCRIPTION: access function for d_firmware_waking_vector field in FACS
*
******************************************************************************/
acpi_status
acpi_set_firmware_waking_vector (
acpi_physical_address physical_address)
{
ACPI_FUNCTION_TRACE ("acpi_set_firmware_waking_vector");
/* Set the vector */
if (acpi_gbl_common_fACS.vector_width == 32) {
*(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector))
= (u32) physical_address;
}
else {
*acpi_gbl_common_fACS.firmware_waking_vector
= physical_address;
}
return_ACPI_STATUS (AE_OK);
}
/******************************************************************************
*
* FUNCTION: acpi_get_firmware_waking_vector
*
* PARAMETERS: *physical_address - Output buffer where contents of
* the firmware_waking_vector field of
* the FACS will be stored.
*
* RETURN: Status
*
* DESCRIPTION: Access function for firmware_waking_vector field in FACS
*
******************************************************************************/
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_get_firmware_waking_vector (
acpi_physical_address *physical_address)
{
ACPI_FUNCTION_TRACE ("acpi_get_firmware_waking_vector");
if (!physical_address) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/* Get the vector */
if (acpi_gbl_common_fACS.vector_width == 32) {
*physical_address = (acpi_physical_address)
*(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector));
}
else {
*physical_address =
*acpi_gbl_common_fACS.firmware_waking_vector;
}
return_ACPI_STATUS (AE_OK);
}
#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 indicator 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_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
}
return_ACPI_STATUS (AE_OK);
}
/******************************************************************************
*
* 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_REPORT_ERROR (("Sleep values out of range: A=%X B=%X\n",
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, ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* Clear all fixed and general purpose status bits */
status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/*
* 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs
*/
status = acpi_hw_disable_all_gpes (ACPI_ISR);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
acpi_gbl_system_awake_and_running = FALSE;
status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR);
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, ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* Spin until we wake */
} while (!in_value);
return_ACPI_STATUS (AE_OK);
}
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, ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/*
* 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs
*/
status = acpi_hw_disable_all_gpes (ACPI_ISR);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
acpi_gbl_system_awake_and_running = FALSE;
status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
ACPI_FLUSH_CPU_CACHE ();
status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8);
do {
acpi_os_stall(1000);
status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
} while (!in_value);
return_ACPI_STATUS (AE_OK);
}
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_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
}
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_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
}
status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
}
/* 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 (ACPI_NOT_ISR);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
acpi_gbl_system_awake_and_running = TRUE;
status = acpi_hw_enable_all_runtime_gpes (ACPI_NOT_ISR);
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, ACPI_MTX_DO_NOT_LOCK);
(void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id,
1, ACPI_MTX_DO_NOT_LOCK);
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_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
}
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,203 @@
/******************************************************************************
*
* Name: hwtimer.c - ACPI Power Management Timer Interface
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#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 (0 == acpi_gbl_FADT->tmr_val_ext) {
*resolution = 24;
}
else {
*resolution = 32;
}
return_ACPI_STATUS (AE_OK);
}
/******************************************************************************
*
* FUNCTION: acpi_get_timer
*
* PARAMETERS: Ticks - Where the timer value is returned
*
* RETURN: Status and current 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_tmr_blk);
return_ACPI_STATUS (status);
}
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 (0 == acpi_gbl_FADT->tmr_val_ext) {
/* 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, &quotient, NULL);
*time_elapsed = (u32) quotient;
return_ACPI_STATUS (status);
}
EXPORT_SYMBOL(acpi_get_timer_duration);

1242
drivers/acpi/ibm_acpi.c Normal file

File diff suppressed because it is too large Load Diff

177
drivers/acpi/motherboard.c Normal file
View File

@@ -0,0 +1,177 @@
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME ("acpi_motherboard")
/* Dell use PNP0C01 instead of PNP0C02 */
#define ACPI_MB_HID1 "PNP0C01"
#define ACPI_MB_HID2 "PNP0C02"
/**
* Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
* Doesn't care about the failure of 'request_region', since other may reserve
* the io ports as well
*/
#define IS_RESERVED_ADDR(base, len) \
(((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
&& ((base) + (len) > PCIBIOS_MIN_IO))
/*
* Clearing the flag (IORESOURCE_BUSY) allows drivers to use
* the io ports if they really know they can use it, while
* still preventing hotplug PCI devices from using it.
*/
static acpi_status
acpi_reserve_io_ranges (struct acpi_resource *res, void *data)
{
struct resource *requested_res = NULL;
ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges");
if (res->id == ACPI_RSTYPE_IO) {
struct acpi_resource_io *io_res = &res->data.io;
if (io_res->min_base_address != io_res->max_base_address)
return_VALUE(AE_OK);
if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n",
io_res->min_base_address,
io_res->min_base_address + io_res->range_length));
requested_res = request_region(io_res->min_base_address,
io_res->range_length, "motherboard");
}
} else if (res->id == ACPI_RSTYPE_FIXED_IO) {
struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io;
if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n",
fixed_io_res->base_address,
fixed_io_res->base_address + fixed_io_res->range_length));
requested_res = request_region(fixed_io_res->base_address,
fixed_io_res->range_length, "motherboard");
}
} else {
/* Memory mapped IO? */
}
if (requested_res)
requested_res->flags &= ~IORESOURCE_BUSY;
return_VALUE(AE_OK);
}
static int acpi_motherboard_add (struct acpi_device *device)
{
if (!device)
return -EINVAL;
acpi_walk_resources(device->handle, METHOD_NAME__CRS,
acpi_reserve_io_ranges, NULL);
return 0;
}
static struct acpi_driver acpi_motherboard_driver1 = {
.name = "motherboard",
.class = "",
.ids = ACPI_MB_HID1,
.ops = {
.add = acpi_motherboard_add,
},
};
static struct acpi_driver acpi_motherboard_driver2 = {
.name = "motherboard",
.class = "",
.ids = ACPI_MB_HID2,
.ops = {
.add = acpi_motherboard_add,
},
};
static void __init
acpi_reserve_resources (void)
{
if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
request_region(acpi_gbl_FADT->xpm1a_evt_blk.address,
acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK");
if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
request_region(acpi_gbl_FADT->xpm1b_evt_blk.address,
acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK");
if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address,
acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK");
if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address,
acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK");
if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4)
request_region(acpi_gbl_FADT->xpm_tmr_blk.address,
4, "PM_TMR");
if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len)
request_region(acpi_gbl_FADT->xpm2_cnt_blk.address,
acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK");
/* Length of GPE blocks must be a non-negative multiple of 2 */
if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len &&
!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
request_region(acpi_gbl_FADT->xgpe0_blk.address,
acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK");
if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len &&
!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
request_region(acpi_gbl_FADT->xgpe1_blk.address,
acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK");
}
static int __init acpi_motherboard_init(void)
{
acpi_bus_register_driver(&acpi_motherboard_driver1);
acpi_bus_register_driver(&acpi_motherboard_driver2);
/*
* Guarantee motherboard IO reservation first
* This module must run after scan.c
*/
if (!acpi_disabled)
acpi_reserve_resources ();
return 0;
}
/**
* Reserve motherboard resources after PCI claim BARs,
* but before PCI assign resources for uninitialized PCI devices
*/
fs_initcall(acpi_motherboard_init);

View 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)

View File

@@ -0,0 +1,637 @@
/*******************************************************************************
*
* Module Name: nsaccess - Top-level functions for accessing ACPI namespace
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not create predefined name %s, %s\n",
init_val->name, acpi_format_exception (status)));
}
/*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not override predefined %s\n",
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) || defined (_ACPI_DUMP_App)
/*
* i_aSL Compiler cheats by putting parameter count
* in the owner_iD
*/
new_node->owner_id = obj_desc->method.param_count;
#else
/* Mark this as a very SPECIAL method */
obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY;
obj_desc->method.implementation = acpi_ut_osi_implementation;
#endif
break;
case ACPI_TYPE_INTEGER:
obj_desc->integer.value = ACPI_TO_INTEGER (val);
break;
case ACPI_TYPE_STRING:
/*
* Build an object around the static string
*/
obj_desc->string.length = (u32) 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);
if (ACPI_STRCMP (init_val->name, "_GL_") == 0) {
/*
* Create a counting semaphore for the
* global lock
*/
status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT,
1, &obj_desc->mutex.semaphore);
if (ACPI_FAILURE (status)) {
acpi_ut_remove_reference (obj_desc);
goto unlock_and_exit;
}
/*
* We just created the mutex for the
* global lock, save it
*/
acpi_gbl_global_lock_semaphore = obj_desc->mutex.semaphore;
}
else {
/* Create a mutex */
status = acpi_os_create_semaphore (1, 1,
&obj_desc->mutex.semaphore);
if (ACPI_FAILURE (status)) {
acpi_ut_remove_reference (obj_desc);
goto unlock_and_exit;
}
}
break;
default:
ACPI_REPORT_ERROR (("Unsupported initial type value %X\n",
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_by_path ("\\_GPE", NULL, ACPI_NS_NO_UPSEARCH,
&acpi_gbl_fadt_gpe_device);
}
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_lookup
*
* PARAMETERS: prefix_node - Search scope if name is not fully qualified
* 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 = flags & ~(ACPI_NS_ERROR_IF_FOUND |
ACPI_NS_SEARCH_PARENT);
ACPI_FUNCTION_TRACE ("ns_lookup");
if (!return_node) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
acpi_gbl_ns_lookup_count++;
*return_node = ACPI_ENTRY_NOT_FOUND;
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_REPORT_ERROR (("ns_lookup: %p is not a namespace node [%s]\n",
prefix_node, acpi_ut_get_descriptor_name (prefix_node)));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
/*
* 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_REPORT_ERROR (
("ACPI path has too many parent prefixes (^) - reached beyond root node\n"));
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 *) &current_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_REPORT_WARNING (
("ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)\n",
(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);
}

View File

@@ -0,0 +1,685 @@
/*******************************************************************************
*
* Module Name: nsalloc - Namespace allocation and deletion utilities
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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: acpi_name - Name of the new node
*
* RETURN: None
*
* DESCRIPTION: Create a namespace node
*
******************************************************************************/
struct acpi_namespace_node *
acpi_ns_create_node (
u32 name)
{
struct acpi_namespace_node *node;
ACPI_FUNCTION_TRACE ("ns_create_node");
node = ACPI_MEM_CALLOCATE (sizeof (struct acpi_namespace_node));
if (!node) {
return_PTR (NULL);
}
ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_allocated++);
node->name.integer = name;
node->reference_count = 1;
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_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++);
/*
* Detach an object if there is one then delete the node
*/
acpi_ns_detach_object (node);
ACPI_MEM_FREE (node);
return_VOID;
}
#ifdef ACPI_ALPHABETIC_NAMESPACE
/*******************************************************************************
*
* FUNCTION: acpi_ns_compare_names
*
* PARAMETERS: Name1 - First name to compare
* Name2 - Second name to compare
*
* RETURN: value from strncmp
*
* DESCRIPTION: Compare two ACPI names. Names that are prefixed with an
* underscore are forced to be alphabetically first.
*
******************************************************************************/
int
acpi_ns_compare_names (
char *name1,
char *name2)
{
char reversed_name1[ACPI_NAME_SIZE];
char reversed_name2[ACPI_NAME_SIZE];
u32 i;
u32 j;
/*
* Replace all instances of "underscore" with a value that is smaller so
* that all names that are prefixed with underscore(s) are alphabetically
* first.
*
* Reverse the name bytewise so we can just do a 32-bit compare instead
* of a strncmp.
*/
for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) {
reversed_name1[j] = name1[i];
if (name1[i] == '_') {
reversed_name1[j] = '*';
}
reversed_name2[j] = name2[i];
if (name2[i] == '_') {
reversed_name2[j] = '*';
}
}
return (*(int *) reversed_name1 - *(int *) reversed_name2);
}
#endif
/*******************************************************************************
*
* 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. However, the
* nodes are linked in alphabetical order to 1) put all reserved
* names (start with underscore) first, and to 2) make a readable
* namespace dump.
*
******************************************************************************/
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)
{
u16 owner_id = 0;
struct acpi_namespace_node *child_node;
#ifdef ACPI_ALPHABETIC_NAMESPACE
struct acpi_namespace_node *previous_child_node;
#endif
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 {
#ifdef ACPI_ALPHABETIC_NAMESPACE
/*
* Walk the list whilst searching for the correct
* alphabetic placement.
*/
previous_child_node = NULL;
while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) {
if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
/* Last peer; Clear end-of-list flag */
child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
/* This node is the new peer to the child node */
child_node->peer = node;
/* This node is the new end-of-list */
node->flags |= ANOBJ_END_OF_PEER_LIST;
node->peer = parent_node;
break;
}
/* Get next peer */
previous_child_node = child_node;
child_node = child_node->peer;
}
/* Did the node get inserted at the end-of-list? */
if (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
/*
* Loop above terminated without reaching the end-of-list.
* Insert the new node at the current location
*/
if (previous_child_node) {
/* Insert node alphabetically */
node->peer = child_node;
previous_child_node->peer = node;
}
else {
/* Insert node alphabetically at start of list */
node->peer = child_node;
parent_node->child = 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;
#endif
}
/* 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));
/*
* Increment the reference count(s) of all parents up to
* the root!
*/
while ((node = acpi_ns_get_parent_node (node)) != NULL) {
node->reference_count++;
}
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;
struct acpi_namespace_node *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_DEBUG_PRINT ((ACPI_DB_ERROR, "Found a grandchild! P=%p C=%p\n",
parent_node, child_node));
}
/* Now we can free this child object */
ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].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);
/*
* Decrement the reference count(s) of all parents up to
* the root! (counts were incremented when the node was created)
*/
node = child_node;
while ((node = acpi_ns_get_parent_node (node)) != NULL) {
node->reference_count--;
}
/* There should be only one reference remaining on this node */
if (child_node->reference_count != 1) {
ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n",
child_node->reference_count, child_node));
}
/* Now we can delete the node */
ACPI_MEM_FREE (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_remove_reference
*
* PARAMETERS: Node - Named node whose reference count is to be
* decremented
*
* RETURN: None.
*
* DESCRIPTION: Remove a Node reference. Decrements the reference count
* of all parent Nodes up to the root. Any node along
* the way that reaches zero references is freed.
*
******************************************************************************/
void
acpi_ns_remove_reference (
struct acpi_namespace_node *node)
{
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *this_node;
ACPI_FUNCTION_ENTRY ();
/*
* Decrement the reference count(s) of this node and all
* nodes up to the root, Delete anything with zero remaining references.
*/
this_node = node;
while (this_node) {
/* Prepare to move up to parent */
parent_node = acpi_ns_get_parent_node (this_node);
/* Decrement the reference count on this node */
this_node->reference_count--;
/* Delete the node if no more references */
if (!this_node->reference_count) {
/* Delete all children and delete the node */
acpi_ns_delete_children (this_node);
acpi_ns_delete_node (this_node);
}
this_node = parent_node;
}
}
/*******************************************************************************
*
* 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.
*
******************************************************************************/
void
acpi_ns_delete_namespace_by_owner (
u16 owner_id)
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *deletion_node;
u32 level;
struct acpi_namespace_node *parent_node;
ACPI_FUNCTION_TRACE_U32 ("ns_delete_namespace_by_owner", owner_id);
parent_node = acpi_gbl_root_node;
child_node = NULL;
deletion_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_remove_reference (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);
}
}
return_VOID;
}

View File

@@ -0,0 +1,673 @@
/******************************************************************************
*
* Module Name: nsdump - table dumping routines for debug
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/*******************************************************************************
*
* FUNCTION: acpi_ns_print_pathname
*
* PARAMETERS: num_segment - Number of ACPI name segments
* Pathname - The compressed (internal) path
*
* DESCRIPTION: Print an object's full namespace pathname
*
******************************************************************************/
void
acpi_ns_print_pathname (
u32 num_segments,
char *pathname)
{
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) {
acpi_os_printf ("%4.4s", pathname);
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
*
* 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: Handle - Node to be dumped
* Level - Nesting level of the handle
* Context - Passed into walk_namespace
*
* 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_UINT32_MAX) &&
(info->owner_id != this_node->owner_id)) {
return (AE_OK);
}
/* 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_REPORT_WARNING (("Invalid ACPI Type %08X\n", type));
}
if (!acpi_ut_valid_acpi_name (this_node->name.integer)) {
ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n",
this_node->name.integer));
}
/*
* Now we can print out the pertinent information
*/
acpi_os_printf ("%4.4s %-12s %p ",
acpi_ut_get_node_name (this_node), acpi_ut_get_type_name (type), this_node);
dbg_level = acpi_dbg_level;
acpi_dbg_level = 0;
obj_desc = acpi_ns_get_attached_object (this_node);
acpi_dbg_level = dbg_level;
switch (info->display_type) {
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);
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 %s, %X)\n",
acpi_ut_get_type_name (obj_type), obj_type);
bytes_to_dump = sizeof (union acpi_operand_object);
}
break;
default:
acpi_os_printf (
"(String or Buffer ptr - not an object descriptor) [%s]\n",
acpi_ut_get_descriptor_name (obj_desc));
bytes_to_dump = 16;
break;
}
ACPI_DUMP_BUFFER (obj_desc, bytes_to_dump);
/* 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_STRING:
obj_desc = (void *) obj_desc->string.pointer;
break;
case ACPI_TYPE_BUFFER:
obj_desc = (void *) obj_desc->buffer.pointer;
break;
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
* 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
*
* 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,
u32 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_dump_one_object,
(void *) &info, NULL);
}
/*******************************************************************************
*
* 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.
*
* 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_UINT32_MAX, search_handle);
return_VOID;
}
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
*
* FUNCTION: acpi_ns_dump_entry
*
* PARAMETERS: Handle - Node to be dumped
* debug_level - Output level
*
* 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_UINT32_MAX;
info.display_type = ACPI_DISPLAY_SUMMARY;
(void) acpi_ns_dump_one_object (handle, 1, &info, NULL);
}
#endif

View File

@@ -0,0 +1,146 @@
/******************************************************************************
*
* Module Name: nsdump - table dumping routines for debug
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 ("nsdumpdv")
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/*******************************************************************************
*
* FUNCTION: acpi_ns_dump_one_device
*
* PARAMETERS: Handle - Node to be dumped
* Level - Nesting level of the handle
* Context - Passed into walk_namespace
*
* DESCRIPTION: Dump a single Node that represents a device
* This procedure is a user_function called by acpi_ns_walk_namespace.
*
******************************************************************************/
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_MEM_FREE (info);
}
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_dump_root_devices
*
* PARAMETERS: 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

View File

@@ -0,0 +1,487 @@
/*******************************************************************************
*
* Module Name: nseval - Object evaluation interfaces -- includes control
* method lookup and execution.
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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_relative
*
* PARAMETERS: Pathname - Name of method to execute, If NULL, the
* handle is the object to execute
* Info - Method info block
*
* RETURN: Status
*
* DESCRIPTION: Find and execute the requested method using the handle as a
* scope
*
* MUTEX: Locks Namespace
*
******************************************************************************/
acpi_status
acpi_ns_evaluate_relative (
char *pathname,
struct acpi_parameter_info *info)
{
acpi_status status;
struct acpi_namespace_node *node = NULL;
union acpi_generic_state *scope_info;
char *internal_path = NULL;
ACPI_FUNCTION_TRACE ("ns_evaluate_relative");
/*
* Must have a valid object handle
*/
if (!info || !info->node) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/* Build an internal name string for the method */
status = acpi_ns_internalize_name (pathname, &internal_path);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
scope_info = acpi_ut_create_generic_state ();
if (!scope_info) {
goto cleanup1;
}
/* Get the prefix handle and Node */
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
info->node = acpi_ns_map_handle_to_node (info->node);
if (!info->node) {
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
status = AE_BAD_PARAMETER;
goto cleanup;
}
/* Lookup the name in the namespace */
scope_info->scope.node = info->node;
status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY,
ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
&node);
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object [%s] not found [%s]\n",
pathname, acpi_format_exception (status)));
goto cleanup;
}
/*
* Now that we have a handle to the object, we can attempt to evaluate it.
*/
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
pathname, node, acpi_ns_get_attached_object (node)));
info->node = node;
status = acpi_ns_evaluate_by_handle (info);
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n",
pathname));
cleanup:
acpi_ut_delete_generic_state (scope_info);
cleanup1:
ACPI_MEM_FREE (internal_path);
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_evaluate_by_name
*
* PARAMETERS: Pathname - Fully qualified pathname to the object
* Info - Contains:
* return_object - Where to put method's return value (if
* any). If NULL, no value is returned.
* Params - List of parameters to pass to the method,
* terminated by NULL. Params itself may be
* NULL if no parameters are being passed.
*
* RETURN: Status
*
* DESCRIPTION: Find and execute the requested method passing the given
* parameters
*
* MUTEX: Locks Namespace
*
******************************************************************************/
acpi_status
acpi_ns_evaluate_by_name (
char *pathname,
struct acpi_parameter_info *info)
{
acpi_status status;
char *internal_path = NULL;
ACPI_FUNCTION_TRACE ("ns_evaluate_by_name");
/* Build an internal name string for the method */
status = acpi_ns_internalize_name (pathname, &internal_path);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
/* Lookup the name in the namespace */
status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY,
ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
&info->node);
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
"Object at [%s] was not found, status=%.4X\n",
pathname, status));
goto cleanup;
}
/*
* Now that we have a handle to the object, we can attempt to evaluate it.
*/
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
pathname, info->node, acpi_ns_get_attached_object (info->node)));
status = acpi_ns_evaluate_by_handle (info);
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n",
pathname));
cleanup:
/* Cleanup */
if (internal_path) {
ACPI_MEM_FREE (internal_path);
}
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_evaluate_by_handle
*
* PARAMETERS: Handle - Method Node to execute
* Params - List of parameters to pass to the method,
* terminated by NULL. Params itself may be
* NULL if no parameters are being passed.
* param_type - Type of Parameter list
* return_object - Where to put method's return value (if
* any). If NULL, no value is returned.
*
* RETURN: Status
*
* DESCRIPTION: Execute the requested method passing the given parameters
*
* MUTEX: Locks Namespace
*
******************************************************************************/
acpi_status
acpi_ns_evaluate_by_handle (
struct acpi_parameter_info *info)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle");
/* Check if namespace has been initialized */
if (!acpi_gbl_root_node) {
return_ACPI_STATUS (AE_NO_NAMESPACE);
}
/* Parameter Validation */
if (!info) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/* Initialize the return value to an invalid object */
info->return_object = NULL;
/* Get the prefix handle and Node */
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
info->node = acpi_ns_map_handle_to_node (info->node);
if (!info->node) {
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/*
* For a method alias, we must grab the actual method node so that proper
* scoping context will be established before execution.
*/
if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object);
}
/*
* Two major cases here:
* 1) The object is an actual control method -- execute it.
* 2) The object is not a method -- just return it's current value
*
* In both cases, the namespace is unlocked by the acpi_ns* procedure
*/
if (acpi_ns_get_type (info->node) == ACPI_TYPE_METHOD) {
/*
* Case 1) We have an actual control method to execute
*/
status = acpi_ns_execute_control_method (info);
}
else {
/*
* Case 2) Object is NOT a method, just return its current value
*/
status = acpi_ns_get_object_value (info);
}
/*
* Check if there is a return value on the stack that must be dealt with
*/
if (status == AE_CTRL_RETURN_VALUE) {
/* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
status = AE_OK;
}
/*
* Namespace was unlocked by the handling acpi_ns* function, so we
* just return
*/
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_execute_control_method
*
* PARAMETERS: Info - Method info block (w/params)
*
* RETURN: Status
*
* DESCRIPTION: Execute the requested method passing the given parameters
*
* MUTEX: Assumes namespace is locked
*
******************************************************************************/
acpi_status
acpi_ns_execute_control_method (
struct acpi_parameter_info *info)
{
acpi_status status;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_TRACE ("ns_execute_control_method");
/* Verify that there is a method associated with this object */
obj_desc = acpi_ns_get_attached_object (info->node);
if (!obj_desc) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n"));
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (AE_NULL_OBJECT);
}
ACPI_DUMP_PATHNAME (info->node, "Execute Method:",
ACPI_LV_INFO, _COMPONENT);
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n",
obj_desc->method.aml_start + 1, obj_desc->method.aml_length - 1));
/*
* Unlock the namespace before execution. This allows namespace access
* via the external Acpi* interfaces while a method is being executed.
* However, 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.
*/
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/*
* 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_psx_execute (info);
acpi_ex_exit_interpreter ();
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_get_object_value
*
* PARAMETERS: Info - Method info block (w/params)
*
* RETURN: Status
*
* DESCRIPTION: Return the current value of the object
*
* MUTEX: Assumes namespace is locked, leaves namespace unlocked
*
******************************************************************************/
acpi_status
acpi_ns_get_object_value (
struct acpi_parameter_info *info)
{
acpi_status status = AE_OK;
struct acpi_namespace_node *resolved_node = info->node;
ACPI_FUNCTION_TRACE ("ns_get_object_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. This call always
* deletes obj_desc (allocated above).
*
* NOTE: we can get away with passing in NULL for a walk state because
* obj_desc is guaranteed to not be a reference to either a method local or
* a method argument (because this interface can only be called from the
* acpi_evaluate external interface, never called from a running method.)
*
* Even though we do not directly invoke the interpreter for this, we must
* enter it because we could access an opregion. The opregion access code
* assumes that the interpreter is locked.
*
* We must release the namespace lock before entering the intepreter.
*/
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
status = acpi_ex_enter_interpreter ();
if (ACPI_SUCCESS (status)) {
status = acpi_ex_resolve_node_to_value (&resolved_node, NULL);
/*
* If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
* in resolved_node.
*/
acpi_ex_exit_interpreter ();
if (ACPI_SUCCESS (status)) {
status = AE_CTRL_RETURN_VALUE;
info->return_object = ACPI_CAST_PTR
(union acpi_operand_object, 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)));
}
}
/* Namespace is unlocked */
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,441 @@
/******************************************************************************
*
* Module Name: nsinit - namespace initialization
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsinit")
/*******************************************************************************
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n",
acpi_format_exception (status)));
}
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,
"Executing all Device _STA and_INI methods:"));
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* Walk namespace for all objects */
status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL);
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n",
acpi_format_exception (status)));
}
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
"\n%hd Devices found containing: %hd _STA, %hd _INI methods\n",
info.device_count, info.num_STA, info.num_INI));
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
*
******************************************************************************/
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_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n"));
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not execute arguments for [%4.4s] (%s), %s\n",
acpi_ut_get_node_name (node), acpi_ut_get_type_name (type),
acpi_format_exception (status)));
}
/*
* 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_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.
*
******************************************************************************/
acpi_status
acpi_ns_init_one_device (
acpi_handle obj_handle,
u32 nesting_level,
void *context,
void **return_value)
{
struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context;
struct acpi_parameter_info pinfo;
u32 flags;
acpi_status status;
ACPI_FUNCTION_TRACE ("ns_init_one_device");
pinfo.parameters = NULL;
pinfo.parameter_type = ACPI_PARAM_ARGS;
pinfo.node = acpi_ns_map_handle_to_node (obj_handle);
if (!pinfo.node) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/*
* We will run _STA/_INI on Devices, Processors and thermal_zones only
*/
if ((pinfo.node->type != ACPI_TYPE_DEVICE) &&
(pinfo.node->type != ACPI_TYPE_PROCESSOR) &&
(pinfo.node->type != ACPI_TYPE_THERMAL)) {
return_ACPI_STATUS (AE_OK);
}
if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
(!(acpi_dbg_level & ACPI_LV_INFO))) {
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
}
info->device_count++;
/*
* Run _STA to determine if we can run _INI on the device.
*/
ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA"));
status = acpi_ut_execute_STA (pinfo.node, &flags);
if (ACPI_FAILURE (status)) {
if (pinfo.node->type == ACPI_TYPE_DEVICE) {
/* Ignore error and move on to next device */
return_ACPI_STATUS (AE_OK);
}
/* _STA is not required for Processor or thermal_zone objects */
}
else {
info->num_STA++;
if (!(flags & 0x01)) {
/* Don't look at children of a not present device */
return_ACPI_STATUS(AE_CTRL_DEPTH);
}
}
/*
* The device is present. Run _INI.
*/
ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI"));
status = acpi_ns_evaluate_relative ("_INI", &pinfo);
if (ACPI_FAILURE (status)) {
/* No _INI (AE_NOT_FOUND) means device requires no initialization */
if (status != AE_NOT_FOUND) {
/* Ignore error and move on to next device */
#ifdef ACPI_DEBUG_OUTPUT
char *scope_name = acpi_ns_get_external_pathname (pinfo.node);
ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n",
scope_name, acpi_format_exception (status)));
ACPI_MEM_FREE (scope_name);
#endif
}
status = AE_OK;
}
else {
/* Delete any return object (especially if implicit_return is enabled) */
if (pinfo.return_object) {
acpi_ut_remove_reference (pinfo.return_object);
}
/* Count of successful INIs */
info->num_INI++;
}
if (acpi_gbl_init_handler) {
/* External initialization handler is present, call it */
status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI);
}
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,460 @@
/******************************************************************************
*
* Module Name: nsload - namespace loading/expanding/contracting procedures
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsload")
#ifndef ACPI_NO_METHOD_EXECUTION
/*******************************************************************************
*
* FUNCTION: acpi_ns_load_table
*
* PARAMETERS: table_desc - Descriptor 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 (
struct acpi_table_desc *table_desc,
struct acpi_namespace_node *node)
{
acpi_status status;
ACPI_FUNCTION_TRACE ("ns_load_table");
/* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
if (!(acpi_gbl_table_data[table_desc->type].flags & ACPI_TABLE_EXECUTABLE)) {
/* Just ignore this table */
return_ACPI_STATUS (AE_OK);
}
/* Check validity of the AML start and length */
if (!table_desc->aml_start) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null AML pointer\n"));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AML block at %p\n",
table_desc->aml_start));
/* Ignore table if there is no AML contained within */
if (!table_desc->aml_length) {
ACPI_REPORT_WARNING (("Zero-length AML block in table [%4.4s]\n",
table_desc->pointer->signature));
return_ACPI_STATUS (AE_OK);
}
/*
* 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!
*/
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"**** Loading table into namespace ****\n"));
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
status = acpi_ns_parse_table (table_desc, node->child);
(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_desc, node);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"**** Completed Table Method Parsing and Object Initialization ****\n"));
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_load_table_by_type
*
* PARAMETERS: table_type - Id of the table type to load
*
* RETURN: Status
*
* DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
* of the given type are loaded. The mechanism allows this
* routine to be called repeatedly.
*
******************************************************************************/
acpi_status
acpi_ns_load_table_by_type (
acpi_table_type table_type)
{
u32 i;
acpi_status status;
struct acpi_table_desc *table_desc;
ACPI_FUNCTION_TRACE ("ns_load_table_by_type");
status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/*
* Table types supported are:
* DSDT (one), SSDT/PSDT (multiple)
*/
switch (table_type) {
case ACPI_TABLE_DSDT:
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading DSDT\n"));
table_desc = acpi_gbl_table_lists[ACPI_TABLE_DSDT].next;
/* If table already loaded into namespace, just return */
if (table_desc->loaded_into_namespace) {
goto unlock_and_exit;
}
/* Now load the single DSDT */
status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
if (ACPI_SUCCESS (status)) {
table_desc->loaded_into_namespace = TRUE;
}
break;
case ACPI_TABLE_SSDT:
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading %d SSDTs\n",
acpi_gbl_table_lists[ACPI_TABLE_SSDT].count));
/*
* Traverse list of SSDT tables
*/
table_desc = acpi_gbl_table_lists[ACPI_TABLE_SSDT].next;
for (i = 0; i < acpi_gbl_table_lists[ACPI_TABLE_SSDT].count; i++) {
/*
* Only attempt to load table if it is not
* already loaded!
*/
if (!table_desc->loaded_into_namespace) {
status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
if (ACPI_FAILURE (status)) {
break;
}
table_desc->loaded_into_namespace = TRUE;
}
table_desc = table_desc->next;
}
break;
case ACPI_TABLE_PSDT:
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading %d PSDTs\n",
acpi_gbl_table_lists[ACPI_TABLE_PSDT].count));
/*
* Traverse list of PSDT tables
*/
table_desc = acpi_gbl_table_lists[ACPI_TABLE_PSDT].next;
for (i = 0; i < acpi_gbl_table_lists[ACPI_TABLE_PSDT].count; i++) {
/* Only attempt to load table if it is not already loaded! */
if (!table_desc->loaded_into_namespace) {
status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
if (ACPI_FAILURE (status)) {
break;
}
table_desc->loaded_into_namespace = TRUE;
}
table_desc = table_desc->next;
}
break;
default:
status = AE_SUPPORT;
break;
}
unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_TABLES);
return_ACPI_STATUS (status);
}
/*******************************************************************************
*
* 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_DEBUG_PRINT ((ACPI_DB_ERROR, "DSDT is not in memory\n"));
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_DSDT);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* Ignore exceptions from these */
(void) acpi_ns_load_table_by_type (ACPI_TABLE_SSDT);
(void) acpi_ns_load_table_by_type (ACPI_TABLE_PSDT);
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
"ACPI Namespace successfully loaded at root %p\n",
acpi_gbl_root_node));
return_ACPI_STATUS (status);
}
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
* 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.
*
******************************************************************************/
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 /* ACPI_FUTURE_USAGE */
#endif

View File

@@ -0,0 +1,265 @@
/*******************************************************************************
*
* Module Name: nsnames - Name manipulation and search
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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_NAME ("ns_build_external_path");
/* 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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Could not construct pathname; index=%X, size=%X, Path=%s\n",
(u32) index, (u32) size, &name_buffer[size]));
}
return;
}
#ifdef ACPI_DEBUG_OUTPUT
/*******************************************************************************
*
* FUNCTION: acpi_ns_get_external_pathname
*
* PARAMETERS: Node - NS 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_MEM_CALLOCATE (size);
if (!name_buffer) {
ACPI_REPORT_ERROR (("ns_get_table_pathname: allocation failure\n"));
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);
}

View File

@@ -0,0 +1,461 @@
/*******************************************************************************
*
* Module Name: nsobject - Utilities for objects attached to namespace
* table entries
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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
*
* 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_REPORT_ERROR (("ns_attach_object: Null named_obj handle\n"));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
if (!object && (ACPI_TYPE_ANY != type)) {
/* Null object */
ACPI_REPORT_ERROR (("ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n"));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
/* Not a name handle */
ACPI_REPORT_ERROR (("ns_attach_object: Invalid handle %p [%s]\n",
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 name_obj %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 - An 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 - Parent Node to be examined
*
* 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_DEBUG_PRINT ((ACPI_DB_WARN, "Null Node ptr\n"));
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 - Parent Node to be examined
*
* 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);
}

View File

@@ -0,0 +1,171 @@
/******************************************************************************
*
* Module Name: nsparse - namespace interface to AML parser
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsparse")
/*******************************************************************************
*
* FUNCTION: ns_one_complete_parse
*
* PARAMETERS: pass_number - 1 or 2
* table_desc - The table to be parsed.
*
* RETURN: Status
*
* DESCRIPTION: Perform one complete parse of an ACPI/AML table.
*
******************************************************************************/
acpi_status
acpi_ns_one_complete_parse (
u32 pass_number,
struct acpi_table_desc *table_desc)
{
union acpi_parse_object *parse_root;
acpi_status status;
struct acpi_walk_state *walk_state;
ACPI_FUNCTION_TRACE ("ns_one_complete_parse");
/* 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 (table_desc->table_id,
NULL, NULL, NULL);
if (!walk_state) {
acpi_ps_free_op (parse_root);
return_ACPI_STATUS (AE_NO_MEMORY);
}
status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL,
table_desc->aml_start, table_desc->aml_length,
NULL, pass_number);
if (ACPI_FAILURE (status)) {
acpi_ds_delete_walk_state (walk_state);
return_ACPI_STATUS (status);
}
/* Parse the AML */
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "*PARSE* pass %d parse\n", 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 (
struct acpi_table_desc *table_desc,
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..
*/
status = acpi_ns_one_complete_parse (1, table_desc);
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.
*/
status = acpi_ns_one_complete_parse (2, table_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
return_ACPI_STATUS (status);
}

View File

@@ -0,0 +1,381 @@
/*******************************************************************************
*
* Module Name: nssearch - Namespace search
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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")
/*******************************************************************************
*
* FUNCTION: acpi_ns_search_node
*
* 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 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.
*
******************************************************************************/
acpi_status
acpi_ns_search_node (
u32 target_name,
struct acpi_namespace_node *node,
acpi_object_type type,
struct acpi_namespace_node **return_node)
{
struct acpi_namespace_node *next_node;
ACPI_FUNCTION_TRACE ("ns_search_node");
#ifdef ACPI_DEBUG_OUTPUT
if (ACPI_LV_NAMES & acpi_dbg_level) {
char *scope_name;
scope_name = acpi_ns_get_external_pathname (node);
if (scope_name) {
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
"Searching %s (%p) For [%4.4s] (%s)\n",
scope_name, node, (char *) &target_name,
acpi_ut_get_type_name (type)));
ACPI_MEM_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
*/
next_node = node->child;
while (next_node) {
/* Check for match against the name */
if (next_node->name.integer == target_name) {
/* Resolve a control method alias if any */
if (acpi_ns_get_type (next_node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
next_node = ACPI_CAST_PTR (struct acpi_namespace_node, next_node->object);
}
/*
* Found matching entry.
*/
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
"Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n",
(char *) &target_name, acpi_ut_get_type_name (next_node->type),
next_node, acpi_ut_get_node_name (node), node));
*return_node = next_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 (next_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 */
next_node = next_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",
(char *) &target_name, acpi_ut_get_type_name (type),
acpi_ut_get_node_name (node), node, 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",
(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",
(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), (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_node (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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Null param: Node %p Name %X return_node %p\n",
node, target_name, return_node));
ACPI_REPORT_ERROR (("ns_search_and_enter: Null parameter\n"));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
/* Name must consist of printable characters */
if (!acpi_ut_valid_acpi_name (target_name)) {
ACPI_REPORT_ERROR (("ns_search_and_enter: Bad character in ACPI Name: %X\n",
target_name));
return_ACPI_STATUS (AE_BAD_CHARACTER);
}
/* Try to find the name in the namespace level specified by the caller */
*return_node = ACPI_ENTRY_NOT_FOUND;
status = acpi_ns_search_node (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",
(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);
}
/* 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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,289 @@
/******************************************************************************
*
* Module Name: nswalk - Functions for walking the ACPI namespace
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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
* unlock_before_callback- 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,
u8 unlock_before_callback,
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 node, Get the type if we are not
* searching for ANY
*/
if (type != ACPI_TYPE_ANY) {
child_type = child_node->type;
}
if (child_type == type) {
/*
* Found a matching node, invoke the user
* callback function
*/
if (unlock_before_callback) {
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 (unlock_before_callback) {
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 the onde
*/
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);
}

View File

@@ -0,0 +1,764 @@
/*******************************************************************************
*
* Module Name: nsxfeval - Public interfaces to the ACPI subsystem
* ACPI Object evaluation interfaces
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acinterp.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsxfeval")
/*******************************************************************************
*
* 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)
*
******************************************************************************/
#ifdef ACPI_FUTURE_USAGE
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"No return value\n"));
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_DEBUG_PRINT ((ACPI_DB_ERROR,
"Incorrect return type [%s] requested [%s]\n",
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_os_free (return_buffer->pointer);
return_buffer->pointer = NULL;
}
return_buffer->length = 0;
return_ACPI_STATUS (AE_TYPE);
}
#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_parameter_info info;
acpi_size buffer_space_needed;
u32 i;
ACPI_FUNCTION_TRACE ("acpi_evaluate_object");
info.node = handle;
info.parameters = NULL;
info.return_object = NULL;
info.parameter_type = ACPI_PARAM_ARGS;
/*
* If there are parameters to be passed to the object
* (which must be a control method), the external objects
* must 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_MEM_CALLOCATE (
((acpi_size) external_params->count + 1) *
sizeof (void *));
if (!info.parameters) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
/*
* 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)) {
acpi_ut_delete_internal_object_list (info.parameters);
return_ACPI_STATUS (status);
}
}
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
*/
status = acpi_ns_evaluate_by_name (pathname, &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_ERROR,
"Both Handle and Pathname are NULL\n"));
}
else {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Handle is NULL and Pathname is relative\n"));
}
status = AE_BAD_PARAMETER;
}
else {
/*
* We get here if we have a handle -- and if we have a
* pathname it is relative. The handle will be validated
* in the lower procedures
*/
if (!pathname) {
/*
* The null pathname case means the handle is for
* the actual object to be evaluated
*/
status = acpi_ns_evaluate_by_handle (&info);
}
else {
/*
* Both a Handle and a relative Pathname
*/
status = acpi_ns_evaluate_relative (pathname, &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)) {
/*
* Find out how large a buffer is needed
* to contain 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)) {
/*
* Delete the internal return object. (Or at least
* decrement the reference count by one)
*/
acpi_ut_remove_reference (info.return_object);
acpi_ex_exit_interpreter ();
}
}
/*
* 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);
}
return_ACPI_STATUS (status);
}
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_EXTERNAL_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);
}
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 & 0x01)) {
/* Don't return at the device or children of the device if not there */
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_MEM_FREE (cid);
return (AE_OK);
}
}
ACPI_MEM_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.context = context;
info.user_function = user_function;
info.hid = HID;
/*
* 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);
}
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);
}
/*******************************************************************************
*
* 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);
}
/*******************************************************************************
*
* 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);
}

View File

@@ -0,0 +1,369 @@
/******************************************************************************
*
* Module Name: nsxfname - Public interfaces to the ACPI subsystem
* ACPI Namespace oriented interfaces
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsxfname")
/******************************************************************************
*
* FUNCTION: acpi_get_handle
*
* PARAMETERS: Parent - Object to search under (search scope).
* path_name - Pointer to an asciiz string containing the
* name
* ret_handle - Where the return handle is placed
*
* RETURN: Status
*
* DESCRIPTION: This routine will search for a caller specified name in the
* name space. The caller can restrict the search region by
* specifying a non NULL parent. The parent value is itself a
* namespace handle.
*
******************************************************************************/
acpi_status
acpi_get_handle (
acpi_handle parent,
acpi_string pathname,
acpi_handle *ret_handle)
{
acpi_status status;
struct acpi_namespace_node *node = NULL;
struct acpi_namespace_node *prefix_node = NULL;
ACPI_FUNCTION_ENTRY ();
/* Parameter Validation */
if (!ret_handle || !pathname) {
return (AE_BAD_PARAMETER);
}
/* Convert a parent handle to a prefix node */
if (parent) {
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return (status);
}
prefix_node = acpi_ns_map_handle_to_node (parent);
if (!prefix_node) {
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (AE_BAD_PARAMETER);
}
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return (status);
}
}
/* Special case for root, since we can't search for it */
if (ACPI_STRCMP (pathname, ACPI_NS_ROOT_PATH) == 0) {
*ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_node);
return (AE_OK);
}
/*
* Find the Node and convert to a handle
*/
status = acpi_ns_get_node_by_path (pathname, prefix_node, ACPI_NS_NO_UPSEARCH,
&node);
*ret_handle = NULL;
if (ACPI_SUCCESS (status)) {
*ret_handle = acpi_ns_convert_entry_to_handle (node);
}
return (status);
}
EXPORT_SYMBOL(acpi_get_handle);
/******************************************************************************
*
* FUNCTION: acpi_get_name
*
* PARAMETERS: Handle - Handle to be converted to a pathname
* name_type - Full pathname or single segment
* Buffer - Buffer for returned path
*
* RETURN: Pointer to a string containing the fully qualified Name.
*
* DESCRIPTION: This routine returns the fully qualified name associated with
* the Handle parameter. This and the acpi_pathname_to_handle are
* complementary functions.
*
******************************************************************************/
acpi_status
acpi_get_name (
acpi_handle handle,
u32 name_type,
struct acpi_buffer *buffer)
{
acpi_status status;
struct acpi_namespace_node *node;
/* Parameter validation */
if (name_type > ACPI_NAME_TYPE_MAX) {
return (AE_BAD_PARAMETER);
}
status = acpi_ut_validate_buffer (buffer);
if (ACPI_FAILURE (status)) {
return (status);
}
if (name_type == ACPI_FULL_PATHNAME) {
/* Get the full pathname (From the namespace root) */
status = acpi_ns_handle_to_pathname (handle, buffer);
return (status);
}
/*
* Wants the single segment ACPI name.
* Validate handle and convert to a namespace Node
*/
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return (status);
}
node = acpi_ns_map_handle_to_node (handle);
if (!node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/* Validate/Allocate/Clear caller buffer */
status = acpi_ut_initialize_buffer (buffer, ACPI_PATH_SEGMENT_LENGTH);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
/* Just copy the ACPI name from the Node and zero terminate it */
ACPI_STRNCPY (buffer->pointer, acpi_ut_get_node_name (node),
ACPI_NAME_SIZE);
((char *) buffer->pointer) [ACPI_NAME_SIZE] = 0;
status = AE_OK;
unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (status);
}
EXPORT_SYMBOL(acpi_get_name);
/******************************************************************************
*
* FUNCTION: acpi_get_object_info
*
* PARAMETERS: Handle - Object Handle
* Info - Where the info is returned
*
* RETURN: Status
*
* DESCRIPTION: Returns information about an object as gleaned from the
* namespace node and possibly by running several standard
* control methods (Such as in the case of a device.)
*
******************************************************************************/
acpi_status
acpi_get_object_info (
acpi_handle handle,
struct acpi_buffer *buffer)
{
acpi_status status;
struct acpi_namespace_node *node;
struct acpi_device_info *info;
struct acpi_device_info *return_info;
struct acpi_compatible_id_list *cid_list = NULL;
acpi_size size;
/* Parameter validation */
if (!handle || !buffer) {
return (AE_BAD_PARAMETER);
}
status = acpi_ut_validate_buffer (buffer);
if (ACPI_FAILURE (status)) {
return (status);
}
info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_device_info));
if (!info) {
return (AE_NO_MEMORY);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
node = acpi_ns_map_handle_to_node (handle);
if (!node) {
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
goto cleanup;
}
/* Init return structure */
size = sizeof (struct acpi_device_info);
info->type = node->type;
info->name = node->name.integer;
info->valid = 0;
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
/* If not a device, we are all done */
if (info->type == ACPI_TYPE_DEVICE) {
/*
* Get extra info for ACPI Devices objects only:
* Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods.
*
* Note: none of these methods are required, so they may or may
* not be present for this device. The Info->Valid bitfield is used
* to indicate which methods were found and ran successfully.
*/
/* Execute the Device._HID method */
status = acpi_ut_execute_HID (node, &info->hardware_id);
if (ACPI_SUCCESS (status)) {
info->valid |= ACPI_VALID_HID;
}
/* Execute the Device._UID method */
status = acpi_ut_execute_UID (node, &info->unique_id);
if (ACPI_SUCCESS (status)) {
info->valid |= ACPI_VALID_UID;
}
/* Execute the Device._CID method */
status = acpi_ut_execute_CID (node, &cid_list);
if (ACPI_SUCCESS (status)) {
size += ((acpi_size) cid_list->count - 1) *
sizeof (struct acpi_compatible_id);
info->valid |= ACPI_VALID_CID;
}
/* Execute the Device._STA method */
status = acpi_ut_execute_STA (node, &info->current_status);
if (ACPI_SUCCESS (status)) {
info->valid |= ACPI_VALID_STA;
}
/* Execute the Device._ADR method */
status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node,
&info->address);
if (ACPI_SUCCESS (status)) {
info->valid |= ACPI_VALID_ADR;
}
/* Execute the Device._sx_d methods */
status = acpi_ut_execute_sxds (node, info->highest_dstates);
if (ACPI_SUCCESS (status)) {
info->valid |= ACPI_VALID_SXDS;
}
}
/* Validate/Allocate/Clear caller buffer */
status = acpi_ut_initialize_buffer (buffer, size);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
/* Populate the return buffer */
return_info = buffer->pointer;
ACPI_MEMCPY (return_info, info, sizeof (struct acpi_device_info));
if (cid_list) {
ACPI_MEMCPY (&return_info->compatibility_id, cid_list, cid_list->size);
}
cleanup:
ACPI_MEM_FREE (info);
if (cid_list) {
ACPI_MEM_FREE (cid_list);
}
return (status);
}
EXPORT_SYMBOL(acpi_get_object_info);

View File

@@ -0,0 +1,262 @@
/*******************************************************************************
*
* Module Name: nsxfobj - Public interfaces to the ACPI subsystem
* ACPI Object oriented interfaces
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2005, 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 <linux/module.h>
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsxfobj")
/*******************************************************************************
*
* FUNCTION: acpi_get_type
*
* PARAMETERS: Handle - Handle of object whose type is desired
* *ret_type - Where the type will be placed
*
* RETURN: Status
*
* DESCRIPTION: This routine returns the type associatd with a particular handle
*
******************************************************************************/
acpi_status
acpi_get_type (
acpi_handle handle,
acpi_object_type *ret_type)
{
struct acpi_namespace_node *node;
acpi_status status;
/* Parameter Validation */
if (!ret_type) {
return (AE_BAD_PARAMETER);
}
/*
* Special case for the predefined Root Node
* (return type ANY)
*/
if (handle == ACPI_ROOT_OBJECT) {
*ret_type = ACPI_TYPE_ANY;
return (AE_OK);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return (status);
}
/* Convert and validate the handle */
node = acpi_ns_map_handle_to_node (handle);
if (!node) {
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (AE_BAD_PARAMETER);
}
*ret_type = node->type;
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (status);
}
EXPORT_SYMBOL(acpi_get_type);
/*******************************************************************************
*
* FUNCTION: acpi_get_parent
*
* PARAMETERS: Handle - Handle of object whose parent is desired
* ret_handle - Where the parent handle will be placed
*
* RETURN: Status
*
* DESCRIPTION: Returns a handle to the parent of the object represented by
* Handle.
*
******************************************************************************/
acpi_status
acpi_get_parent (
acpi_handle handle,
acpi_handle *ret_handle)
{
struct acpi_namespace_node *node;
acpi_status status;
if (!ret_handle) {
return (AE_BAD_PARAMETER);
}
/* Special case for the predefined Root Node (no parent) */
if (handle == ACPI_ROOT_OBJECT) {
return (AE_NULL_ENTRY);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return (status);
}
/* Convert and validate the handle */
node = acpi_ns_map_handle_to_node (handle);
if (!node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/* Get the parent entry */
*ret_handle =
acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_node (node));
/* Return exception if parent is null */
if (!acpi_ns_get_parent_node (node)) {
status = AE_NULL_ENTRY;
}
unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (status);
}
EXPORT_SYMBOL(acpi_get_parent);
/*******************************************************************************
*
* FUNCTION: acpi_get_next_object
*
* PARAMETERS: Type - Type of object to be searched for
* Parent - Parent object whose children we are getting
* last_child - Previous child that was found.
* The NEXT child will be returned
* ret_handle - Where handle to the next object is placed
*
* RETURN: Status
*
* DESCRIPTION: Return the next peer object within the namespace. If Handle is
* valid, Scope is ignored. Otherwise, the first object within
* Scope is returned.
*
******************************************************************************/
acpi_status
acpi_get_next_object (
acpi_object_type type,
acpi_handle parent,
acpi_handle child,
acpi_handle *ret_handle)
{
acpi_status status;
struct acpi_namespace_node *node;
struct acpi_namespace_node *parent_node = NULL;
struct acpi_namespace_node *child_node = NULL;
/* Parameter validation */
if (type > ACPI_TYPE_EXTERNAL_MAX) {
return (AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return (status);
}
/* If null handle, use the parent */
if (!child) {
/* Start search at the beginning of the specified scope */
parent_node = acpi_ns_map_handle_to_node (parent);
if (!parent_node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
}
else {
/* Non-null handle, ignore the parent */
/* Convert and validate the handle */
child_node = acpi_ns_map_handle_to_node (child);
if (!child_node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
}
/* Internal function does the real work */
node = acpi_ns_get_next_node (type, parent_node, child_node);
if (!node) {
status = AE_NOT_FOUND;
goto unlock_and_exit;
}
if (ret_handle) {
*ret_handle = acpi_ns_convert_entry_to_handle (node);
}
unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (status);
}
EXPORT_SYMBOL(acpi_get_next_object);

Some files were not shown because too many files have changed in this diff Show More