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
14f7d720
Commit
14f7d720
authored
Oct 29, 2007
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Pull alexey-fixes into release branch
parents
6a22c57b
5527c8be
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
237 additions
and
274 deletions
+237
-274
Documentation/kernel-parameters.txt
Documentation/kernel-parameters.txt
+0
-5
drivers/acpi/Kconfig
drivers/acpi/Kconfig
+5
-3
drivers/acpi/battery.c
drivers/acpi/battery.c
+95
-69
drivers/acpi/bus.c
drivers/acpi/bus.c
+3
-5
drivers/acpi/button.c
drivers/acpi/button.c
+29
-8
drivers/acpi/ec.c
drivers/acpi/ec.c
+70
-76
drivers/acpi/fan.c
drivers/acpi/fan.c
+7
-65
drivers/acpi/power.c
drivers/acpi/power.c
+24
-39
drivers/acpi/sleep/main.c
drivers/acpi/sleep/main.c
+3
-2
include/acpi/acpi_bus.h
include/acpi/acpi_bus.h
+1
-2
No files found.
Documentation/kernel-parameters.txt
View file @
14f7d720
...
...
@@ -586,11 +586,6 @@ and is between 256 and 4096 characters. It is defined in the file
eata= [HW,SCSI]
ec_intr= [HW,ACPI] ACPI Embedded Controller interrupt mode
Format: <int>
0: polling mode
non-0: interrupt mode (default)
edd= [EDD]
Format: {"of[f]" | "sk[ipmbr]"}
See comment in arch/i386/boot/edd.S
...
...
drivers/acpi/Kconfig
View file @
14f7d720
...
...
@@ -88,7 +88,8 @@ config ACPI_PROC_EVENT
config ACPI_AC
tristate "AC Adapter"
depends on X86 && POWER_SUPPLY
depends on X86
select POWER_SUPPLY
default y
help
This driver adds support for the AC Adapter object, which indicates
...
...
@@ -97,7 +98,8 @@ config ACPI_AC
config ACPI_BATTERY
tristate "Battery"
depends on X86 && POWER_SUPPLY
depends on X86
select POWER_SUPPLY
default y
help
This driver adds support for battery information through
...
...
@@ -352,7 +354,7 @@ config ACPI_HOTPLUG_MEMORY
config ACPI_SBS
tristate "Smart Battery System"
depends on X86
depends on
POWER_SUPPLY
select
POWER_SUPPLY
help
This driver adds support for the Smart Battery System, another
type of access to battery information, found on some laptops.
...
...
drivers/acpi/battery.c
View file @
14f7d720
...
...
@@ -125,11 +125,15 @@ static int acpi_battery_technology(struct acpi_battery *battery)
return
POWER_SUPPLY_TECHNOLOGY_NiMH
;
if
(
!
strcasecmp
(
"LION"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_LION
;
if
(
!
strcasecmp
(
"LI-ION"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_LION
;
if
(
!
strcasecmp
(
"LiP"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_LIPO
;
return
POWER_SUPPLY_TECHNOLOGY_UNKNOWN
;
}
static
int
acpi_battery_update
(
struct
acpi_battery
*
battery
);
static
int
acpi_battery_get_property
(
struct
power_supply
*
psy
,
enum
power_supply_property
psp
,
union
power_supply_propval
*
val
)
...
...
@@ -139,6 +143,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
if
((
!
acpi_battery_present
(
battery
))
&&
psp
!=
POWER_SUPPLY_PROP_PRESENT
)
return
-
ENODEV
;
acpi_battery_update
(
battery
);
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_STATUS
:
if
(
battery
->
state
&
0x01
)
...
...
@@ -257,7 +262,7 @@ static int extract_package(struct acpi_battery *battery,
union
acpi_object
*
package
,
struct
acpi_offsets
*
offsets
,
int
num
)
{
int
i
,
*
x
;
int
i
;
union
acpi_object
*
element
;
if
(
package
->
type
!=
ACPI_TYPE_PACKAGE
)
return
-
EFAULT
;
...
...
@@ -266,16 +271,21 @@ static int extract_package(struct acpi_battery *battery,
return
-
EFAULT
;
element
=
&
package
->
package
.
elements
[
i
];
if
(
offsets
[
i
].
mode
)
{
if
(
element
->
type
!=
ACPI_TYPE_STRING
&&
element
->
type
!=
ACPI_TYPE_BUFFER
)
return
-
EFAULT
;
strncpy
((
u8
*
)
battery
+
offsets
[
i
].
offset
,
element
->
string
.
pointer
,
32
);
u8
*
ptr
=
(
u8
*
)
battery
+
offsets
[
i
].
offset
;
if
(
element
->
type
==
ACPI_TYPE_STRING
||
element
->
type
==
ACPI_TYPE_BUFFER
)
strncpy
(
ptr
,
element
->
string
.
pointer
,
32
);
else
if
(
element
->
type
==
ACPI_TYPE_INTEGER
)
{
strncpy
(
ptr
,
(
u8
*
)
&
element
->
integer
.
value
,
sizeof
(
acpi_integer
));
ptr
[
sizeof
(
acpi_integer
)]
=
0
;
}
else
return
-
EFAULT
;
}
else
{
if
(
element
->
type
!=
ACPI_TYPE_INTEGER
)
return
-
EFAULT
;
x
=
(
int
*
)((
u8
*
)
battery
+
offsets
[
i
].
offset
);
if
(
element
->
type
==
ACPI_TYPE_INTEGER
)
{
int
*
x
=
(
int
*
)((
u8
*
)
battery
+
offsets
[
i
].
offset
);
*
x
=
element
->
integer
.
value
;
}
else
return
-
EFAULT
;
}
}
return
0
;
...
...
@@ -385,16 +395,40 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
return
acpi_battery_set_alarm
(
battery
);
}
static
int
acpi_battery_update
(
struct
acpi_battery
*
battery
)
static
ssize_t
acpi_battery_alarm_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
int
saved_present
=
acpi_battery_present
(
battery
);
int
result
=
acpi_battery_get_status
(
battery
);
if
(
result
||
!
acpi_battery_present
(
battery
))
return
result
;
if
(
saved_present
!=
acpi_battery_present
(
battery
)
||
!
battery
->
update_time
)
{
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
return
sprintf
(
buf
,
"%d
\n
"
,
battery
->
alarm
*
1000
);
}
static
ssize_t
acpi_battery_alarm_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
x
;
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
if
(
sscanf
(
buf
,
"%ld
\n
"
,
&
x
)
==
1
)
battery
->
alarm
=
x
/
1000
;
if
(
acpi_battery_present
(
battery
))
acpi_battery_set_alarm
(
battery
);
return
count
;
}
static
struct
device_attribute
alarm_attr
=
{
.
attr
=
{.
name
=
"alarm"
,
.
mode
=
0644
,
.
owner
=
THIS_MODULE
},
.
show
=
acpi_battery_alarm_show
,
.
store
=
acpi_battery_alarm_store
,
};
static
int
sysfs_add_battery
(
struct
acpi_battery
*
battery
)
{
int
result
;
battery
->
update_time
=
0
;
result
=
acpi_battery_get_info
(
battery
);
acpi_battery_init_alarm
(
battery
);
if
(
result
)
return
result
;
if
(
battery
->
power_unit
)
{
...
...
@@ -406,8 +440,36 @@ static int acpi_battery_update(struct acpi_battery *battery)
battery
->
bat
.
num_properties
=
ARRAY_SIZE
(
energy_battery_props
);
}
acpi_battery_init_alarm
(
battery
);
battery
->
bat
.
name
=
acpi_device_bid
(
battery
->
device
);
battery
->
bat
.
type
=
POWER_SUPPLY_TYPE_BATTERY
;
battery
->
bat
.
get_property
=
acpi_battery_get_property
;
result
=
power_supply_register
(
&
battery
->
device
->
dev
,
&
battery
->
bat
);
if
(
result
)
return
result
;
return
device_create_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
}
static
void
sysfs_remove_battery
(
struct
acpi_battery
*
battery
)
{
if
(
!
battery
->
bat
.
dev
)
return
;
device_remove_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
power_supply_unregister
(
&
battery
->
bat
);
}
static
int
acpi_battery_update
(
struct
acpi_battery
*
battery
)
{
int
result
=
acpi_battery_get_status
(
battery
);
if
(
result
)
return
result
;
if
(
!
acpi_battery_present
(
battery
))
{
sysfs_remove_battery
(
battery
);
return
0
;
}
if
(
!
battery
->
bat
.
dev
)
sysfs_add_battery
(
battery
);
return
acpi_battery_get_state
(
battery
);
}
...
...
@@ -554,10 +616,6 @@ static ssize_t acpi_battery_write_alarm(struct file *file,
if
(
!
battery
||
(
count
>
sizeof
(
alarm_string
)
-
1
))
return
-
EINVAL
;
if
(
result
)
{
result
=
-
ENODEV
;
goto
end
;
}
if
(
!
acpi_battery_present
(
battery
))
{
result
=
-
ENODEV
;
goto
end
;
...
...
@@ -688,33 +746,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
#endif
static
ssize_t
acpi_battery_alarm_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
return
sprintf
(
buf
,
"%d
\n
"
,
battery
->
alarm
*
1000
);
}
static
ssize_t
acpi_battery_alarm_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
x
;
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
if
(
sscanf
(
buf
,
"%ld
\n
"
,
&
x
)
==
1
)
battery
->
alarm
=
x
/
1000
;
if
(
acpi_battery_present
(
battery
))
acpi_battery_set_alarm
(
battery
);
return
count
;
}
static
struct
device_attribute
alarm_attr
=
{
.
attr
=
{.
name
=
"alarm"
,
.
mode
=
0644
,
.
owner
=
THIS_MODULE
},
.
show
=
acpi_battery_alarm_show
,
.
store
=
acpi_battery_alarm_store
,
};
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
...
...
@@ -732,6 +763,8 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
acpi_bus_generate_netlink_event
(
device
->
pnp
.
device_class
,
device
->
dev
.
bus_id
,
event
,
acpi_battery_present
(
battery
));
/* acpi_batter_update could remove power_supply object */
if
(
battery
->
bat
.
dev
)
kobject_uevent
(
&
battery
->
bat
.
dev
->
kobj
,
KOBJ_CHANGE
);
}
...
...
@@ -756,11 +789,6 @@ static int acpi_battery_add(struct acpi_device *device)
if
(
result
)
goto
end
;
#endif
battery
->
bat
.
name
=
acpi_device_bid
(
device
);
battery
->
bat
.
type
=
POWER_SUPPLY_TYPE_BATTERY
;
battery
->
bat
.
get_property
=
acpi_battery_get_property
;
result
=
power_supply_register
(
&
battery
->
device
->
dev
,
&
battery
->
bat
);
result
=
device_create_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
status
=
acpi_install_notify_handler
(
device
->
handle
,
ACPI_ALL_NOTIFY
,
acpi_battery_notify
,
battery
);
...
...
@@ -796,10 +824,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
#ifdef CONFIG_ACPI_PROCFS
acpi_battery_remove_fs
(
device
);
#endif
if
(
battery
->
bat
.
dev
)
{
device_remove_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
power_supply_unregister
(
&
battery
->
bat
);
}
sysfs_remove_battery
(
battery
);
mutex_destroy
(
&
battery
->
lock
);
kfree
(
battery
);
return
0
;
...
...
@@ -813,6 +838,7 @@ static int acpi_battery_resume(struct acpi_device *device)
return
-
EINVAL
;
battery
=
acpi_driver_data
(
device
);
battery
->
update_time
=
0
;
acpi_battery_update
(
battery
);
return
0
;
}
...
...
drivers/acpi/bus.c
View file @
14f7d720
...
...
@@ -198,12 +198,10 @@ int acpi_bus_set_power(acpi_handle handle, int state)
return
-
ENODEV
;
}
/*
* Get device's current power state if it's unknown
* This means device power state isn't initialized or previous setting failed
* Get device's current power state
*/
if
((
device
->
power
.
state
==
ACPI_STATE_UNKNOWN
)
||
device
->
flags
.
force_power_state
)
acpi_bus_get_power
(
device
->
handle
,
&
device
->
power
.
state
);
if
(
(
state
==
device
->
power
.
state
)
&&
!
device
->
flags
.
force_power_
state
)
{
if
(
state
==
device
->
power
.
state
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Device is already at D%d
\n
"
,
state
));
return
0
;
...
...
drivers/acpi/button.c
View file @
14f7d720
...
...
@@ -78,6 +78,7 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids);
static
int
acpi_button_add
(
struct
acpi_device
*
device
);
static
int
acpi_button_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_button_resume
(
struct
acpi_device
*
device
);
static
int
acpi_button_info_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
);
static
int
acpi_button_state_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
);
...
...
@@ -87,6 +88,7 @@ static struct acpi_driver acpi_button_driver = {
.
ids
=
button_device_ids
,
.
ops
=
{
.
add
=
acpi_button_add
,
.
resume
=
acpi_button_resume
,
.
remove
=
acpi_button_remove
,
},
};
...
...
@@ -253,6 +255,19 @@ static int acpi_button_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static
int
acpi_lid_send_state
(
struct
acpi_button
*
button
)
{
unsigned
long
state
;
acpi_status
status
;
status
=
acpi_evaluate_integer
(
button
->
device
->
handle
,
"_LID"
,
NULL
,
&
state
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
/* input layer checks if event is redundant */
input_report_switch
(
button
->
input
,
SW_LID
,
!
state
);
return
0
;
}
static
void
acpi_button_notify
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
{
...
...
@@ -265,15 +280,8 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
switch
(
event
)
{
case
ACPI_BUTTON_NOTIFY_STATUS
:
input
=
button
->
input
;
if
(
button
->
type
==
ACPI_BUTTON_TYPE_LID
)
{
struct
acpi_handle
*
handle
=
button
->
device
->
handle
;
unsigned
long
state
;
if
(
!
ACPI_FAILURE
(
acpi_evaluate_integer
(
handle
,
"_LID"
,
NULL
,
&
state
)))
input_report_switch
(
input
,
SW_LID
,
!
state
);
acpi_lid_send_state
(
button
);
}
else
{
int
keycode
=
test_bit
(
KEY_SLEEP
,
input
->
keybit
)
?
KEY_SLEEP
:
KEY_POWER
;
...
...
@@ -336,6 +344,17 @@ static int acpi_button_install_notify_handlers(struct acpi_button *button)
return
ACPI_FAILURE
(
status
)
?
-
ENODEV
:
0
;
}
static
int
acpi_button_resume
(
struct
acpi_device
*
device
)
{
struct
acpi_button
*
button
;
if
(
!
device
)
return
-
EINVAL
;
button
=
acpi_driver_data
(
device
);
if
(
button
&&
button
->
type
==
ACPI_BUTTON_TYPE_LID
)
return
acpi_lid_send_state
(
button
);
return
0
;
}
static
void
acpi_button_remove_notify_handlers
(
struct
acpi_button
*
button
)
{
switch
(
button
->
type
)
{
...
...
@@ -453,6 +472,8 @@ static int acpi_button_add(struct acpi_device *device)
error
=
input_register_device
(
input
);
if
(
error
)
goto
err_remove_handlers
;
if
(
button
->
type
==
ACPI_BUTTON_TYPE_LID
)
acpi_lid_send_state
(
button
);
if
(
device
->
wakeup
.
flags
.
valid
)
{
/* Button's GPE is run-wake GPE */
...
...
drivers/acpi/ec.c
View file @
14f7d720
...
...
@@ -71,10 +71,12 @@ enum ec_event {
#define ACPI_EC_DELAY 500
/* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000
/* Wait 1ms max. to get global lock */
static
enum
ec_mode
{
EC_INTR
=
1
,
/* Output buffer full */
EC_POLL
,
/* Input buffer empty */
}
acpi_ec_mode
=
EC_INTR
;
enum
{
EC_FLAGS_WAIT_GPE
=
0
,
/* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING
,
/* Query is pending */
EC_FLAGS_GPE_MODE
,
/* Expect GPE to be sent for status change */
EC_FLAGS_ONLY_IBF_GPE
,
/* Expect GPE only for IBF = 0 event */
};
static
int
acpi_ec_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_ec_start
(
struct
acpi_device
*
device
);
...
...
@@ -116,9 +118,8 @@ static struct acpi_ec {
unsigned
long
command_addr
;
unsigned
long
data_addr
;
unsigned
long
global_lock
;
unsigned
long
flags
;
struct
mutex
lock
;
atomic_t
query_pending
;
atomic_t
event_count
;
wait_queue_head_t
wait
;
struct
list_head
list
;
u8
handlers_installed
;
...
...
@@ -148,45 +149,54 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb
(
data
,
ec
->
data_addr
);
}
static
inline
int
acpi_ec_check_status
(
struct
acpi_ec
*
ec
,
enum
ec_event
event
,
unsigned
old_count
)
static
inline
int
acpi_ec_check_status
(
struct
acpi_ec
*
ec
,
enum
ec_event
event
)
{
u8
status
=
acpi_ec_read_status
(
ec
);
if
(
old_count
==
atomic_read
(
&
ec
->
event_count
))
if
(
test_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
))
return
0
;
if
(
event
==
ACPI_EC_EVENT_OBF_1
)
{
if
(
status
&
ACPI_EC_FLAG_OBF
)
if
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_OBF
)
return
1
;
}
else
if
(
event
==
ACPI_EC_EVENT_IBF_0
)
{
if
(
!
(
status
&
ACPI_EC_FLAG_IBF
))
if
(
!
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_IBF
))
return
1
;
}
return
0
;
}
static
int
acpi_ec_wait
(
struct
acpi_ec
*
ec
,
enum
ec_event
event
,
unsigned
count
,
int
force_poll
)
static
int
acpi_ec_wait
(
struct
acpi_ec
*
ec
,
enum
ec_event
event
,
int
force_poll
)
{
if
(
unlikely
(
force_poll
)
||
acpi_ec_mode
==
EC_POLL
)
{
unsigned
long
delay
=
jiffies
+
msecs_to_jiffies
(
ACPI_EC_DELAY
);
while
(
time_before
(
jiffies
,
delay
))
{
if
(
acpi_ec_check_status
(
ec
,
event
,
0
))
if
(
likely
(
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
))
&&
likely
(
!
force_poll
))
{
if
(
wait_event_timeout
(
ec
->
wait
,
acpi_ec_check_status
(
ec
,
event
),
msecs_to_jiffies
(
ACPI_EC_DELAY
)
))
return
0
;
}
clear_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
if
(
acpi_ec_check_status
(
ec
,
event
))
{
if
(
event
==
ACPI_EC_EVENT_OBF_1
)
{
/* miss OBF = 1 GPE, don't expect it anymore */
printk
(
KERN_INFO
PREFIX
"missing OBF_1 confirmation,"
"switching to degraded mode.
\n
"
);
set_bit
(
EC_FLAGS_ONLY_IBF_GPE
,
&
ec
->
flags
);
}
else
{
if
(
wait_event_timeout
(
ec
->
wait
,
acpi_ec_check_status
(
ec
,
event
,
count
),
msecs_to_jiffies
(
ACPI_EC_DELAY
))
||
acpi_ec_check_status
(
ec
,
event
,
0
))
{
/* missing GPEs, switch back to poll mode */
printk
(
KERN_INFO
PREFIX
"missing IBF_1 confirmations,"
"switch off interrupt mode.
\n
"
);
clear_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
}
return
0
;
}
}
else
{
unsigned
long
delay
=
jiffies
+
msecs_to_jiffies
(
ACPI_EC_DELAY
);
clear_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
while
(
time_before
(
jiffies
,
delay
))
{
if
(
acpi_ec_check_status
(
ec
,
event
))
return
0
;
}
}
printk
(
KERN_ERR
PREFIX
"acpi_ec_wait timeout,"
" status = %d, expect_event = %d
\n
"
,
acpi_ec_read_status
(
ec
),
event
);
}
}
return
-
ETIME
;
}
...
...
@@ -196,39 +206,42 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
int
force_poll
)
{
int
result
=
0
;
unsigned
count
=
atomic_read
(
&
ec
->
event_count
);
set_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
acpi_ec_write_cmd
(
ec
,
command
);
for
(;
wdata_len
>
0
;
--
wdata_len
)
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
count
,
force_poll
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
force_poll
);
if
(
result
)
{
printk
(
KERN_ERR
PREFIX
"write_cmd timeout, command = %d
\n
"
,
command
);
goto
end
;
}
count
=
atomic_read
(
&
ec
->
event_count
);
set_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
acpi_ec_write_data
(
ec
,
*
(
wdata
++
));
}
if
(
!
rdata_len
)
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
count
,
force_poll
);
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
force_poll
);
if
(
result
)
{
printk
(
KERN_ERR
PREFIX
"finish-write timeout, command = %d
\n
"
,
command
);
goto
end
;
}
}
else
if
(
command
==
ACPI_EC_COMMAND_QUERY
)
{
atomic_set
(
&
ec
->
query_pending
,
0
);
}
}
else
if
(
command
==
ACPI_EC_COMMAND_QUERY
)
clear_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
);
for
(;
rdata_len
>
0
;
--
rdata_len
)
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF_1
,
count
,
force_poll
);
if
(
test_bit
(
EC_FLAGS_ONLY_IBF_GPE
,
&
ec
->
flags
))
force_poll
=
1
;
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF_1
,
force_poll
);
if
(
result
)
{
printk
(
KERN_ERR
PREFIX
"read timeout, command = %d
\n
"
,
command
);
goto
end
;
}
count
=
atomic_read
(
&
ec
->
event_count
);
/* Don't expect GPE after last read */
if
(
rdata_len
>
1
)
set_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
*
(
rdata
++
)
=
acpi_ec_read_data
(
ec
);
}
end:
...
...
@@ -258,10 +271,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
}
}
/* Make sure GPE is enabled before doing transaction */
acpi_enable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
0
,
0
);
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
0
);
if
(
status
)
{
printk
(
KERN_ERR
PREFIX
"input buffer is not empty, aborting transaction
\n
"
);
...
...
@@ -435,9 +445,9 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
void
acpi_ec_remove_query_handler
(
struct
acpi_ec
*
ec
,
u8
query_bit
)
{
struct
acpi_ec_query_handler
*
handler
;
struct
acpi_ec_query_handler
*
handler
,
*
tmp
;
mutex_lock
(
&
ec
->
lock
);
list_for_each_entry
(
handler
,
&
ec
->
list
,
node
)
{
list_for_each_entry
_safe
(
handler
,
tmp
,
&
ec
->
list
,
node
)
{
if
(
query_bit
==
handler
->
query_bit
)
{
list_del
(
&
handler
->
node
);
kfree
(
handler
);
...
...
@@ -476,23 +486,24 @@ static void acpi_ec_gpe_query(void *ec_cxt)
static
u32
acpi_ec_gpe_handler
(
void
*
data
)
{
acpi_status
status
=
AE_OK
;
u8
value
;
struct
acpi_ec
*
ec
=
data
;
atomic_inc
(
&
ec
->
event_count
);
if
(
acpi_ec_mode
==
EC_INTR
)
{
clear_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
if
(
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
))
wake_up
(
&
ec
->
wait
);
}
value
=
acpi_ec_read_status
(
ec
);
if
((
value
&
ACPI_EC_FLAG_SCI
)
&&
!
atomic_read
(
&
ec
->
query_pending
))
{
atomic_set
(
&
ec
->
query_pending
,
1
);
status
=
acpi_os_execute
(
OSL_EC_BURST_HANDLER
,
acpi_ec_gpe_query
,
ec
);
if
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_SCI
)
{
if
(
!
test_and_set_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
))
status
=
acpi_os_execute
(
OSL_EC_BURST_HANDLER
,
acpi_ec_gpe_query
,
ec
);
}
else
if
(
unlikely
(
!
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
)))
{
/* this is non-query, must be confirmation */
printk
(
KERN_INFO
PREFIX
"non-query interrupt received,"
" switching to interrupt mode
\n
"
);
set_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
}
return
status
==
AE_OK
?
return
ACPI_SUCCESS
(
status
)
?
ACPI_INTERRUPT_HANDLED
:
ACPI_INTERRUPT_NOT_HANDLED
;
}
...
...
@@ -641,13 +652,10 @@ 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
);
ec
->
flags
=
1
<<
EC_FLAGS_QUERY_PENDING
;
mutex_init
(
&
ec
->
lock
);
init_waitqueue_head
(
&
ec
->
wait
);
INIT_LIST_HEAD
(
&
ec
->
list
);
return
ec
;
}
...
...
@@ -741,6 +749,8 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_ec_add_fs
(
device
);
printk
(
KERN_INFO
PREFIX
"GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx
\n
"
,
ec
->
gpe
,
ec
->
command_addr
,
ec
->
data_addr
);
printk
(
KERN_INFO
PREFIX
"driver started in %s mode
\n
"
,
(
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
))
?
"interrupt"
:
"poll"
);
return
0
;
}
...
...
@@ -833,7 +843,7 @@ static int acpi_ec_start(struct acpi_device *device)
ret
=
ec_install_handlers
(
ec
);
/* EC is fully operational, allow queries */
atomic_set
(
&
ec
->
query_pending
,
0
);
clear_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
);
return
ret
;
}
...
...
@@ -925,19 +935,3 @@ static void __exit acpi_ec_exit(void)
return;
}
#endif /* 0 */
static
int
__init
acpi_ec_set_intr_mode
(
char
*
str
)
{
int
intr
;
if
(
!
get_option
(
&
str
,
&
intr
))
return
0
;
acpi_ec_mode
=
(
intr
)
?
EC_INTR
:
EC_POLL
;
printk
(
KERN_NOTICE
PREFIX
"%s mode.
\n
"
,
intr
?
"interrupt"
:
"polling"
);
return
1
;
}
__setup
(
"ec_intr="
,
acpi_ec_set_intr_mode
);
drivers/acpi/fan.c
View file @
14f7d720
...
...
@@ -47,8 +47,6 @@ MODULE_LICENSE("GPL");
static
int
acpi_fan_add
(
struct
acpi_device
*
device
);
static
int
acpi_fan_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_fan_suspend
(
struct
acpi_device
*
device
,
pm_message_t
state
);
static
int
acpi_fan_resume
(
struct
acpi_device
*
device
);
static
const
struct
acpi_device_id
fan_device_ids
[]
=
{
{
"PNP0C0B"
,
0
},
...
...
@@ -63,15 +61,9 @@ static struct acpi_driver acpi_fan_driver = {
.
ops
=
{
.
add
=
acpi_fan_add
,
.
remove
=
acpi_fan_remove
,
.
suspend
=
acpi_fan_suspend
,
.
resume
=
acpi_fan_resume
,
},
};
struct
acpi_fan
{
struct
acpi_device
*
device
;
};
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
...
...
@@ -80,12 +72,12 @@ static struct proc_dir_entry *acpi_fan_dir;
static
int
acpi_fan_read_state
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_
fan
*
fan
=
seq
->
private
;
struct
acpi_
device
*
device
=
seq
->
private
;
int
state
=
0
;
if
(
fan
)
{
if
(
acpi_bus_get_power
(
fan
->
device
->
handle
,
&
state
))
if
(
device
)
{
if
(
acpi_bus_get_power
(
device
->
handle
,
&
state
))
seq_printf
(
seq
,
"status: ERROR
\n
"
);
else
seq_printf
(
seq
,
"status: %s
\n
"
,
...
...
@@ -105,11 +97,10 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
{
int
result
=
0
;
struct
seq_file
*
m
=
file
->
private_data
;
struct
acpi_
fan
*
fan
=
m
->
private
;
struct
acpi_
device
*
device
=
m
->
private
;
char
state_string
[
12
]
=
{
'\0'
};
if
(
!
fan
||
(
count
>
sizeof
(
state_string
)
-
1
))
if
(
count
>
sizeof
(
state_string
)
-
1
)
return
-
EINVAL
;
if
(
copy_from_user
(
state_string
,
buffer
,
count
))
...
...
@@ -117,7 +108,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
state_string
[
count
]
=
'\0'
;
result
=
acpi_bus_set_power
(
fan
->
device
->
handle
,
result
=
acpi_bus_set_power
(
device
->
handle
,
simple_strtoul
(
state_string
,
NULL
,
0
));
if
(
result
)
return
result
;
...
...
@@ -158,7 +149,7 @@ static int acpi_fan_add_fs(struct acpi_device *device)
return
-
ENODEV
;
else
{
entry
->
proc_fops
=
&
acpi_fan_state_ops
;
entry
->
data
=
acpi_driver_data
(
device
)
;
entry
->
data
=
device
;
entry
->
owner
=
THIS_MODULE
;
}
...
...
@@ -191,14 +182,8 @@ static int acpi_fan_add(struct acpi_device *device)
if
(
!
device
)
return
-
EINVAL
;
fan
=
kzalloc
(
sizeof
(
struct
acpi_fan
),
GFP_KERNEL
);
if
(
!
fan
)
return
-
ENOMEM
;
fan
->
device
=
device
;
strcpy
(
acpi_device_name
(
device
),
"Fan"
);
strcpy
(
acpi_device_class
(
device
),
ACPI_FAN_CLASS
);
acpi_driver_data
(
device
)
=
fan
;
result
=
acpi_bus_get_power
(
device
->
handle
,
&
state
);
if
(
result
)
{
...
...
@@ -206,10 +191,6 @@ static int acpi_fan_add(struct acpi_device *device)
goto
end
;
}
device
->
flags
.
force_power_state
=
1
;
acpi_bus_set_power
(
device
->
handle
,
state
);
device
->
flags
.
force_power_state
=
0
;
result
=
acpi_fan_add_fs
(
device
);
if
(
result
)
goto
end
;
...
...
@@ -227,53 +208,14 @@ static int acpi_fan_add(struct acpi_device *device)
static
int
acpi_fan_remove
(
struct
acpi_device
*
device
,
int
type
)
{
struct
acpi_fan
*
fan
=
NULL
;
if
(
!
device
||
!
acpi_driver_data
(
device
))
return
-
EINVAL
;
fan
=
acpi_driver_data
(
device
);
acpi_fan_remove_fs
(
device
);
kfree
(
fan
);
return
0
;
}
static
int
acpi_fan_suspend
(
struct
acpi_device
*
device
,
pm_message_t
state
)
{
if
(
!
device
)
return
-
EINVAL
;
acpi_bus_set_power
(
device
->
handle
,
ACPI_STATE_D0
);
return
AE_OK
;
}
static
int
acpi_fan_resume
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
int
power_state
=
0
;
if
(
!
device
)
return
-
EINVAL
;
result
=
acpi_bus_get_power
(
device
->
handle
,
&
power_state
);
if
(
result
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_ERROR
,
"Error reading fan power state
\n
"
));
return
result
;
}
device
->
flags
.
force_power_state
=
1
;
acpi_bus_set_power
(
device
->
handle
,
power_state
);
device
->
flags
.
force_power_state
=
0
;
return
result
;
}
static
int
__init
acpi_fan_init
(
void
)
{
int
result
=
0
;
...
...
drivers/acpi/power.c
View file @
14f7d720
...
...
@@ -86,7 +86,6 @@ struct acpi_power_resource {
acpi_bus_id
name
;
u32
system_level
;
u32
order
;
int
state
;
struct
mutex
resource_lock
;
struct
list_head
reference
;
};
...
...
@@ -128,33 +127,31 @@ acpi_power_get_context(acpi_handle handle,
return
0
;
}
static
int
acpi_power_get_state
(
struct
acpi_power_resource
*
resource
)
static
int
acpi_power_get_state
(
struct
acpi_power_resource
*
resource
,
int
*
state
)
{
acpi_status
status
=
AE_OK
;
unsigned
long
sta
=
0
;
if
(
!
resource
)
if
(
!
resource
||
!
state
)
return
-
EINVAL
;
status
=
acpi_evaluate_integer
(
resource
->
device
->
handle
,
"_STA"
,
NULL
,
&
sta
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
if
(
sta
&
0x01
)
resource
->
state
=
ACPI_POWER_RESOURCE_STATE_ON
;
else
resource
->
state
=
ACPI_POWER_RESOURCE_STATE_OFF
;
*
state
=
(
sta
&
0x01
)
?
ACPI_POWER_RESOURCE_STATE_ON
:
ACPI_POWER_RESOURCE_STATE_OFF
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Resource [%s] is %s
\n
"
,
resource
->
name
,
resource
->
state
?
"on"
:
"off"
));
resource
->
name
,
state
?
"on"
:
"off"
));
return
0
;
}
static
int
acpi_power_get_list_state
(
struct
acpi_handle_list
*
list
,
int
*
state
)
{
int
result
=
0
;
int
result
=
0
,
state1
;
struct
acpi_power_resource
*
resource
=
NULL
;
u32
i
=
0
;
...
...
@@ -168,11 +165,11 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
result
=
acpi_power_get_context
(
list
->
handles
[
i
],
&
resource
);
if
(
result
)
return
result
;
result
=
acpi_power_get_state
(
resource
);
result
=
acpi_power_get_state
(
resource
,
&
state1
);
if
(
result
)
return
result
;
*
state
=
resource
->
state
;
*
state
=
state1
;
if
(
*
state
!=
ACPI_POWER_RESOURCE_STATE_ON
)
break
;
...
...
@@ -186,7 +183,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
static
int
acpi_power_on
(
acpi_handle
handle
,
struct
acpi_device
*
dev
)
{
int
result
=
0
;
int
result
=
0
,
state
;
int
found
=
0
;
acpi_status
status
=
AE_OK
;
struct
acpi_power_resource
*
resource
=
NULL
;
...
...
@@ -224,20 +221,14 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
}
mutex_unlock
(
&
resource
->
resource_lock
);
if
(
resource
->
state
==
ACPI_POWER_RESOURCE_STATE_ON
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Resource [%s] already on
\n
"
,
resource
->
name
));
return
0
;
}
status
=
acpi_evaluate_object
(
resource
->
device
->
handle
,
"_ON"
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
result
=
acpi_power_get_state
(
resource
);
result
=
acpi_power_get_state
(
resource
,
&
state
);
if
(
result
)
return
result
;
if
(
resource
->
state
!=
ACPI_POWER_RESOURCE_STATE_ON
)
if
(
state
!=
ACPI_POWER_RESOURCE_STATE_ON
)
return
-
ENOEXEC
;
/* Update the power resource's _device_ power state */
...
...
@@ -250,7 +241,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
static
int
acpi_power_off_device
(
acpi_handle
handle
,
struct
acpi_device
*
dev
)
{
int
result
=
0
;
int
result
=
0
,
state
;
acpi_status
status
=
AE_OK
;
struct
acpi_power_resource
*
resource
=
NULL
;
struct
list_head
*
node
,
*
next
;
...
...
@@ -281,20 +272,14 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
}
mutex_unlock
(
&
resource
->
resource_lock
);
if
(
resource
->
state
==
ACPI_POWER_RESOURCE_STATE_OFF
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Resource [%s] already off
\n
"
,
resource
->
name
));
return
0
;
}
status
=
acpi_evaluate_object
(
resource
->
device
->
handle
,
"_OFF"
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
result
=
acpi_power_get_state
(
resource
);
result
=
acpi_power_get_state
(
resource
,
&
state
);
if
(
result
)
return
result
;
if
(
resource
->
state
!=
ACPI_POWER_RESOURCE_STATE_OFF
)
if
(
state
!=
ACPI_POWER_RESOURCE_STATE_OFF
)
return
-
ENOEXEC
;
/* Update the power resource's _device_ power state */
...
...
@@ -494,7 +479,7 @@ static struct proc_dir_entry *acpi_power_dir;
static
int
acpi_power_seq_show
(
struct
seq_file
*
seq
,
void
*
offset
)
{
int
count
=
0
;
int
result
=
0
;
int
result
=
0
,
state
;
struct
acpi_power_resource
*
resource
=
NULL
;
struct
list_head
*
node
,
*
next
;
struct
acpi_power_reference
*
ref
;
...
...
@@ -505,12 +490,12 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
if
(
!
resource
)
goto
end
;
result
=
acpi_power_get_state
(
resource
);
result
=
acpi_power_get_state
(
resource
,
&
state
);
if
(
result
)
goto
end
;
seq_puts
(
seq
,
"state: "
);
switch
(
resource
->
state
)
{
switch
(
state
)
{
case
ACPI_POWER_RESOURCE_STATE_ON
:
seq_puts
(
seq
,
"on
\n
"
);
break
;
...
...
@@ -591,7 +576,7 @@ static int acpi_power_remove_fs(struct acpi_device *device)
static
int
acpi_power_add
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
int
result
=
0
,
state
;
acpi_status
status
=
AE_OK
;
struct
acpi_power_resource
*
resource
=
NULL
;
union
acpi_object
acpi_object
;
...
...
@@ -622,11 +607,11 @@ static int acpi_power_add(struct acpi_device *device)
resource
->
system_level
=
acpi_object
.
power_resource
.
system_level
;
resource
->
order
=
acpi_object
.
power_resource
.
resource_order
;
result
=
acpi_power_get_state
(
resource
);
result
=
acpi_power_get_state
(
resource
,
&
state
);
if
(
result
)
goto
end
;
switch
(
resource
->
state
)
{
switch
(
state
)
{
case
ACPI_POWER_RESOURCE_STATE_ON
:
device
->
power
.
state
=
ACPI_STATE_D0
;
break
;
...
...
@@ -643,7 +628,7 @@ static int acpi_power_add(struct acpi_device *device)
goto
end
;
printk
(
KERN_INFO
PREFIX
"%s [%s] (%s)
\n
"
,
acpi_device_name
(
device
),
acpi_device_bid
(
device
),
resource
->
state
?
"on"
:
"off"
);
acpi_device_bid
(
device
),
state
?
"on"
:
"off"
);
end:
if
(
result
)
...
...
@@ -680,7 +665,7 @@ static int acpi_power_remove(struct acpi_device *device, int type)
static
int
acpi_power_resume
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
int
result
=
0
,
state
;
struct
acpi_power_resource
*
resource
=
NULL
;
struct
acpi_power_reference
*
ref
;
...
...
@@ -689,12 +674,12 @@ static int acpi_power_resume(struct acpi_device *device)
resource
=
(
struct
acpi_power_resource
*
)
acpi_driver_data
(
device
);
result
=
acpi_power_get_state
(
resource
);
result
=
acpi_power_get_state
(
resource
,
&
state
);
if
(
result
)
return
result
;
mutex_lock
(
&
resource
->
resource_lock
);
if
(
(
resource
->
state
==
ACPI_POWER_RESOURCE_STATE_OFF
)
&&
if
(
state
==
ACPI_POWER_RESOURCE_STATE_OFF
&&
!
list_empty
(
&
resource
->
reference
))
{
ref
=
container_of
(
resource
->
reference
.
next
,
struct
acpi_power_reference
,
node
);
mutex_unlock
(
&
resource
->
resource_lock
);
...
...
drivers/acpi/sleep/main.c
View file @
14f7d720
...
...
@@ -167,8 +167,8 @@ static void acpi_pm_finish(void)
{
u32
acpi_state
=
acpi_target_sleep_state
;
acpi_leave_sleep_state
(
acpi_state
);
acpi_disable_wakeup_device
(
acpi_state
);
acpi_leave_sleep_state
(
acpi_state
);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector
((
acpi_physical_address
)
0
);
...
...
@@ -272,8 +272,8 @@ static void acpi_hibernation_finish(void)
* enable it here.
*/
acpi_enable
();
acpi_leave_sleep_state
(
ACPI_STATE_S4
);
acpi_disable_wakeup_device
(
ACPI_STATE_S4
);
acpi_leave_sleep_state
(
ACPI_STATE_S4
);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector
((
acpi_physical_address
)
0
);
...
...
@@ -410,6 +410,7 @@ static void acpi_power_off(void)
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
printk
(
"%s called
\n
"
,
__FUNCTION__
);
local_irq_disable
();
acpi_enable_wakeup_device
(
ACPI_STATE_S5
);
acpi_enter_sleep_state
(
ACPI_STATE_S5
);
}
...
...
include/acpi/acpi_bus.h
View file @
14f7d720
...
...
@@ -168,8 +168,7 @@ struct acpi_device_flags {
u32
power_manageable
:
1
;
u32
performance_manageable
:
1
;
u32
wake_capable
:
1
;
/* Wakeup(_PRW) supported? */
u32
force_power_state
:
1
;
u32
reserved
:
19
;
u32
reserved
:
20
;
};
/* File System */
...
...
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