Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
ed3269a3
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
ed3269a3
编写于
10月 14, 2006
作者:
L
Len Brown
浏览文件
操作
浏览文件
下载
差异文件
Pull ec into test branch
上级
d7321ad2
ab9e43c6
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
296 addition
and
803 deletion
+296
-803
drivers/acpi/ec.c
drivers/acpi/ec.c
+293
-803
include/linux/acpi.h
include/linux/acpi.h
+3
-0
未找到文件。
drivers/acpi/ec.c
浏览文件 @
ed3269a3
...
...
@@ -45,206 +45,143 @@ ACPI_MODULE_NAME("acpi_ec")
#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01
/* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02
/* Input buffer full */
#define ACPI_EC_FLAG_BURST 0x10
/* burst mode */
#define ACPI_EC_FLAG_SCI 0x20
/* EC-SCI occurred */
#define ACPI_EC_EVENT_OBF 0x01
/* Output buffer full */
#define ACPI_EC_EVENT_IBE 0x02
/* Input buffer empty */
#define ACPI_EC_DELAY 50
/* Wait 50ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000
/* Wait 1ms max. to get global lock */
#define ACPI_EC_UDELAY 100
/* Poll @ 100us increments */
#define ACPI_EC_UDELAY_COUNT 1000
/* Wait 10ms max. during EC ops */
/* EC commands */
#define ACPI_EC_COMMAND_READ 0x80
#define ACPI_EC_COMMAND_WRITE 0x81
#define ACPI_EC_BURST_ENABLE 0x82
#define ACPI_EC_BURST_DISABLE 0x83
#define ACPI_EC_COMMAND_QUERY 0x84
#define EC_POLL 0xFF
#define EC_INTR 0x00
/* EC events */
enum
{
ACPI_EC_EVENT_OBF_1
=
1
,
/* Output buffer full */
ACPI_EC_EVENT_IBF_0
,
/* Input buffer empty */
};
#define ACPI_EC_DELAY 50
/* Wait 50ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000
/* Wait 1ms max. to get global lock */
#define ACPI_EC_UDELAY 100
/* Poll @ 100us increments */
#define ACPI_EC_UDELAY_COUNT 1000
/* Wait 10ms max. during EC ops */
enum
{
EC_INTR
=
1
,
/* Output buffer full */
EC_POLL
,
/* Input buffer empty */
};
static
int
acpi_ec_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_ec_start
(
struct
acpi_device
*
device
);
static
int
acpi_ec_stop
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_ec_intr_add
(
struct
acpi_device
*
device
);
static
int
acpi_ec_poll_add
(
struct
acpi_device
*
device
);
static
int
acpi_ec_add
(
struct
acpi_device
*
device
);
static
struct
acpi_driver
acpi_ec_driver
=
{
.
name
=
ACPI_EC_DRIVER_NAME
,
.
class
=
ACPI_EC_CLASS
,
.
ids
=
ACPI_EC_HID
,
.
ops
=
{
.
add
=
acpi_ec_
intr_
add
,
.
add
=
acpi_ec_add
,
.
remove
=
acpi_ec_remove
,
.
start
=
acpi_ec_start
,
.
stop
=
acpi_ec_stop
,
},
};
union
acpi_ec
{
struct
{
u32
mode
;
acpi_handle
handle
;
unsigned
long
uid
;
unsigned
long
gpe_bit
;
struct
acpi_generic_address
status_addr
;
struct
acpi_generic_address
command_addr
;
struct
acpi_generic_address
data_addr
;
unsigned
long
global_lock
;
}
common
;
struct
{
u32
mode
;
acpi_handle
handle
;
unsigned
long
uid
;
unsigned
long
gpe_bit
;
struct
acpi_generic_address
status_addr
;
struct
acpi_generic_address
command_addr
;
struct
acpi_generic_address
data_addr
;
unsigned
long
global_lock
;
unsigned
int
expect_event
;
atomic_t
leaving_burst
;
/* 0 : No, 1 : Yes, 2: abort */
atomic_t
pending_gpe
;
struct
semaphore
sem
;
wait_queue_head_t
wait
;
}
intr
;
struct
{
u32
mode
;
acpi_handle
handle
;
unsigned
long
uid
;
unsigned
long
gpe_bit
;
struct
acpi_generic_address
status_addr
;
struct
acpi_generic_address
command_addr
;
struct
acpi_generic_address
data_addr
;
unsigned
long
global_lock
;
struct
semaphore
sem
;
}
poll
;
};
static
int
acpi_ec_poll_wait
(
union
acpi_ec
*
ec
,
u8
event
);
static
int
acpi_ec_intr_wait
(
union
acpi_ec
*
ec
,
unsigned
int
event
);
static
int
acpi_ec_poll_read
(
union
acpi_ec
*
ec
,
u8
address
,
u32
*
data
);
static
int
acpi_ec_intr_read
(
union
acpi_ec
*
ec
,
u8
address
,
u32
*
data
);
static
int
acpi_ec_poll_write
(
union
acpi_ec
*
ec
,
u8
address
,
u8
data
);
static
int
acpi_ec_intr_write
(
union
acpi_ec
*
ec
,
u8
address
,
u8
data
);
static
int
acpi_ec_poll_query
(
union
acpi_ec
*
ec
,
u32
*
data
);
static
int
acpi_ec_intr_query
(
union
acpi_ec
*
ec
,
u32
*
data
);
static
void
acpi_ec_gpe_poll_query
(
void
*
ec_cxt
);
static
void
acpi_ec_gpe_intr_query
(
void
*
ec_cxt
);
static
u32
acpi_ec_gpe_poll_handler
(
void
*
data
);
static
u32
acpi_ec_gpe_intr_handler
(
void
*
data
);
static
acpi_status
__init
acpi_fake_ecdt_poll_callback
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
);
static
acpi_status
__init
acpi_fake_ecdt_intr_callback
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
);
static
int
__init
acpi_ec_poll_get_real_ecdt
(
void
);
static
int
__init
acpi_ec_intr_get_real_ecdt
(
void
);
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
static
union
acpi_ec
*
ec_ecdt
;
struct
acpi_ec
{
acpi_handle
handle
;
unsigned
long
uid
;
unsigned
long
gpe_bit
;
unsigned
long
command_addr
;
unsigned
long
data_addr
;
unsigned
long
global_lock
;
struct
semaphore
sem
;
unsigned
int
expect_event
;
atomic_t
leaving_burst
;
/* 0 : No, 1 : Yes, 2: abort */
wait_queue_head_t
wait
;
}
*
ec_ecdt
;
/* External interfaces use first EC only, so remember */
static
struct
acpi_device
*
first_ec
;
static
int
acpi_ec_
poll_
mode
=
EC_INTR
;
static
int
acpi_ec_mode
=
EC_INTR
;
/* --------------------------------------------------------------------------
Transaction Management
-------------------------------------------------------------------------- */
static
u32
acpi_ec_read_status
(
union
acpi_ec
*
ec
)
static
inline
u8
acpi_ec_read_status
(
struct
acpi_ec
*
ec
)
{
u32
status
=
0
;
acpi_hw_low_level_read
(
8
,
&
status
,
&
ec
->
common
.
status_addr
);
return
status
;
return
inb
(
ec
->
command_addr
);
}
static
in
t
acpi_ec_wait
(
union
acpi_ec
*
ec
,
u8
event
)
static
in
line
u8
acpi_ec_read_data
(
struct
acpi_ec
*
ec
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_ec_poll_wait
(
ec
,
event
);
else
return
acpi_ec_intr_wait
(
ec
,
event
);
return
inb
(
ec
->
data_addr
);
}
static
in
t
acpi_ec_poll_wait
(
union
acpi_ec
*
ec
,
u8
event
)
static
in
line
void
acpi_ec_write_cmd
(
struct
acpi_ec
*
ec
,
u8
command
)
{
u32
acpi_ec_status
=
0
;
u32
i
=
ACPI_EC_UDELAY_COUNT
;
outb
(
command
,
ec
->
command_addr
)
;
}
if
(
!
ec
)
return
-
EINVAL
;
static
inline
void
acpi_ec_write_data
(
struct
acpi_ec
*
ec
,
u8
data
)
{
outb
(
data
,
ec
->
data_addr
);
}
/* Poll the EC status register waiting for the event to occur. */
static
int
acpi_ec_check_status
(
u8
status
,
u8
event
)
{
switch
(
event
)
{
case
ACPI_EC_EVENT_OBF
:
do
{
acpi_hw_low_level_read
(
8
,
&
acpi_ec_status
,
&
ec
->
common
.
status_addr
);
if
(
acpi_ec_status
&
ACPI_EC_FLAG_OBF
)
return
0
;
udelay
(
ACPI_EC_UDELAY
);
}
while
(
--
i
>
0
);
case
ACPI_EC_EVENT_OBF_1
:
if
(
status
&
ACPI_EC_FLAG_OBF
)
return
1
;
break
;
case
ACPI_EC_EVENT_IBE
:
do
{
acpi_hw_low_level_read
(
8
,
&
acpi_ec_status
,
&
ec
->
common
.
status_addr
);
if
(
!
(
acpi_ec_status
&
ACPI_EC_FLAG_IBF
))
return
0
;
udelay
(
ACPI_EC_UDELAY
);
}
while
(
--
i
>
0
);
case
ACPI_EC_EVENT_IBF_0
:
if
(
!
(
status
&
ACPI_EC_FLAG_IBF
))
return
1
;
break
;
default:
return
-
EINVAL
;
break
;
}
return
-
ETIME
;
return
0
;
}
static
int
acpi_ec_intr_wait
(
union
acpi_ec
*
ec
,
unsigned
int
event
)
{
int
result
=
0
;
ec
->
intr
.
expect_event
=
event
;
smp_mb
();
static
int
acpi_ec_wait
(
struct
acpi_ec
*
ec
,
u8
event
)
{
int
i
=
(
acpi_ec_mode
==
EC_POLL
)
?
ACPI_EC_UDELAY_COUNT
:
0
;
long
time_left
;
switch
(
event
)
{
case
ACPI_EC_EVENT_IBE
:
if
(
~
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_IBF
)
{
ec
->
intr
.
expect_event
=
0
;
return
0
;
}
break
;
default:
break
;
ec
->
expect_event
=
event
;
if
(
acpi_ec_check_status
(
acpi_ec_read_status
(
ec
),
event
))
{
ec
->
expect_event
=
0
;
return
0
;
}
result
=
wait_event_timeout
(
ec
->
intr
.
wait
,
!
ec
->
intr
.
expect_event
,
do
{
if
(
acpi_ec_mode
==
EC_POLL
)
{
udelay
(
ACPI_EC_UDELAY
);
}
else
{
time_left
=
wait_event_timeout
(
ec
->
wait
,
!
ec
->
expect_event
,
msecs_to_jiffies
(
ACPI_EC_DELAY
));
ec
->
intr
.
expect_event
=
0
;
smp_mb
();
/*
* Verify that the event in question has actually happened by
* querying EC status. Do the check even if operation timed-out
* to make sure that we did not miss interrupt.
*/
switch
(
event
)
{
case
ACPI_EC_EVENT_OBF
:
if
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_OBF
)
if
(
time_left
>
0
)
{
ec
->
expect_event
=
0
;
return
0
;
}
}
if
(
acpi_ec_check_status
(
acpi_ec_read_status
(
ec
),
event
))
{
ec
->
expect_event
=
0
;
return
0
;
break
;
}
}
while
(
--
i
>
0
);
case
ACPI_EC_EVENT_IBE
:
if
(
~
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_IBF
)
return
0
;
break
;
}
ec
->
expect_event
=
0
;
return
-
ETIME
;
}
...
...
@@ -254,272 +191,150 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
* Note: samsung nv5000 doesn't work with ec burst mode.
* http://bugzilla.kernel.org/show_bug.cgi?id=4980
*/
int
acpi_ec_enter_burst_mode
(
union
acpi_ec
*
ec
)
int
acpi_ec_enter_burst_mode
(
struct
acpi_ec
*
ec
)
{
u
32
tmp
=
0
;
int
status
=
0
;
u
8
tmp
=
0
;
u8
status
=
0
;
status
=
acpi_ec_read_status
(
ec
);
if
(
status
!=
-
EINVAL
&&
!
(
status
&
ACPI_EC_FLAG_BURST
))
{
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IB
E
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IB
F_0
);
if
(
status
)
goto
end
;
acpi_hw_low_level_write
(
8
,
ACPI_EC_BURST_ENABLE
,
&
ec
->
common
.
command_addr
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF
);
acpi_hw_low_level_read
(
8
,
&
tmp
,
&
ec
->
common
.
data_addr
);
acpi_ec_write_cmd
(
ec
,
ACPI_EC_BURST_ENABLE
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF_1
);
tmp
=
acpi_ec_read_data
(
ec
);
if
(
tmp
!=
0x90
)
{
/* Burst ACK byte */
return
-
EINVAL
;
}
}
atomic_set
(
&
ec
->
intr
.
leaving_burst
,
0
);
atomic_set
(
&
ec
->
leaving_burst
,
0
);
return
0
;
end:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"EC wait, burst mode"
);
end:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"EC wait, burst mode"
)
);
return
-
1
;
}
int
acpi_ec_leave_burst_mode
(
union
acpi_ec
*
ec
)
int
acpi_ec_leave_burst_mode
(
struct
acpi_ec
*
ec
)
{
int
status
=
0
;
u8
status
=
0
;
status
=
acpi_ec_read_status
(
ec
);
if
(
status
!=
-
EINVAL
&&
(
status
&
ACPI_EC_FLAG_BURST
)){
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_
FLAG_IBF
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_
EVENT_IBF_0
);
if
(
status
)
goto
end
;
acpi_
hw_low_level_write
(
8
,
ACPI_EC_BURST_DISABLE
,
&
ec
->
common
.
command_addr
);
acpi_ec_wait
(
ec
,
ACPI_EC_
FLAG_IBF
);
}
atomic_set
(
&
ec
->
intr
.
leaving_burst
,
1
);
acpi_
ec_write_cmd
(
ec
,
ACPI_EC_BURST_DISABLE
);
acpi_ec_wait
(
ec
,
ACPI_EC_
EVENT_IBF_0
);
}
atomic_set
(
&
ec
->
leaving_burst
,
1
);
return
0
;
end:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"EC leave burst mode"
);
end:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"EC leave burst mode"
)
)
;
return
-
1
;
}
#endif
/* ACPI_FUTURE_USAGE */
static
int
acpi_ec_read
(
union
acpi_ec
*
ec
,
u8
address
,
u32
*
data
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_ec_poll_read
(
ec
,
address
,
data
);
else
return
acpi_ec_intr_read
(
ec
,
address
,
data
);
}
static
int
acpi_ec_write
(
union
acpi_ec
*
ec
,
u8
address
,
u8
data
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_ec_poll_write
(
ec
,
address
,
data
);
else
return
acpi_ec_intr_write
(
ec
,
address
,
data
);
}
static
int
acpi_ec_poll_read
(
union
acpi_ec
*
ec
,
u8
address
,
u32
*
data
)
static
int
acpi_ec_transaction_unlocked
(
struct
acpi_ec
*
ec
,
u8
command
,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
)
{
acpi_status
status
=
AE_OK
;
int
result
=
0
;
u32
glk
=
0
;
int
result
;
acpi_ec_write_cmd
(
ec
,
command
);
if
(
!
ec
||
!
data
)
return
-
EINVAL
;
*
data
=
0
;
if
(
ec
->
common
.
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
for
(;
wdata_len
>
0
;
wdata_len
--
)
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
);
if
(
result
)
return
result
;
acpi_ec_write_data
(
ec
,
*
(
wdata
++
));
}
if
(
down_interruptible
(
&
ec
->
poll
.
sem
))
{
result
=
-
ERESTARTSYS
;
goto
end_nosem
;
if
(
command
==
ACPI_EC_COMMAND_WRITE
)
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
);
if
(
result
)
return
result
;
}
acpi_hw_low_level_write
(
8
,
ACPI_EC_COMMAND_READ
,
&
ec
->
common
.
command_addr
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
result
)
goto
end
;
acpi_hw_low_level_write
(
8
,
address
,
&
ec
->
common
.
data_addr
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF
);
if
(
result
)
goto
end
;
acpi_hw_low_level_read
(
8
,
data
,
&
ec
->
common
.
data_addr
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Read [%02x] from address [%02x]
\n
"
,
*
data
,
address
));
end:
up
(
&
ec
->
poll
.
sem
);
end_nosem:
if
(
ec
->
common
.
global_lock
)
acpi_release_global_lock
(
glk
);
return
result
;
}
static
int
acpi_ec_poll_write
(
union
acpi_ec
*
ec
,
u8
address
,
u8
data
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
u32
glk
=
0
;
for
(;
rdata_len
>
0
;
rdata_len
--
)
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF_1
);
if
(
result
)
return
result
;
if
(
!
ec
)
return
-
EINVAL
;
if
(
ec
->
common
.
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
}
if
(
down_interruptible
(
&
ec
->
poll
.
sem
))
{
result
=
-
ERESTARTSYS
;
goto
end_nosem
;
*
(
rdata
++
)
=
acpi_ec_read_data
(
ec
);
}
acpi_hw_low_level_write
(
8
,
ACPI_EC_COMMAND_WRITE
,
&
ec
->
common
.
command_addr
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
result
)
goto
end
;
acpi_hw_low_level_write
(
8
,
address
,
&
ec
->
common
.
data_addr
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
result
)
goto
end
;
acpi_hw_low_level_write
(
8
,
data
,
&
ec
->
common
.
data_addr
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
result
)
goto
end
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Wrote [%02x] to address [%02x]
\n
"
,
data
,
address
));
end:
up
(
&
ec
->
poll
.
sem
);
end_nosem:
if
(
ec
->
common
.
global_lock
)
acpi_release_global_lock
(
glk
);
return
result
;
return
0
;
}
static
int
acpi_ec_intr_read
(
union
acpi_ec
*
ec
,
u8
address
,
u32
*
data
)
static
int
acpi_ec_transaction
(
struct
acpi_ec
*
ec
,
u8
command
,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
)
{
int
status
=
0
;
int
status
;
u32
glk
;
if
(
!
ec
||
!
data
)
if
(
!
ec
||
(
wdata_len
&&
!
wdata
)
||
(
rdata_len
&&
!
rdata
))
return
-
EINVAL
;
*
data
=
0
;
if
(
rdata
)
memset
(
rdata
,
0
,
rdata_len
);
if
(
ec
->
common
.
global_lock
)
{
if
(
ec
->
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
}
down
(
&
ec
->
sem
);
WARN_ON
(
in_interrupt
());
down
(
&
ec
->
intr
.
sem
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"read EC, IB not empty
\n
"
);
goto
end
;
}
acpi_hw_low_level_write
(
8
,
ACPI_EC_COMMAND_READ
,
&
ec
->
common
.
command_addr
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"read EC, IB not empty
\n
"
);
}
acpi_hw_low_level_write
(
8
,
address
,
&
ec
->
common
.
data_addr
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"read EC, OB not full
\n
"
);
goto
end
;
}
acpi_hw_low_level_read
(
8
,
data
,
&
ec
->
common
.
data_addr
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Read [%02x] from address [%02x]
\n
"
,
*
data
,
address
));
status
=
acpi_ec_transaction_unlocked
(
ec
,
command
,
wdata
,
wdata_len
,
rdata
,
rdata_len
);
end:
up
(
&
ec
->
intr
.
sem
);
end:
up
(
&
ec
->
sem
);
if
(
ec
->
common
.
global_lock
)
if
(
ec
->
global_lock
)
acpi_release_global_lock
(
glk
);
return
status
;
}
static
int
acpi_ec_
intr_write
(
union
acpi_ec
*
ec
,
u8
address
,
u8
data
)
static
int
acpi_ec_
read
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
*
data
)
{
int
status
=
0
;
u32
glk
;
if
(
!
ec
)
return
-
EINVAL
;
if
(
ec
->
common
.
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
}
WARN_ON
(
in_interrupt
());
down
(
&
ec
->
intr
.
sem
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"write EC, IB not empty
\n
"
);
}
acpi_hw_low_level_write
(
8
,
ACPI_EC_COMMAND_WRITE
,
&
ec
->
common
.
command_addr
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"write EC, IB not empty
\n
"
);
}
acpi_hw_low_level_write
(
8
,
address
,
&
ec
->
common
.
data_addr
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"write EC, IB not empty
\n
"
);
}
acpi_hw_low_level_write
(
8
,
data
,
&
ec
->
common
.
data_addr
);
int
result
;
u8
d
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Wrote [%02x] to address [%02x]
\n
"
,
data
,
address
));
up
(
&
ec
->
intr
.
sem
);
if
(
ec
->
common
.
global_lock
)
acpi_release_global_lock
(
glk
);
result
=
acpi_ec_transaction
(
ec
,
ACPI_EC_COMMAND_READ
,
&
address
,
1
,
&
d
,
1
);
*
data
=
d
;
return
result
;
}
return
status
;
static
int
acpi_ec_write
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
data
)
{
u8
wdata
[
2
]
=
{
address
,
data
};
return
acpi_ec_transaction
(
ec
,
ACPI_EC_COMMAND_WRITE
,
wdata
,
2
,
NULL
,
0
);
}
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
int
ec_read
(
u8
addr
,
u8
*
val
)
int
ec_read
(
u8
addr
,
u8
*
val
)
{
union
acpi_ec
*
ec
;
struct
acpi_ec
*
ec
;
int
err
;
u
32
temp_data
;
u
8
temp_data
;
if
(
!
first_ec
)
return
-
ENODEV
;
...
...
@@ -539,7 +354,7 @@ EXPORT_SYMBOL(ec_read);
int
ec_write
(
u8
addr
,
u8
val
)
{
union
acpi_ec
*
ec
;
struct
acpi_ec
*
ec
;
int
err
;
if
(
!
first_ec
)
...
...
@@ -554,255 +369,106 @@ int ec_write(u8 addr, u8 val)
EXPORT_SYMBOL
(
ec_write
);
static
int
acpi_ec_query
(
union
acpi_ec
*
ec
,
u32
*
data
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_ec_poll_query
(
ec
,
data
);
else
return
acpi_ec_intr_query
(
ec
,
data
);
}
static
int
acpi_ec_poll_query
(
union
acpi_ec
*
ec
,
u32
*
data
)
extern
int
ec_transaction
(
u8
command
,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
u32
glk
=
0
;
if
(
!
ec
||
!
data
)
return
-
EINVAL
;
*
data
=
0
;
if
(
ec
->
common
.
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
}
struct
acpi_ec
*
ec
;
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
if
(
down_interruptible
(
&
ec
->
poll
.
sem
))
{
result
=
-
ERESTARTSYS
;
goto
end_nosem
;
}
acpi_hw_low_level_write
(
8
,
ACPI_EC_COMMAND_QUERY
,
&
ec
->
common
.
command_addr
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF
);
if
(
result
)
goto
end
;
acpi_hw_low_level_read
(
8
,
data
,
&
ec
->
common
.
data_addr
);
if
(
!*
data
)
result
=
-
ENODATA
;
if
(
!
first_ec
)
return
-
ENODEV
;
end:
up
(
&
ec
->
poll
.
sem
);
end_nosem:
if
(
ec
->
common
.
global_lock
)
acpi_release_global_lock
(
glk
);
ec
=
acpi_driver_data
(
first_ec
);
return
result
;
return
acpi_ec_transaction
(
ec
,
command
,
wdata
,
wdata_len
,
rdata
,
rdata_len
);
}
static
int
acpi_ec_intr_query
(
union
acpi_ec
*
ec
,
u32
*
data
)
{
int
status
=
0
;
u32
glk
;
if
(
!
ec
||
!
data
)
return
-
EINVAL
;
*
data
=
0
;
if
(
ec
->
common
.
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
}
EXPORT_SYMBOL
(
ec_transaction
);
down
(
&
ec
->
intr
.
sem
);
static
int
acpi_ec_query
(
struct
acpi_ec
*
ec
,
u8
*
data
)
{
int
result
;
u8
d
;
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBE
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"query EC, IB not empty
\n
"
);
goto
end
;
}
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
acpi_hw_low_level_write
(
8
,
ACPI_EC_COMMAND_QUERY
,
&
ec
->
common
.
command_addr
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF
);
if
(
status
)
{
printk
(
KERN_DEBUG
PREFIX
"query EC, OB not full
\n
"
);
goto
end
;
}
if
(
!
ec
||
!
data
)
return
-
EINVAL
;
acpi_hw_low_level_read
(
8
,
data
,
&
ec
->
common
.
data_addr
);
if
(
!*
data
)
status
=
-
ENODATA
;
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
end:
up
(
&
ec
->
intr
.
sem
);
result
=
acpi_ec_transaction
(
ec
,
ACPI_EC_COMMAND_QUERY
,
NULL
,
0
,
&
d
,
1
);
if
(
result
)
return
result
;
if
(
ec
->
common
.
global_lock
)
acpi_release_global_lock
(
glk
)
;
if
(
!
d
)
return
-
ENODATA
;
return
status
;
*
data
=
d
;
return
0
;
}
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
union
acpi_ec_query_data
{
struct
acpi_ec_query_data
{
acpi_handle
handle
;
u8
data
;
};
static
void
acpi_ec_gpe_query
(
void
*
ec_cxt
)
{
if
(
acpi_ec_poll_mode
)
acpi_ec_gpe_poll_query
(
ec_cxt
);
else
acpi_ec_gpe_intr_query
(
ec_cxt
);
}
static
void
acpi_ec_gpe_poll_query
(
void
*
ec_cxt
)
{
union
acpi_ec
*
ec
=
(
union
acpi_ec
*
)
ec_cxt
;
u32
value
=
0
;
static
char
object_name
[
5
]
=
{
'_'
,
'Q'
,
'0'
,
'0'
,
'\0'
};
const
char
hex
[]
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
};
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
ec_cxt
;
u8
value
=
0
;
static
char
object_name
[
8
];
if
(
!
ec
_cxt
)
if
(
!
ec
)
goto
end
;
if
(
down_interruptible
(
&
ec
->
poll
.
sem
))
{
return
;
}
acpi_hw_low_level_read
(
8
,
&
value
,
&
ec
->
common
.
command_addr
);
up
(
&
ec
->
poll
.
sem
);
/* TBD: Implement asynch events!
* NOTE: All we care about are EC-SCI's. Other EC events are
* handled via polling (yuck!). This is because some systems
* treat EC-SCIs as level (versus EDGE!) triggered, preventing
* a purely interrupt-driven approach (grumble, grumble).
*/
value
=
acpi_ec_read_status
(
ec
);
if
(
!
(
value
&
ACPI_EC_FLAG_SCI
))
goto
end
;
if
(
acpi_ec_query
(
ec
,
&
value
))
goto
end
;
object_name
[
2
]
=
hex
[((
value
>>
4
)
&
0x0F
)];
object_name
[
3
]
=
hex
[(
value
&
0x0F
)];
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Evaluating %s
\n
"
,
object_name
));
snprintf
(
object_name
,
8
,
"_Q%2.2X"
,
value
);
acpi_evaluate_object
(
ec
->
common
.
handle
,
object_name
,
NULL
,
NULL
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Evaluating %s"
,
object_name
)
);
end:
acpi_enable_gpe
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_NOT_ISR
);
}
static
void
acpi_ec_gpe_intr_query
(
void
*
ec_cxt
)
{
union
acpi_ec
*
ec
=
(
union
acpi_ec
*
)
ec_cxt
;
u32
value
;
int
result
=
-
ENODATA
;
static
char
object_name
[
5
]
=
{
'_'
,
'Q'
,
'0'
,
'0'
,
'\0'
};
const
char
hex
[]
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
};
acpi_evaluate_object
(
ec
->
handle
,
object_name
,
NULL
,
NULL
);
if
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_SCI
)
result
=
acpi_ec_query
(
ec
,
&
value
);
if
(
result
)
goto
end
;
object_name
[
2
]
=
hex
[((
value
>>
4
)
&
0x0F
)];
object_name
[
3
]
=
hex
[(
value
&
0x0F
)];
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Evaluating %s
\n
"
,
object_name
));
acpi_evaluate_object
(
ec
->
common
.
handle
,
object_name
,
NULL
,
NULL
);
end:
atomic_dec
(
&
ec
->
intr
.
pending_gpe
);
return
;
acpi_enable_gpe
(
NULL
,
ec
->
gpe_bit
,
ACPI_NOT_ISR
);
}
static
u32
acpi_ec_gpe_handler
(
void
*
data
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_ec_gpe_poll_handler
(
data
);
else
return
acpi_ec_gpe_intr_handler
(
data
);
}
static
u32
acpi_ec_gpe_poll_handler
(
void
*
data
)
{
acpi_status
status
=
AE_OK
;
union
acpi_ec
*
ec
=
(
union
acpi_ec
*
)
data
;
if
(
!
ec
)
return
ACPI_INTERRUPT_NOT_HANDLED
;
acpi_disable_gpe
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_ISR
);
status
=
acpi_os_execute
(
OSL_EC_POLL_HANDLER
,
acpi_ec_gpe_query
,
ec
);
if
(
status
==
AE_OK
)
return
ACPI_INTERRUPT_HANDLED
;
else
return
ACPI_INTERRUPT_NOT_HANDLED
;
}
static
u32
acpi_ec_gpe_intr_handler
(
void
*
data
)
{
acpi_status
status
=
AE_OK
;
u32
value
;
union
acpi_ec
*
ec
=
(
union
acpi_ec
*
)
data
;
if
(
!
ec
)
return
ACPI_INTERRUPT_NOT_HANDLED
;
u8
value
;
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
data
;
acpi_clear_gpe
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_ISR
);
acpi_clear_gpe
(
NULL
,
ec
->
gpe_bit
,
ACPI_ISR
);
value
=
acpi_ec_read_status
(
ec
);
switch
(
ec
->
intr
.
expect_event
)
{
case
ACPI_EC_EVENT_OBF
:
if
(
!
(
value
&
ACPI_EC_FLAG_OBF
))
break
;
ec
->
intr
.
expect_event
=
0
;
wake_up
(
&
ec
->
intr
.
wait
);
break
;
case
ACPI_EC_EVENT_IBE
:
if
((
value
&
ACPI_EC_FLAG_IBF
))
break
;
ec
->
intr
.
expect_event
=
0
;
wake_up
(
&
ec
->
intr
.
wait
);
break
;
default:
break
;
if
(
acpi_ec_mode
==
EC_INTR
)
{
if
(
acpi_ec_check_status
(
value
,
ec
->
expect_event
))
{
ec
->
expect_event
=
0
;
wake_up
(
&
ec
->
wait
);
}
}
if
(
value
&
ACPI_EC_FLAG_SCI
)
{
atomic_add
(
1
,
&
ec
->
intr
.
pending_gpe
);
status
=
acpi_os_execute
(
OSL_EC_BURST_HANDLER
,
acpi_ec_gpe_query
,
ec
);
status
=
acpi_os_execute
(
OSL_EC_BURST_HANDLER
,
acpi_ec_gpe_query
,
ec
);
return
status
==
AE_OK
?
ACPI_INTERRUPT_HANDLED
:
ACPI_INTERRUPT_NOT_HANDLED
;
}
acpi_enable_gpe
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_ISR
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe_bit
,
ACPI_ISR
);
return
status
==
AE_OK
?
ACPI_INTERRUPT_HANDLED
:
ACPI_INTERRUPT_NOT_HANDLED
;
}
...
...
@@ -833,7 +499,7 @@ acpi_ec_space_handler(u32 function,
void
*
handler_context
,
void
*
region_context
)
{
int
result
=
0
;
union
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
=
NULL
;
u64
temp
=
*
value
;
acpi_integer
f_v
=
0
;
int
i
=
0
;
...
...
@@ -843,18 +509,16 @@ acpi_ec_space_handler(u32 function,
return
AE_BAD_PARAMETER
;
if
(
bit_width
!=
8
&&
acpi_strict
)
{
printk
(
KERN_WARNING
PREFIX
"acpi_ec_space_handler: bit_width should be 8
\n
"
);
return
AE_BAD_PARAMETER
;
}
ec
=
(
union
acpi_ec
*
)
handler_context
;
ec
=
(
struct
acpi_ec
*
)
handler_context
;
next_byte:
switch
(
function
)
{
case
ACPI_READ
:
temp
=
0
;
result
=
acpi_ec_read
(
ec
,
(
u8
)
address
,
(
u
32
*
)
&
temp
);
result
=
acpi_ec_read
(
ec
,
(
u8
)
address
,
(
u
8
*
)
&
temp
);
break
;
case
ACPI_WRITE
:
result
=
acpi_ec_write
(
ec
,
(
u8
)
address
,
(
u8
)
temp
);
...
...
@@ -905,20 +569,20 @@ static struct proc_dir_entry *acpi_ec_dir;
static
int
acpi_ec_read_info
(
struct
seq_file
*
seq
,
void
*
offset
)
{
union
acpi_ec
*
ec
=
(
union
acpi_ec
*
)
seq
->
private
;
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
seq
->
private
;
if
(
!
ec
)
goto
end
;
seq_printf
(
seq
,
"gpe bit: 0x%02x
\n
"
,
(
u32
)
ec
->
common
.
gpe_bit
);
(
u32
)
ec
->
gpe_bit
);
seq_printf
(
seq
,
"ports: 0x%02x, 0x%02x
\n
"
,
(
u32
)
ec
->
comm
on
.
status_addr
.
address
,
(
u32
)
ec
->
common
.
data_addr
.
address
);
(
u32
)
ec
->
comm
and_addr
,
(
u32
)
ec
->
data_addr
);
seq_printf
(
seq
,
"use global lock: %s
\n
"
,
ec
->
common
.
global_lock
?
"yes"
:
"no"
);
acpi_enable_gpe
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_NOT_ISR
);
ec
->
global_lock
?
"yes"
:
"no"
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe_bit
,
ACPI_NOT_ISR
);
end:
return
0
;
...
...
@@ -929,7 +593,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
return
single_open
(
file
,
acpi_ec_read_info
,
PDE
(
inode
)
->
data
);
}
static
const
struct
file_operations
acpi_ec_info_ops
=
{
static
struct
file_operations
acpi_ec_info_ops
=
{
.
open
=
acpi_ec_info_open_fs
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
...
...
@@ -978,101 +642,35 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
Driver Interface
-------------------------------------------------------------------------- */
static
int
acpi_ec_
poll_
add
(
struct
acpi_device
*
device
)
static
int
acpi_ec_add
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
union
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
kmalloc
(
sizeof
(
union
acpi_ec
),
GFP_KERNEL
);
ec
=
kmalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec
)
return
-
ENOMEM
;
memset
(
ec
,
0
,
sizeof
(
union
acpi_ec
));
ec
->
common
.
handle
=
device
->
handle
;
ec
->
common
.
uid
=
-
1
;
init_MUTEX
(
&
ec
->
poll
.
sem
);
strcpy
(
acpi_device_name
(
device
),
ACPI_EC_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ACPI_EC_CLASS
);
acpi_driver_data
(
device
)
=
ec
;
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer
(
ec
->
common
.
handle
,
"_GLK"
,
NULL
,
&
ec
->
common
.
global_lock
);
/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
if
(
ec_ecdt
)
{
acpi_remove_address_space_handler
(
ACPI_ROOT_OBJECT
,
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
);
acpi_remove_gpe_handler
(
NULL
,
ec_ecdt
->
common
.
gpe_bit
,
&
acpi_ec_gpe_handler
);
kfree
(
ec_ecdt
);
memset
(
ec
,
0
,
sizeof
(
struct
acpi_ec
));
ec
->
handle
=
device
->
handle
;
ec
->
uid
=
-
1
;
init_MUTEX
(
&
ec
->
sem
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
atomic_set
(
&
ec
->
leaving_burst
,
1
);
init_waitqueue_head
(
&
ec
->
wait
);
}
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status
=
acpi_evaluate_integer
(
ec
->
common
.
handle
,
"_GPE"
,
NULL
,
&
ec
->
common
.
gpe_bit
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Obtaining GPE bit"
));
result
=
-
ENODEV
;
goto
end
;
}
result
=
acpi_ec_add_fs
(
device
);
if
(
result
)
goto
end
;
printk
(
KERN_INFO
PREFIX
"%s [%s] (gpe %d) polling mode.
\n
"
,
acpi_device_name
(
device
),
acpi_device_bid
(
device
),
(
u32
)
ec
->
common
.
gpe_bit
);
if
(
!
first_ec
)
first_ec
=
device
;
end:
if
(
result
)
kfree
(
ec
);
return
result
;
}
static
int
acpi_ec_intr_add
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
union
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
kmalloc
(
sizeof
(
union
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec
)
return
-
ENOMEM
;
memset
(
ec
,
0
,
sizeof
(
union
acpi_ec
));
ec
->
common
.
handle
=
device
->
handle
;
ec
->
common
.
uid
=
-
1
;
atomic_set
(
&
ec
->
intr
.
pending_gpe
,
0
);
atomic_set
(
&
ec
->
intr
.
leaving_burst
,
1
);
init_MUTEX
(
&
ec
->
intr
.
sem
);
init_waitqueue_head
(
&
ec
->
intr
.
wait
);
strcpy
(
acpi_device_name
(
device
),
ACPI_EC_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ACPI_EC_CLASS
);
acpi_driver_data
(
device
)
=
ec
;
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer
(
ec
->
common
.
handle
,
"_GLK"
,
NULL
,
&
ec
->
common
.
global_lock
);
acpi_evaluate_integer
(
ec
->
handle
,
"_GLK"
,
NULL
,
&
ec
->
global_lock
);
/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
...
...
@@ -1081,7 +679,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
);
acpi_remove_gpe_handler
(
NULL
,
ec_ecdt
->
common
.
gpe_bit
,
acpi_remove_gpe_handler
(
NULL
,
ec_ecdt
->
gpe_bit
,
&
acpi_ec_gpe_handler
);
kfree
(
ec_ecdt
);
...
...
@@ -1090,10 +688,10 @@ static int acpi_ec_intr_add(struct acpi_device *device)
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status
=
acpi_evaluate_integer
(
ec
->
common
.
handle
,
"_GPE"
,
NULL
,
&
ec
->
common
.
gpe_bit
);
acpi_evaluate_integer
(
ec
->
handle
,
"_GPE"
,
NULL
,
&
ec
->
gpe_bit
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_ERR
PREFIX
"Obtaining GPE bit assignment
\n
"
);
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Obtaining GPE bit assignment"
)
);
result
=
-
ENODEV
;
goto
end
;
}
...
...
@@ -1102,14 +700,14 @@ static int acpi_ec_intr_add(struct acpi_device *device)
if
(
result
)
goto
end
;
printk
(
KERN_INFO
PREFIX
"%s [%s] (gpe %d) interrupt mode.
\n
"
,
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"%s [%s] (gpe %d) interrupt mode.
"
,
acpi_device_name
(
device
),
acpi_device_bid
(
device
),
(
u32
)
ec
->
common
.
gpe_bit
);
(
u32
)
ec
->
gpe_bit
)
);
if
(
!
first_ec
)
first_ec
=
device
;
end:
end:
if
(
result
)
kfree
(
ec
);
...
...
@@ -1118,7 +716,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
static
int
acpi_ec_remove
(
struct
acpi_device
*
device
,
int
type
)
{
union
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
...
...
@@ -1136,8 +734,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
static
acpi_status
acpi_ec_io_ports
(
struct
acpi_resource
*
resource
,
void
*
context
)
{
union
acpi_ec
*
ec
=
(
union
acpi_ec
*
)
context
;
struct
acpi_generic_address
*
addr
;
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
context
;
if
(
resource
->
type
!=
ACPI_RESOURCE_TYPE_IO
)
{
return
AE_OK
;
...
...
@@ -1148,26 +745,21 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
* the second address region returned is the status/command
* port.
*/
if
(
ec
->
common
.
data_addr
.
register_bit_width
==
0
)
{
addr
=
&
ec
->
common
.
data_addr
;
}
else
if
(
ec
->
comm
on
.
command_addr
.
register_bit_width
==
0
)
{
addr
=
&
ec
->
common
.
command_addr
;
if
(
ec
->
data_addr
==
0
)
{
ec
->
data_addr
=
resource
->
data
.
io
.
minimum
;
}
else
if
(
ec
->
comm
and_addr
==
0
)
{
ec
->
command_addr
=
resource
->
data
.
io
.
minimum
;
}
else
{
return
AE_CTRL_TERMINATE
;
}
addr
->
address_space_id
=
ACPI_ADR_SPACE_SYSTEM_IO
;
addr
->
register_bit_width
=
8
;
addr
->
register_bit_offset
=
0
;
addr
->
address
=
resource
->
data
.
io
.
minimum
;
return
AE_OK
;
}
static
int
acpi_ec_start
(
struct
acpi_device
*
device
)
{
acpi_status
status
=
AE_OK
;
union
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
...
...
@@ -1181,39 +773,35 @@ static int acpi_ec_start(struct acpi_device *device)
/*
* Get I/O port addresses. Convert to GAS format.
*/
status
=
acpi_walk_resources
(
ec
->
common
.
handle
,
METHOD_NAME__CRS
,
status
=
acpi_walk_resources
(
ec
->
handle
,
METHOD_NAME__CRS
,
acpi_ec_io_ports
,
ec
);
if
(
ACPI_FAILURE
(
status
)
||
ec
->
common
.
command_addr
.
register_bit_width
==
0
)
{
printk
(
KERN_ERR
PREFIX
"Error getting I/O port addresses
\n
"
);
if
(
ACPI_FAILURE
(
status
)
||
ec
->
command_addr
==
0
)
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Error getting I/O port addresses"
)
);
return
-
ENODEV
;
}
ec
->
common
.
status_addr
=
ec
->
common
.
command_addr
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"gpe=0x%02x, ports=0x%2x,0x%2x
\n
"
,
(
u32
)
ec
->
common
.
gpe_bit
,
(
u32
)
ec
->
common
.
command_addr
.
address
,
(
u32
)
ec
->
common
.
data_addr
.
address
));
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"gpe=0x%02lx, ports=0x%2lx,0x%2lx"
,
ec
->
gpe_bit
,
ec
->
command_addr
,
ec
->
data_addr
));
/*
* Install GPE handler
*/
status
=
acpi_install_gpe_handler
(
NULL
,
ec
->
common
.
gpe_bit
,
status
=
acpi_install_gpe_handler
(
NULL
,
ec
->
gpe_bit
,
ACPI_GPE_EDGE_TRIGGERED
,
&
acpi_ec_gpe_handler
,
ec
);
if
(
ACPI_FAILURE
(
status
))
{
return
-
ENODEV
;
}
acpi_set_gpe_type
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec
->
common
.
gpe_bit
,
ACPI_NOT_ISR
);
acpi_set_gpe_type
(
NULL
,
ec
->
gpe_bit
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe_bit
,
ACPI_NOT_ISR
);
status
=
acpi_install_address_space_handler
(
ec
->
common
.
handle
,
status
=
acpi_install_address_space_handler
(
ec
->
handle
,
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
,
&
acpi_ec_space_setup
,
ec
);
if
(
ACPI_FAILURE
(
status
))
{
acpi_remove_gpe_handler
(
NULL
,
ec
->
common
.
gpe_bit
,
acpi_remove_gpe_handler
(
NULL
,
ec
->
gpe_bit
,
&
acpi_ec_gpe_handler
);
return
-
ENODEV
;
}
...
...
@@ -1224,7 +812,7 @@ static int acpi_ec_start(struct acpi_device *device)
static
int
acpi_ec_stop
(
struct
acpi_device
*
device
,
int
type
)
{
acpi_status
status
=
AE_OK
;
union
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
...
...
@@ -1232,14 +820,14 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
ec
=
acpi_driver_data
(
device
);
status
=
acpi_remove_address_space_handler
(
ec
->
common
.
handle
,
status
=
acpi_remove_address_space_handler
(
ec
->
handle
,
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
status
=
acpi_remove_gpe_handler
(
NULL
,
ec
->
common
.
gpe_bit
,
acpi_remove_gpe_handler
(
NULL
,
ec
->
gpe_bit
,
&
acpi_ec_gpe_handler
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
...
...
@@ -1251,76 +839,30 @@ static acpi_status __init
acpi_fake_ecdt_callback
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_fake_ecdt_poll_callback
(
handle
,
Level
,
context
,
retval
);
else
return
acpi_fake_ecdt_intr_callback
(
handle
,
Level
,
context
,
retval
);
}
static
acpi_status
__init
acpi_fake_ecdt_poll_callback
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
)
{
acpi_status
status
;
status
=
acpi_walk_resources
(
handle
,
METHOD_NAME__CRS
,
acpi_ec_io_ports
,
ec_ecdt
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
ec_ecdt
->
common
.
status_addr
=
ec_ecdt
->
common
.
command_addr
;
ec_ecdt
->
common
.
uid
=
-
1
;
acpi_evaluate_integer
(
handle
,
"_UID"
,
NULL
,
&
ec_ecdt
->
common
.
uid
);
status
=
acpi_evaluate_integer
(
handle
,
"_GPE"
,
NULL
,
&
ec_ecdt
->
common
.
gpe_bit
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
init_MUTEX
(
&
ec_ecdt
->
poll
.
sem
);
ec_ecdt
->
common
.
global_lock
=
TRUE
;
ec_ecdt
->
common
.
handle
=
handle
;
printk
(
KERN_INFO
PREFIX
"GPE=0x%02x, ports=0x%2x, 0x%2x
\n
"
,
(
u32
)
ec_ecdt
->
common
.
gpe_bit
,
(
u32
)
ec_ecdt
->
common
.
command_addr
.
address
,
(
u32
)
ec_ecdt
->
common
.
data_addr
.
address
);
return
AE_CTRL_TERMINATE
;
}
static
acpi_status
__init
acpi_fake_ecdt_intr_callback
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
)
{
acpi_status
status
;
init_MUTEX
(
&
ec_ecdt
->
intr
.
sem
);
init_waitqueue_head
(
&
ec_ecdt
->
intr
.
wait
);
init_MUTEX
(
&
ec_ecdt
->
sem
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
init_waitqueue_head
(
&
ec_ecdt
->
wait
);
}
status
=
acpi_walk_resources
(
handle
,
METHOD_NAME__CRS
,
acpi_ec_io_ports
,
ec_ecdt
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
ec_ecdt
->
common
.
status_addr
=
ec_ecdt
->
common
.
command_addr
;
ec_ecdt
->
common
.
uid
=
-
1
;
acpi_evaluate_integer
(
handle
,
"_UID"
,
NULL
,
&
ec_ecdt
->
common
.
uid
);
ec_ecdt
->
uid
=
-
1
;
acpi_evaluate_integer
(
handle
,
"_UID"
,
NULL
,
&
ec_ecdt
->
uid
);
status
=
acpi_evaluate_integer
(
handle
,
"_GPE"
,
NULL
,
&
ec_ecdt
->
common
.
gpe_bit
);
&
ec_ecdt
->
gpe_bit
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
ec_ecdt
->
common
.
global_lock
=
TRUE
;
ec_ecdt
->
common
.
handle
=
handle
;
ec_ecdt
->
global_lock
=
TRUE
;
ec_ecdt
->
handle
=
handle
;
printk
(
KERN_INFO
PREFIX
"GPE=0x%02x, ports=0x%2x, 0x%2x
\n
"
,
(
u32
)
ec_ecdt
->
common
.
gpe_bit
,
(
u32
)
ec_ecdt
->
common
.
command_addr
.
address
,
(
u32
)
ec_ecdt
->
common
.
data_addr
.
address
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"GPE=0x%02lx, ports=0x%2lx, 0x%2lx"
,
ec_ecdt
->
gpe_bit
,
ec_ecdt
->
command_addr
,
ec_ecdt
->
data_addr
));
return
AE_CTRL_TERMINATE
;
}
...
...
@@ -1340,14 +882,14 @@ static int __init acpi_ec_fake_ecdt(void)
acpi_status
status
;
int
ret
=
0
;
printk
(
KERN_INFO
PREFIX
"Try to make an fake ECDT
\n
"
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Try to make an fake ECDT"
)
);
ec_ecdt
=
kmalloc
(
sizeof
(
union
acpi_ec
),
GFP_KERNEL
);
ec_ecdt
=
kmalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec_ecdt
)
{
ret
=
-
ENOMEM
;
goto
error
;
}
memset
(
ec_ecdt
,
0
,
sizeof
(
union
acpi_ec
));
memset
(
ec_ecdt
,
0
,
sizeof
(
struct
acpi_ec
));
status
=
acpi_get_devices
(
ACPI_EC_HID
,
acpi_fake_ecdt_callback
,
NULL
,
NULL
);
...
...
@@ -1355,23 +897,15 @@ static int __init acpi_ec_fake_ecdt(void)
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
ret
=
-
ENODEV
;
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Can't make an fake ECDT"
));
goto
error
;
}
return
0
;
error:
printk
(
KERN_ERR
PREFIX
"Can't make an fake ECDT
\n
"
);
error:
return
ret
;
}
static
int
__init
acpi_ec_get_real_ecdt
(
void
)
{
if
(
acpi_ec_poll_mode
)
return
acpi_ec_poll_get_real_ecdt
();
else
return
acpi_ec_intr_get_real_ecdt
();
}
static
int
__init
acpi_ec_poll_get_real_ecdt
(
void
)
{
acpi_status
status
;
struct
acpi_table_ecdt
*
ecdt_ptr
;
...
...
@@ -1382,80 +916,36 @@ static int __init acpi_ec_poll_get_real_ecdt(void)
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
printk
(
KERN_INFO
PREFIX
"Found ECDT
\n
"
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Found ECDT"
)
);
/*
* Generate a temporary ec context to use until the namespace is scanned
*/
ec_ecdt
=
kmalloc
(
sizeof
(
union
acpi_ec
),
GFP_KERNEL
);
ec_ecdt
=
kmalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec_ecdt
)
return
-
ENOMEM
;
memset
(
ec_ecdt
,
0
,
sizeof
(
union
acpi_ec
));
ec_ecdt
->
common
.
command_addr
=
ecdt_ptr
->
ec_control
;
ec_ecdt
->
common
.
status_addr
=
ecdt_ptr
->
ec_control
;
ec_ecdt
->
common
.
data_addr
=
ecdt_ptr
->
ec_data
;
ec_ecdt
->
common
.
gpe_bit
=
ecdt_ptr
->
gpe_bit
;
init_MUTEX
(
&
ec_ecdt
->
poll
.
sem
);
/* use the GL just to be safe */
ec_ecdt
->
common
.
global_lock
=
TRUE
;
ec_ecdt
->
common
.
uid
=
ecdt_ptr
->
uid
;
memset
(
ec_ecdt
,
0
,
sizeof
(
struct
acpi_ec
));
status
=
acpi_get_handle
(
NULL
,
ecdt_ptr
->
ec_id
,
&
ec_ecdt
->
common
.
handle
);
if
(
ACPI_FAILURE
(
status
))
{
goto
error
;
init_MUTEX
(
&
ec_ecdt
->
sem
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
init_waitqueue_head
(
&
ec_ecdt
->
wait
);
}
return
0
;
error:
printk
(
KERN_ERR
PREFIX
"Could not use ECDT
\n
"
);
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
return
-
ENODEV
;
}
static
int
__init
acpi_ec_intr_get_real_ecdt
(
void
)
{
acpi_status
status
;
struct
acpi_table_ecdt
*
ecdt_ptr
;
status
=
acpi_get_firmware_table
(
"ECDT"
,
1
,
ACPI_LOGICAL_ADDRESSING
,
(
struct
acpi_table_header
**
)
&
ecdt_ptr
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
printk
(
KERN_INFO
PREFIX
"Found ECDT
\n
"
);
/*
* Generate a temporary ec context to use until the namespace is scanned
*/
ec_ecdt
=
kmalloc
(
sizeof
(
union
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec_ecdt
)
return
-
ENOMEM
;
memset
(
ec_ecdt
,
0
,
sizeof
(
union
acpi_ec
));
init_MUTEX
(
&
ec_ecdt
->
intr
.
sem
);
init_waitqueue_head
(
&
ec_ecdt
->
intr
.
wait
);
ec_ecdt
->
common
.
command_addr
=
ecdt_ptr
->
ec_control
;
ec_ecdt
->
common
.
status_addr
=
ecdt_ptr
->
ec_control
;
ec_ecdt
->
common
.
data_addr
=
ecdt_ptr
->
ec_data
;
ec_ecdt
->
common
.
gpe_bit
=
ecdt_ptr
->
gpe_bit
;
ec_ecdt
->
command_addr
=
ecdt_ptr
->
ec_control
.
address
;
ec_ecdt
->
data_addr
=
ecdt_ptr
->
ec_data
.
address
;
ec_ecdt
->
gpe_bit
=
ecdt_ptr
->
gpe_bit
;
/* use the GL just to be safe */
ec_ecdt
->
common
.
global_lock
=
TRUE
;
ec_ecdt
->
common
.
uid
=
ecdt_ptr
->
uid
;
ec_ecdt
->
global_lock
=
TRUE
;
ec_ecdt
->
uid
=
ecdt_ptr
->
uid
;
status
=
acpi_get_handle
(
NULL
,
ecdt_ptr
->
ec_id
,
&
ec_ecdt
->
common
.
handle
);
acpi_get_handle
(
NULL
,
ecdt_ptr
->
ec_id
,
&
ec_ecdt
->
handle
);
if
(
ACPI_FAILURE
(
status
))
{
goto
error
;
}
return
0
;
error:
printk
(
KERN_ERR
PREFIX
"Could not use ECDT
\n
"
);
error:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Could not use ECDT"
)
);
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
...
...
@@ -1480,14 +970,14 @@ int __init acpi_ec_ecdt_probe(void)
/*
* Install GPE handler
*/
status
=
acpi_install_gpe_handler
(
NULL
,
ec_ecdt
->
common
.
gpe_bit
,
status
=
acpi_install_gpe_handler
(
NULL
,
ec_ecdt
->
gpe_bit
,
ACPI_GPE_EDGE_TRIGGERED
,
&
acpi_ec_gpe_handler
,
ec_ecdt
);
if
(
ACPI_FAILURE
(
status
))
{
goto
error
;
}
acpi_set_gpe_type
(
NULL
,
ec_ecdt
->
common
.
gpe_bit
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec_ecdt
->
common
.
gpe_bit
,
ACPI_NOT_ISR
);
acpi_set_gpe_type
(
NULL
,
ec_ecdt
->
gpe_bit
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec_ecdt
->
gpe_bit
,
ACPI_NOT_ISR
);
status
=
acpi_install_address_space_handler
(
ACPI_ROOT_OBJECT
,
ACPI_ADR_SPACE_EC
,
...
...
@@ -1495,7 +985,7 @@ int __init acpi_ec_ecdt_probe(void)
&
acpi_ec_space_setup
,
ec_ecdt
);
if
(
ACPI_FAILURE
(
status
))
{
acpi_remove_gpe_handler
(
NULL
,
ec_ecdt
->
common
.
gpe_bit
,
acpi_remove_gpe_handler
(
NULL
,
ec_ecdt
->
gpe_bit
,
&
acpi_ec_gpe_handler
);
goto
error
;
}
...
...
@@ -1503,7 +993,7 @@ int __init acpi_ec_ecdt_probe(void)
return
0
;
error:
printk
(
KERN_ERR
PREFIX
"Could not use ECDT
\n
"
);
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Could not use ECDT"
)
);
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
...
...
@@ -1562,13 +1052,13 @@ static int __init acpi_ec_set_intr_mode(char *str)
return
0
;
if
(
intr
)
{
acpi_ec_poll_mode
=
EC_INTR
;
acpi_ec_driver
.
ops
.
add
=
acpi_ec_intr_add
;
acpi_ec_mode
=
EC_INTR
;
}
else
{
acpi_ec_poll_mode
=
EC_POLL
;
acpi_ec_driver
.
ops
.
add
=
acpi_ec_poll_add
;
acpi_ec_mode
=
EC_POLL
;
}
printk
(
KERN_INFO
PREFIX
"EC %s mode.
\n
"
,
intr
?
"interrupt"
:
"polling"
);
acpi_ec_driver
.
ops
.
add
=
acpi_ec_add
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"EC %s mode.
\n
"
,
intr
?
"interrupt"
:
"polling"
));
return
1
;
}
...
...
include/linux/acpi.h
浏览文件 @
ed3269a3
...
...
@@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
extern
int
ec_read
(
u8
addr
,
u8
*
val
);
extern
int
ec_write
(
u8
addr
,
u8
val
);
extern
int
ec_transaction
(
u8
command
,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
);
#endif
/*CONFIG_ACPI_EC*/
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录