Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
03feb052
Commit
03feb052
authored
Apr 28, 2007
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Pull ec into release branch
parents
fb165969
9fd9f8e8
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
181 additions
and
321 deletions
+181
-321
drivers/acpi/Makefile
drivers/acpi/Makefile
+4
-3
drivers/acpi/ec.c
drivers/acpi/ec.c
+177
-318
No files found.
drivers/acpi/Makefile
View file @
03feb052
#
# Makefile for the Linux ACPI interpreter
#
#
export
ACPI_CFLAGS
...
...
@@ -32,16 +32,17 @@ obj-y += osl.o utils.o \
processor-objs
+=
processor_core.o processor_throttling.o
\
processor_idle.o processor_thermal.o
ifdef
CONFIG_CPU_FREQ
processor-objs
+=
processor_perflib.o
processor-objs
+=
processor_perflib.o
endif
obj-y
+=
sleep
/
obj-y
+=
bus.o glue.o
obj-y
+=
scan.o
# Keep EC driver first. Initialization of others depend on it.
obj-$(CONFIG_ACPI_EC)
+=
ec.o
obj-$(CONFIG_ACPI_AC)
+=
ac.o
obj-$(CONFIG_ACPI_BATTERY)
+=
battery.o
obj-$(CONFIG_ACPI_BUTTON)
+=
button.o
obj-$(CONFIG_ACPI_EC)
+=
ec.o
obj-$(CONFIG_ACPI_FAN)
+=
fan.o
obj-$(CONFIG_ACPI_DOCK)
+=
dock.o
obj-$(CONFIG_ACPI_BAY)
+=
bay.o
...
...
drivers/acpi/ec.c
View file @
03feb052
/*
*
acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $
)
*
ec.c - ACPI Embedded Controller Driver (v2.0
)
*
* Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
* Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
...
...
@@ -91,9 +93,9 @@ static struct acpi_driver acpi_ec_driver = {
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
static
struct
acpi_ec
{
acpi_handle
handle
;
unsigned
long
uid
;
unsigned
long
gpe
;
unsigned
long
command_addr
;
unsigned
long
data_addr
;
...
...
@@ -101,12 +103,8 @@ static struct acpi_ec {
struct
mutex
lock
;
atomic_t
query_pending
;
atomic_t
event_count
;
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
;
}
*
boot_ec
,
*
first_ec
;
/* --------------------------------------------------------------------------
Transaction Management
...
...
@@ -173,56 +171,6 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
return
-
ETIME
;
}
#ifdef ACPI_FUTURE_USAGE
/*
* 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
(
struct
acpi_ec
*
ec
)
{
u8
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_IBF_0
);
if
(
status
)
goto
end
;
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
->
leaving_burst
,
0
);
return
0
;
end:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"EC wait, burst mode"
));
return
-
1
;
}
int
acpi_ec_leave_burst_mode
(
struct
acpi_ec
*
ec
)
{
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_IBF_0
);
if
(
status
)
goto
end
;
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"
));
return
-
1
;
}
#endif
/* ACPI_FUTURE_USAGE */
static
int
acpi_ec_transaction_unlocked
(
struct
acpi_ec
*
ec
,
u8
command
,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
)
...
...
@@ -312,6 +260,21 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
return
status
;
}
/*
* Note: samsung nv5000 doesn't work with ec burst mode.
* http://bugzilla.kernel.org/show_bug.cgi?id=4980
*/
int
acpi_ec_burst_enable
(
struct
acpi_ec
*
ec
)
{
u8
d
;
return
acpi_ec_transaction
(
ec
,
ACPI_EC_BURST_ENABLE
,
NULL
,
0
,
&
d
,
1
);
}
int
acpi_ec_burst_disable
(
struct
acpi_ec
*
ec
)
{
return
acpi_ec_transaction
(
ec
,
ACPI_EC_BURST_DISABLE
,
NULL
,
0
,
NULL
,
0
);
}
static
int
acpi_ec_read
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
*
data
)
{
int
result
;
...
...
@@ -333,18 +296,33 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
int
ec_burst_enable
(
void
)
{
if
(
!
first_ec
)
return
-
ENODEV
;
return
acpi_ec_burst_enable
(
first_ec
);
}
EXPORT_SYMBOL
(
ec_burst_enable
);
int
ec_burst_disable
(
void
)
{
if
(
!
first_ec
)
return
-
ENODEV
;
return
acpi_ec_burst_disable
(
first_ec
);
}
EXPORT_SYMBOL
(
ec_burst_disable
);
int
ec_read
(
u8
addr
,
u8
*
val
)
{
struct
acpi_ec
*
ec
;
int
err
;
u8
temp_data
;
if
(
!
first_ec
)
return
-
ENODEV
;
ec
=
acpi_driver_data
(
first_ec
);
err
=
acpi_ec_read
(
ec
,
addr
,
&
temp_data
);
err
=
acpi_ec_read
(
first_ec
,
addr
,
&
temp_data
);
if
(
!
err
)
{
*
val
=
temp_data
;
...
...
@@ -357,15 +335,12 @@ EXPORT_SYMBOL(ec_read);
int
ec_write
(
u8
addr
,
u8
val
)
{
struct
acpi_ec
*
ec
;
int
err
;
if
(
!
first_ec
)
return
-
ENODEV
;
ec
=
acpi_driver_data
(
first_ec
);
err
=
acpi_ec_write
(
ec
,
addr
,
val
);
err
=
acpi_ec_write
(
first_ec
,
addr
,
val
);
return
err
;
}
...
...
@@ -376,14 +351,10 @@ int ec_transaction(u8 command,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
)
{
struct
acpi_ec
*
ec
;
if
(
!
first_ec
)
return
-
ENODEV
;
ec
=
acpi_driver_data
(
first_ec
);
return
acpi_ec_transaction
(
ec
,
command
,
wdata
,
return
acpi_ec_transaction
(
first_ec
,
command
,
wdata
,
wdata_len
,
rdata
,
rdata_len
);
}
...
...
@@ -420,7 +391,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
static
void
acpi_ec_gpe_query
(
void
*
ec_cxt
)
{
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
ec_cxt
;
struct
acpi_ec
*
ec
=
ec_cxt
;
u8
value
=
0
;
char
object_name
[
8
];
...
...
@@ -438,8 +409,9 @@ static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status
status
=
AE_OK
;
u8
value
;
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
data
;
struct
acpi_ec
*
ec
=
data
;
atomic_inc
(
&
ec
->
event_count
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
wake_up
(
&
ec
->
wait
);
}
...
...
@@ -482,7 +454,7 @@ acpi_ec_space_handler(u32 function,
void
*
handler_context
,
void
*
region_context
)
{
int
result
=
0
;
struct
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
=
handler_context
;
u64
temp
=
*
value
;
acpi_integer
f_v
=
0
;
int
i
=
0
;
...
...
@@ -494,8 +466,6 @@ acpi_ec_space_handler(u32 function,
return
AE_BAD_PARAMETER
;
}
ec
=
(
struct
acpi_ec
*
)
handler_context
;
next_byte:
switch
(
function
)
{
case
ACPI_READ
:
...
...
@@ -551,18 +521,16 @@ static struct proc_dir_entry *acpi_ec_dir;
static
int
acpi_ec_read_info
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
seq
->
private
;
struct
acpi_ec
*
ec
=
seq
->
private
;
if
(
!
ec
)
goto
end
;
seq_printf
(
seq
,
"gpe:
0x%02x
\n
"
,
(
u32
)
ec
->
gpe
);
seq_printf
(
seq
,
"ports:
0x%02x, 0x%02x
\n
"
,
(
u
32
)
ec
->
command_addr
,
(
u32
)
ec
->
data_addr
);
seq_printf
(
seq
,
"use global lock:
%s
\n
"
,
seq_printf
(
seq
,
"gpe:
\t\t\t
0x%02x
\n
"
,
(
u32
)
ec
->
gpe
);
seq_printf
(
seq
,
"ports:
\t\t\t
0x%02x, 0x%02x
\n
"
,
(
u
nsigned
)
ec
->
command_addr
,
(
unsigned
)
ec
->
data_addr
);
seq_printf
(
seq
,
"use global lock:
\t
%s
\n
"
,
ec
->
global_lock
?
"yes"
:
"no"
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
end:
return
0
;
}
...
...
@@ -619,154 +587,122 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static
acpi_status
ec_parse_io_ports
(
struct
acpi_resource
*
resource
,
void
*
context
);
static
acpi_status
ec_parse_device
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
);
static
struct
acpi_ec
*
make_acpi_ec
(
void
)
{
struct
acpi_ec
*
ec
=
kzalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec
)
return
NULL
;
atomic_set
(
&
ec
->
query_pending
,
1
);
atomic_set
(
&
ec
->
event_count
,
1
);
mutex_init
(
&
ec
->
lock
);
init_waitqueue_head
(
&
ec
->
wait
);
return
ec
;
}
static
int
acpi_ec_add
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
struct
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
kzalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec
)
return
-
ENOMEM
;
ec
->
handle
=
device
->
handle
;
ec
->
uid
=
-
1
;
mutex_init
(
&
ec
->
lock
);
atomic_set
(
&
ec
->
query_pending
,
0
);
atomic_set
(
&
ec
->
event_count
,
1
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
atomic_set
(
&
ec
->
leaving_burst
,
1
);
init_waitqueue_head
(
&
ec
->
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
->
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 */
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
->
gpe
,
&
acpi_ec_gpe_handler
);
ec
=
make_acpi_ec
();
if
(
!
ec
)
return
-
ENOMEM
;
kfree
(
ec_ecdt
);
status
=
ec_parse_device
(
device
->
handle
,
0
,
ec
,
NULL
);
if
(
status
!=
AE_CTRL_TERMINATE
)
{
kfree
(
ec
);
return
-
EINVAL
;
}
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status
=
acpi_evaluate_integer
(
ec
->
handle
,
"_GPE"
,
NULL
,
&
ec
->
gpe
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Obtaining GPE bit assignment"
));
result
=
-
ENODEV
;
goto
end
;
}
/* Check if we found the boot EC */
if
(
boot_ec
)
{
if
(
boot_ec
->
gpe
==
ec
->
gpe
)
{
/* We might have incorrect info for GL at boot time */
mutex_lock
(
&
boot_ec
->
lock
);
boot_ec
->
global_lock
=
ec
->
global_lock
;
mutex_unlock
(
&
boot_ec
->
lock
);
kfree
(
ec
);
ec
=
boot_ec
;
}
}
else
first_ec
=
ec
;
ec
->
handle
=
device
->
handle
;
acpi_driver_data
(
device
)
=
ec
;
result
=
acpi_ec_add_fs
(
device
);
if
(
result
)
goto
end
;
acpi_ec_add_fs
(
device
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"%s [%s] (gpe %d) interrupt mode."
,
acpi_device_name
(
device
),
acpi_device_bid
(
device
),
(
u32
)
ec
->
gpe
));
if
(
!
first_ec
)
first_ec
=
device
;
end:
if
(
result
)
kfree
(
ec
);
return
result
;
return
0
;
}
static
int
acpi_ec_remove
(
struct
acpi_device
*
device
,
int
type
)
{
struct
acpi_ec
*
ec
=
NULL
;
struct
acpi_ec
*
ec
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
acpi_driver_data
(
device
);
acpi_ec_remove_fs
(
device
);
acpi_driver_data
(
device
)
=
NULL
;
if
(
ec
==
first_ec
)
first_ec
=
NULL
;
kfree
(
ec
);
/* Don't touch boot EC */
if
(
boot_ec
!=
ec
)
kfree
(
ec
);
return
0
;
}
static
acpi_status
acpi_ec
_io_ports
(
struct
acpi_resource
*
resource
,
void
*
context
)
ec_parse
_io_ports
(
struct
acpi_resource
*
resource
,
void
*
context
)
{
struct
acpi_ec
*
ec
=
(
struct
acpi_ec
*
)
context
;
struct
acpi_ec
*
ec
=
context
;
if
(
resource
->
type
!=
ACPI_RESOURCE_TYPE_IO
)
{
if
(
resource
->
type
!=
ACPI_RESOURCE_TYPE_IO
)
return
AE_OK
;
}
/*
* The first address region returned is the data port, and
* the second address region returned is the status/command
* port.
*/
if
(
ec
->
data_addr
==
0
)
{
if
(
ec
->
data_addr
==
0
)
ec
->
data_addr
=
resource
->
data
.
io
.
minimum
;
}
else
if
(
ec
->
command_addr
==
0
)
{
else
if
(
ec
->
command_addr
==
0
)
ec
->
command_addr
=
resource
->
data
.
io
.
minimum
;
}
else
{
else
return
AE_CTRL_TERMINATE
;
}
return
AE_OK
;
}
static
int
acpi_ec_start
(
struct
acpi_device
*
device
)
static
int
ec_install_handlers
(
struct
acpi_ec
*
ec
)
{
acpi_status
status
=
AE_OK
;
struct
acpi_ec
*
ec
=
NULL
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
acpi_driver_data
(
device
);
if
(
!
ec
)
return
-
EINVAL
;
/*
* Get I/O port addresses. Convert to GAS format.
*/
status
=
acpi_walk_resources
(
ec
->
handle
,
METHOD_NAME__CRS
,
acpi_ec_io_ports
,
ec
);
if
(
ACPI_FAILURE
(
status
)
||
ec
->
command_addr
==
0
)
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Error getting I/O port addresses"
));
return
-
ENODEV
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"gpe=0x%02lx, ports=0x%2lx,0x%2lx"
,
ec
->
gpe
,
ec
->
command_addr
,
ec
->
data_addr
));
/*
* Install GPE handler
*/
acpi_status
status
;
status
=
acpi_install_gpe_handler
(
NULL
,
ec
->
gpe
,
ACPI_GPE_EDGE_TRIGGERED
,
&
acpi_ec_gpe_handler
,
ec
);
if
(
ACPI_FAILURE
(
status
))
{
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
}
acpi_set_gpe_type
(
NULL
,
ec
->
gpe
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
...
...
@@ -779,18 +715,49 @@ static int acpi_ec_start(struct acpi_device *device)
return
-
ENODEV
;
}
return
AE_OK
;
/* EC is fully operational, allow queries */
atomic_set
(
&
ec
->
query_pending
,
0
);
return
0
;
}
static
int
acpi_ec_start
(
struct
acpi_device
*
device
)
{
struct
acpi_ec
*
ec
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
acpi_driver_data
(
device
);
if
(
!
ec
)
return
-
EINVAL
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"gpe=0x%02lx, ports=0x%2lx,0x%2lx"
,
ec
->
gpe
,
ec
->
command_addr
,
ec
->
data_addr
));
/* Boot EC is already working */
if
(
ec
==
boot_ec
)
return
0
;
return
ec_install_handlers
(
ec
);
}
static
int
acpi_ec_stop
(
struct
acpi_device
*
device
,
int
type
)
{
acpi_status
status
=
AE_OK
;
struct
acpi_ec
*
ec
=
NULL
;
acpi_status
status
;
struct
acpi_ec
*
ec
;
if
(
!
device
)
return
-
EINVAL
;
ec
=
acpi_driver_data
(
device
);
if
(
!
ec
)
return
-
EINVAL
;
/* Don't touch boot EC */
if
(
ec
==
boot_ec
)
return
0
;
status
=
acpi_remove_address_space_handler
(
ec
->
handle
,
ACPI_ADR_SPACE_EC
,
...
...
@@ -805,164 +772,67 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return
0
;
}
static
acpi_status
__init
acpi_fake_ecdt_callback
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
)
static
acpi_status
ec_parse_device
(
acpi_handle
handle
,
u32
Level
,
void
*
context
,
void
**
retval
)
{
acpi_status
status
;
mutex_init
(
&
ec_ecdt
->
lock
);
atomic_set
(
&
ec_ecdt
->
event_count
,
1
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
init_waitqueue_head
(
&
ec_ecdt
->
wait
);
}
struct
acpi_ec
*
ec
=
context
;
status
=
acpi_walk_resources
(
handle
,
METHOD_NAME__CRS
,
acpi_ec_io_ports
,
ec_ecdt
);
ec_parse_io_ports
,
ec
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
ec_ecdt
->
uid
=
-
1
;
acpi_evaluate_integer
(
handle
,
"_UID"
,
NULL
,
&
ec_ecdt
->
uid
);
status
=
acpi_evaluate_integer
(
handle
,
"_GPE"
,
NULL
,
&
ec_ecdt
->
gpe
);
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status
=
acpi_evaluate_integer
(
handle
,
"_GPE"
,
NULL
,
&
ec
->
gpe
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
ec_ecdt
->
global_lock
=
TRUE
;
ec_ecdt
->
handle
=
handle
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"GPE=0x%02lx, ports=0x%2lx, 0x%2lx"
,
ec_ecdt
->
gpe
,
ec_ecdt
->
command_addr
,
ec_ecdt
->
data_addr
));
return
AE_CTRL_TERMINATE
;
}
/*
* Some BIOS (such as some from Gateway laptops) access EC region very early
* such as in BAT0._INI or EC._INI before an EC device is found and
* do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
* required, but if EC regison is accessed early, it is required.
* The routine tries to workaround the BIOS bug by pre-scan EC device
* It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
* op region (since _REG isn't invoked yet). The assumption is true for
* all systems found.
*/
static
int
__init
acpi_ec_fake_ecdt
(
void
)
{
acpi_status
status
;
int
ret
=
0
;
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer
(
handle
,
"_GLK"
,
NULL
,
&
ec
->
global_lock
);
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Try to make an fake ECDT"
))
;
ec
->
handle
=
handle
;
ec_ecdt
=
kzalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec_ecdt
)
{
ret
=
-
ENOMEM
;
goto
error
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"GPE=0x%02lx, ports=0x%2lx, 0x%2lx"
,
ec
->
gpe
,
ec
->
command_addr
,
ec
->
data_addr
));
status
=
acpi_get_devices
(
ACPI_EC_HID
,
acpi_fake_ecdt_callback
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
{
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
ret
=
-
ENODEV
;
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Can't make an fake ECDT"
));
goto
error
;
}
return
0
;
error:
return
ret
;
return
AE_CTRL_TERMINATE
;
}
static
int
__init
acpi_ec_get_real_ecdt
(
void
)
int
__init
acpi_ec_ecdt_probe
(
void
)
{
int
ret
;
acpi_status
status
;
struct
acpi_table_ecdt
*
ecdt_ptr
;
status
=
acpi_get_table
(
ACPI_SIG_ECDT
,
1
,
(
struct
acpi_table_header
**
)
&
ecdt_ptr
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Found ECDT"
));
boot_ec
=
make_acpi_ec
();
if
(
!
boot_ec
)
return
-
ENOMEM
;
/*
* Generate a
temporary ec context to use until the namespace is scanned
* Generate a
boot ec context
*/
ec_ecdt
=
kzalloc
(
sizeof
(
struct
acpi_ec
),
GFP_KERNEL
);
if
(
!
ec_ecdt
)
return
-
ENOMEM
;
mutex_init
(
&
ec_ecdt
->
lock
);
atomic_set
(
&
ec_ecdt
->
event_count
,
1
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
init_waitqueue_head
(
&
ec_ecdt
->
wait
);
}
ec_ecdt
->
command_addr
=
ecdt_ptr
->
control
.
address
;
ec_ecdt
->
data_addr
=
ecdt_ptr
->
data
.
address
;
ec_ecdt
->
gpe
=
ecdt_ptr
->
gpe
;
/* use the GL just to be safe */
ec_ecdt
->
global_lock
=
TRUE
;
ec_ecdt
->
uid
=
ecdt_ptr
->
uid
;
status
=
acpi_get_handle
(
NULL
,
ecdt_ptr
->
id
,
&
ec_ecdt
->
handle
);
if
(
ACPI_FAILURE
(
status
))
{
status
=
acpi_get_table
(
ACPI_SIG_ECDT
,
1
,
(
struct
acpi_table_header
**
)
&
ecdt_ptr
);
if
(
ACPI_FAILURE
(
status
))
goto
error
;
}
return
0
;
error:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Could not use ECDT"
));
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
return
-
ENODEV
;
}
static
int
__initdata
acpi_fake_ecdt_enabled
;
int
__init
acpi_ec_ecdt_probe
(
void
)
{
acpi_status
status
;
int
ret
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Found ECDT"
));
ret
=
acpi_ec_get_real_ecdt
();
/* Try to make a fake ECDT */
if
(
ret
&&
acpi_fake_ecdt_enabled
)
{
ret
=
acpi_ec_fake_ecdt
();
}
boot_ec
->
command_addr
=
ecdt_ptr
->
control
.
address
;
boot_ec
->
data_addr
=
ecdt_ptr
->
data
.
address
;
boot_ec
->
gpe
=
ecdt_ptr
->
gpe
;
boot_ec
->
handle
=
ACPI_ROOT_OBJECT
;
if
(
ret
)
ret
=
ec_install_handlers
(
boot_ec
);
if
(
!
ret
)
{
first_ec
=
boot_ec
;
return
0
;
/*
* Install GPE handler
*/
status
=
acpi_install_gpe_handler
(
NULL
,
ec_ecdt
->
gpe
,
ACPI_GPE_EDGE_TRIGGERED
,
&
acpi_ec_gpe_handler
,
ec_ecdt
);
if
(
ACPI_FAILURE
(
status
))
{
goto
error
;
}
acpi_set_gpe_type
(
NULL
,
ec_ecdt
->
gpe
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec_ecdt
->
gpe
,
ACPI_NOT_ISR
);
status
=
acpi_install_address_space_handler
(
ACPI_ROOT_OBJECT
,
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
,
&
acpi_ec_space_setup
,
ec_ecdt
);
if
(
ACPI_FAILURE
(
status
))
{
acpi_remove_gpe_handler
(
NULL
,
ec_ecdt
->
gpe
,
&
acpi_ec_gpe_handler
);
goto
error
;
}
return
0
;
error:
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Could not use ECDT"
));
kfree
(
ec_ecdt
);
ec_ecdt
=
NULL
;
kfree
(
boot_ec
);
boot_ec
=
NULL
;
return
-
ENODEV
;
}
...
...
@@ -1003,13 +873,6 @@ static void __exit acpi_ec_exit(void)
}
#endif /* 0 */
static
int
__init
acpi_fake_ecdt_setup
(
char
*
str
)
{
acpi_fake_ecdt_enabled
=
1
;
return
1
;
}
__setup
(
"acpi_fake_ecdt"
,
acpi_fake_ecdt_setup
);
static
int
__init
acpi_ec_set_intr_mode
(
char
*
str
)
{
int
intr
;
...
...
@@ -1017,12 +880,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
if
(
!
get_option
(
&
str
,
&
intr
))
return
0
;
if
(
intr
)
{
acpi_ec_mode
=
EC_INTR
;
}
else
{
acpi_ec_mode
=
EC_POLL
;
}
acpi_ec_driver
.
ops
.
add
=
acpi_ec_add
;
acpi_ec_mode
=
(
intr
)
?
EC_INTR
:
EC_POLL
;
printk
(
KERN_NOTICE
PREFIX
"%s mode.
\n
"
,
intr
?
"interrupt"
:
"polling"
);
return
1
;
...
...
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