Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
ed3269a3
Commit
ed3269a3
authored
Oct 14, 2006
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Pull ec into test branch
parents
d7321ad2
ab9e43c6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
296 additions
and
803 deletions
+296
-803
drivers/acpi/ec.c
drivers/acpi/ec.c
+293
-803
include/linux/acpi.h
include/linux/acpi.h
+3
-0
No files found.
drivers/acpi/ec.c
View file @
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
View file @
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*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment