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
07bf2805
Commit
07bf2805
authored
Jan 12, 2011
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'power-resource' into release
parents
1ae5ec90
53eac700
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
171 additions
and
145 deletions
+171
-145
drivers/acpi/bus.c
drivers/acpi/bus.c
+81
-72
drivers/acpi/fan.c
drivers/acpi/fan.c
+7
-20
drivers/acpi/internal.h
drivers/acpi/internal.h
+3
-2
drivers/acpi/power.c
drivers/acpi/power.c
+50
-40
drivers/acpi/scan.c
drivers/acpi/scan.c
+23
-4
drivers/acpi/thermal.c
drivers/acpi/thermal.c
+3
-2
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/fujitsu-laptop.c
+2
-2
include/acpi/acpi_bus.h
include/acpi/acpi_bus.h
+2
-3
No files found.
drivers/acpi/bus.c
View file @
07bf2805
...
...
@@ -52,22 +52,6 @@ EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s))
static
int
set_power_nocheck
(
const
struct
dmi_system_id
*
id
)
{
printk
(
KERN_NOTICE
PREFIX
"%s detected - "
"disable power check in power transition
\n
"
,
id
->
ident
);
acpi_power_nocheck
=
1
;
return
0
;
}
static
struct
dmi_system_id
__cpuinitdata
power_nocheck_dmi_table
[]
=
{
{
set_power_nocheck
,
"HP Pavilion 05"
,
{
DMI_MATCH
(
DMI_BIOS_VENDOR
,
"Phoenix Technologies LTD"
),
DMI_MATCH
(
DMI_SYS_VENDOR
,
"HP Pavilion 05"
),
DMI_MATCH
(
DMI_PRODUCT_VERSION
,
"2001211RE101GLEND"
)
},
NULL
},
{},
};
#ifdef CONFIG_X86
static
int
set_copy_dsdt
(
const
struct
dmi_system_id
*
id
)
...
...
@@ -196,33 +180,24 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
Power Management
-------------------------------------------------------------------------- */
int
acpi_bus_get_power
(
acpi_handle
handl
e
,
int
*
state
)
static
int
__acpi_bus_get_power
(
struct
acpi_device
*
devic
e
,
int
*
state
)
{
int
result
=
0
;
acpi_status
status
=
0
;
struct
acpi_device
*
device
=
NULL
;
unsigned
long
long
psc
=
0
;
result
=
acpi_bus_get_device
(
handle
,
&
device
);
if
(
result
)
return
result
;
if
(
!
device
||
!
state
)
return
-
EINVAL
;
*
state
=
ACPI_STATE_UNKNOWN
;
if
(
!
device
->
flags
.
power_manageable
)
{
/* TBD: Non-recursive algorithm for walking up hierarchy */
if
(
device
->
parent
)
*
state
=
device
->
parent
->
power
.
state
;
else
*
state
=
ACPI_STATE_D0
;
}
else
{
if
(
device
->
flags
.
power_manageable
)
{
/*
* Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
if
(
device
->
power
.
flags
.
power_resources
)
{
result
=
acpi_power_get_inferred_state
(
device
);
result
=
acpi_power_get_inferred_state
(
device
,
state
);
if
(
result
)
return
result
;
}
else
if
(
device
->
power
.
flags
.
explicit_get
)
{
...
...
@@ -230,59 +205,33 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
NULL
,
&
psc
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
device
->
power
.
state
=
(
int
)
psc
;
*
state
=
(
int
)
psc
;
}
*
state
=
device
->
power
.
state
;
}
else
{
/* TBD: Non-recursive algorithm for walking up hierarchy. */
*
state
=
device
->
parent
?
device
->
parent
->
power
.
state
:
ACPI_STATE_D0
;
}
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Device [%s] power state is D%d
\n
"
,
device
->
pnp
.
bus_id
,
device
->
power
.
state
));
device
->
pnp
.
bus_id
,
*
state
));
return
0
;
}
EXPORT_SYMBOL
(
acpi_bus_get_power
);
int
acpi_bus_set_power
(
acpi_handle
handl
e
,
int
state
)
static
int
__acpi_bus_set_power
(
struct
acpi_device
*
devic
e
,
int
state
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
struct
acpi_device
*
device
=
NULL
;
char
object_name
[
5
]
=
{
'_'
,
'P'
,
'S'
,
'0'
+
state
,
'\0'
};
result
=
acpi_bus_get_device
(
handle
,
&
device
);
if
(
result
)
return
result
;
if
((
state
<
ACPI_STATE_D0
)
||
(
state
>
ACPI_STATE_D3
))
if
(
!
device
||
(
state
<
ACPI_STATE_D0
)
||
(
state
>
ACPI_STATE_D3
))
return
-
EINVAL
;
/* Make sure this is a valid target state */
if
(
!
device
->
flags
.
power_manageable
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Device `[%s]' is not power manageable
\n
"
,
kobject_name
(
&
device
->
dev
.
kobj
)));
return
-
ENODEV
;
}
/*
* Get device's current power state
*/
if
(
!
acpi_power_nocheck
)
{
/*
* Maybe the incorrect power state is returned on the bogus
* bios, which is different with the real power state.
* For example: the bios returns D0 state and the real power
* state is D3. OS expects to set the device to D0 state. In
* such case if OS uses the power state returned by the BIOS,
* the device can't be transisted to the correct power state.
* So if the acpi_power_nocheck is set, it is unnecessary to
* get the power state by calling acpi_bus_get_power.
*/
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
;
...
...
@@ -351,8 +300,75 @@ int acpi_bus_set_power(acpi_handle handle, int state)
return
result
;
}
int
acpi_bus_set_power
(
acpi_handle
handle
,
int
state
)
{
struct
acpi_device
*
device
;
int
result
;
result
=
acpi_bus_get_device
(
handle
,
&
device
);
if
(
result
)
return
result
;
if
(
!
device
->
flags
.
power_manageable
)
{
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Device [%s] is not power manageable
\n
"
,
dev_name
(
&
device
->
dev
)));
return
-
ENODEV
;
}
return
__acpi_bus_set_power
(
device
,
state
);
}
EXPORT_SYMBOL
(
acpi_bus_set_power
);
int
acpi_bus_init_power
(
struct
acpi_device
*
device
)
{
int
state
;
int
result
;
if
(
!
device
)
return
-
EINVAL
;
device
->
power
.
state
=
ACPI_STATE_UNKNOWN
;
result
=
__acpi_bus_get_power
(
device
,
&
state
);
if
(
result
)
return
result
;
if
(
device
->
power
.
flags
.
power_resources
)
result
=
acpi_power_on_resources
(
device
,
state
);
if
(
!
result
)
device
->
power
.
state
=
state
;
return
result
;
}
int
acpi_bus_update_power
(
acpi_handle
handle
,
int
*
state_p
)
{
struct
acpi_device
*
device
;
int
state
;
int
result
;
result
=
acpi_bus_get_device
(
handle
,
&
device
);
if
(
result
)
return
result
;
result
=
__acpi_bus_get_power
(
device
,
&
state
);
if
(
result
)
return
result
;
result
=
__acpi_bus_set_power
(
device
,
state
);
if
(
!
result
&&
state_p
)
*
state_p
=
state
;
return
result
;
}
EXPORT_SYMBOL_GPL
(
acpi_bus_update_power
);
bool
acpi_bus_power_manageable
(
acpi_handle
handle
)
{
struct
acpi_device
*
device
;
...
...
@@ -1023,15 +1039,8 @@ static int __init acpi_init(void)
if
(
acpi_disabled
)
return
result
;
/*
* If the laptop falls into the DMI check table, the power state check
* will be disabled in the course of device power transition.
*/
dmi_check_system
(
power_nocheck_dmi_table
);
acpi_scan_init
();
acpi_ec_init
();
acpi_power_init
();
acpi_debugfs_init
();
acpi_sleep_proc_init
();
acpi_wakeup_device_init
();
...
...
drivers/acpi/fan.c
View file @
07bf2805
...
...
@@ -86,7 +86,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
if
(
!
device
)
return
-
EINVAL
;
result
=
acpi_bus_
get
_power
(
device
->
handle
,
&
acpi_state
);
result
=
acpi_bus_
update
_power
(
device
->
handle
,
&
acpi_state
);
if
(
result
)
return
result
;
...
...
@@ -123,7 +123,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = {
static
int
acpi_fan_add
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
int
state
=
0
;
struct
thermal_cooling_device
*
cdev
;
if
(
!
device
)
...
...
@@ -132,16 +131,12 @@ static int acpi_fan_add(struct acpi_device *device)
strcpy
(
acpi_device_name
(
device
),
"Fan"
);
strcpy
(
acpi_device_class
(
device
),
ACPI_FAN_CLASS
);
result
=
acpi_bus_
get_power
(
device
->
handle
,
&
state
);
result
=
acpi_bus_
update_power
(
device
->
handle
,
NULL
);
if
(
result
)
{
printk
(
KERN_ERR
PREFIX
"
Reading
power state
\n
"
);
printk
(
KERN_ERR
PREFIX
"
Setting initial
power state
\n
"
);
goto
end
;
}
device
->
flags
.
force_power_state
=
1
;
acpi_bus_set_power
(
device
->
handle
,
state
);
device
->
flags
.
force_power_state
=
0
;
cdev
=
thermal_cooling_device_register
(
"Fan"
,
device
,
&
fan_cooling_ops
);
if
(
IS_ERR
(
cdev
))
{
...
...
@@ -200,22 +195,14 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
static
int
acpi_fan_resume
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
int
power_state
=
0
;
int
result
;
if
(
!
device
)
return
-
EINVAL
;
result
=
acpi_bus_get_power
(
device
->
handle
,
&
power_state
);
if
(
result
)
{
printk
(
KERN_ERR
PREFIX
"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
;
result
=
acpi_bus_update_power
(
device
->
handle
,
NULL
);
if
(
result
)
printk
(
KERN_ERR
PREFIX
"Error updating fan power state
\n
"
);
return
result
;
}
...
...
drivers/acpi/internal.h
View file @
07bf2805
...
...
@@ -41,9 +41,10 @@ static inline int acpi_debugfs_init(void) { return 0; }
int
acpi_power_init
(
void
);
int
acpi_device_sleep_wake
(
struct
acpi_device
*
dev
,
int
enable
,
int
sleep_state
,
int
dev_state
);
int
acpi_power_get_inferred_state
(
struct
acpi_device
*
device
);
int
acpi_power_get_inferred_state
(
struct
acpi_device
*
device
,
int
*
state
);
int
acpi_power_on_resources
(
struct
acpi_device
*
device
,
int
state
);
int
acpi_power_transition
(
struct
acpi_device
*
device
,
int
state
);
extern
int
acpi_power_nocheck
;
int
acpi_bus_init_power
(
struct
acpi_device
*
device
)
;
int
acpi_wakeup_device_init
(
void
);
void
acpi_early_processor_set_pdc
(
void
);
...
...
drivers/acpi/power.c
View file @
07bf2805
...
...
@@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
int
acpi_power_nocheck
;
module_param_named
(
power_nocheck
,
acpi_power_nocheck
,
bool
,
000
);
static
int
acpi_power_add
(
struct
acpi_device
*
device
);
static
int
acpi_power_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_power_resume
(
struct
acpi_device
*
device
);
...
...
@@ -266,6 +263,35 @@ static int acpi_power_off_device(acpi_handle handle)
return
result
;
}
static
void
__acpi_power_off_list
(
struct
acpi_handle_list
*
list
,
int
num_res
)
{
int
i
;
for
(
i
=
num_res
-
1
;
i
>=
0
;
i
--
)
acpi_power_off_device
(
list
->
handles
[
i
]);
}
static
void
acpi_power_off_list
(
struct
acpi_handle_list
*
list
)
{
__acpi_power_off_list
(
list
,
list
->
count
);
}
static
int
acpi_power_on_list
(
struct
acpi_handle_list
*
list
)
{
int
result
=
0
;
int
i
;
for
(
i
=
0
;
i
<
list
->
count
;
i
++
)
{
result
=
acpi_power_on
(
list
->
handles
[
i
]);
if
(
result
)
{
__acpi_power_off_list
(
list
,
i
);
break
;
}
}
return
result
;
}
/**
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
* ACPI 3.0) _PSW (Power State Wake)
...
...
@@ -423,19 +449,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
Device Power Management
-------------------------------------------------------------------------- */
int
acpi_power_get_inferred_state
(
struct
acpi_device
*
device
)
int
acpi_power_get_inferred_state
(
struct
acpi_device
*
device
,
int
*
state
)
{
int
result
=
0
;
struct
acpi_handle_list
*
list
=
NULL
;
int
list_state
=
0
;
int
i
=
0
;
if
(
!
device
)
if
(
!
device
||
!
state
)
return
-
EINVAL
;
device
->
power
.
state
=
ACPI_STATE_UNKNOWN
;
/*
* We know a device's inferred power state when all the resources
* required for a given D-state are 'on'.
...
...
@@ -450,22 +473,26 @@ int acpi_power_get_inferred_state(struct acpi_device *device)
return
result
;
if
(
list_state
==
ACPI_POWER_RESOURCE_STATE_ON
)
{
device
->
power
.
state
=
i
;
*
state
=
i
;
return
0
;
}
}
device
->
power
.
state
=
ACPI_STATE_D3
;
*
state
=
ACPI_STATE_D3
;
return
0
;
}
int
acpi_power_on_resources
(
struct
acpi_device
*
device
,
int
state
)
{
if
(
!
device
||
state
<
ACPI_STATE_D0
||
state
>
ACPI_STATE_D3
)
return
-
EINVAL
;
return
acpi_power_on_list
(
&
device
->
power
.
states
[
state
].
resources
);
}
int
acpi_power_transition
(
struct
acpi_device
*
device
,
int
state
)
{
int
result
=
0
;
struct
acpi_handle_list
*
cl
=
NULL
;
/* Current Resources */
struct
acpi_handle_list
*
tl
=
NULL
;
/* Target Resources */
int
i
=
0
;
int
result
;
if
(
!
device
||
(
state
<
ACPI_STATE_D0
)
||
(
state
>
ACPI_STATE_D3
))
return
-
EINVAL
;
...
...
@@ -477,37 +504,20 @@ int acpi_power_transition(struct acpi_device *device, int state)
||
(
device
->
power
.
state
>
ACPI_STATE_D3
))
return
-
ENODEV
;
cl
=
&
device
->
power
.
states
[
device
->
power
.
state
].
resources
;
tl
=
&
device
->
power
.
states
[
state
].
resources
;
/* TBD: Resources must be ordered. */
/*
* First we reference all power resources required in the target list
* (e.g. so the device doesn't lose power while transitioning).
* (e.g. so the device doesn't lose power while transitioning). Then,
* we dereference all power resources used in the current list.
*/
for
(
i
=
0
;
i
<
tl
->
count
;
i
++
)
{
result
=
acpi_power_on
(
tl
->
handles
[
i
]);
if
(
result
)
goto
end
;
}
/*
* Then we dereference all power resources used in the current list.
*/
for
(
i
=
0
;
i
<
cl
->
count
;
i
++
)
{
result
=
acpi_power_off_device
(
cl
->
handles
[
i
]);
if
(
result
)
goto
end
;
}
result
=
acpi_power_on_list
(
&
device
->
power
.
states
[
state
].
resources
);
if
(
!
result
)
acpi_power_off_list
(
&
device
->
power
.
states
[
device
->
power
.
state
].
resources
);
end:
if
(
result
)
device
->
power
.
state
=
ACPI_STATE_UNKNOWN
;
else
{
/* We shouldn't change the state till all above operations succeed */
device
->
power
.
state
=
state
;
}
/* We shouldn't change the state unless the above operations succeed. */
device
->
power
.
state
=
result
?
ACPI_STATE_UNKNOWN
:
state
;
return
result
;
}
...
...
drivers/acpi/scan.c
View file @
07bf2805
...
...
@@ -847,6 +847,8 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
return
0
;
}
static
void
acpi_bus_add_power_resource
(
acpi_handle
handle
);
static
int
acpi_bus_get_power_flags
(
struct
acpi_device
*
device
)
{
acpi_status
status
=
0
;
...
...
@@ -875,8 +877,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
acpi_evaluate_reference
(
device
->
handle
,
object_name
,
NULL
,
&
ps
->
resources
);
if
(
ps
->
resources
.
count
)
{
int
j
;
device
->
power
.
flags
.
power_resources
=
1
;
ps
->
flags
.
valid
=
1
;
for
(
j
=
0
;
j
<
ps
->
resources
.
count
;
j
++
)
acpi_bus_add_power_resource
(
ps
->
resources
.
handles
[
j
]);
}
/* Evaluate "_PSx" to see if we can do explicit sets */
...
...
@@ -901,10 +907,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
device
->
power
.
states
[
ACPI_STATE_D3
].
flags
.
valid
=
1
;
device
->
power
.
states
[
ACPI_STATE_D3
].
power
=
0
;
/* TBD: System wake support and resource requirements. */
device
->
power
.
state
=
ACPI_STATE_UNKNOWN
;
acpi_bus_get_power
(
device
->
handle
,
&
(
device
->
power
.
state
));
acpi_bus_init_power
(
device
);
return
0
;
}
...
...
@@ -1326,6 +1329,20 @@ static int acpi_add_single_object(struct acpi_device **child,
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
static
void
acpi_bus_add_power_resource
(
acpi_handle
handle
)
{
struct
acpi_bus_ops
ops
=
{
.
acpi_op_add
=
1
,
.
acpi_op_start
=
1
,
};
struct
acpi_device
*
device
=
NULL
;
acpi_bus_get_device
(
handle
,
&
device
);
if
(
!
device
)
acpi_add_single_object
(
&
device
,
handle
,
ACPI_BUS_TYPE_POWER
,
ACPI_STA_DEFAULT
,
&
ops
);
}
static
int
acpi_bus_type_and_status
(
acpi_handle
handle
,
int
*
type
,
unsigned
long
long
*
sta
)
{
...
...
@@ -1573,6 +1590,8 @@ int __init acpi_scan_init(void)
printk
(
KERN_ERR
PREFIX
"Could not register bus type
\n
"
);
}
acpi_power_init
();
/*
* Enumerate devices in the ACPI namespace.
*/
...
...
drivers/acpi/thermal.c
View file @
07bf2805
...
...
@@ -1059,8 +1059,9 @@ static int acpi_thermal_resume(struct acpi_device *device)
break
;
tz
->
trips
.
active
[
i
].
flags
.
enabled
=
1
;
for
(
j
=
0
;
j
<
tz
->
trips
.
active
[
i
].
devices
.
count
;
j
++
)
{
result
=
acpi_bus_get_power
(
tz
->
trips
.
active
[
i
].
devices
.
handles
[
j
],
&
power_state
);
result
=
acpi_bus_update_power
(
tz
->
trips
.
active
[
i
].
devices
.
handles
[
j
],
&
power_state
);
if
(
result
||
(
power_state
!=
ACPI_STATE_D0
))
{
tz
->
trips
.
active
[
i
].
flags
.
enabled
=
0
;
break
;
...
...
drivers/platform/x86/fujitsu-laptop.c
View file @
07bf2805
...
...
@@ -689,7 +689,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
if
(
error
)
goto
err_free_input_dev
;
result
=
acpi_bus_
get
_power
(
fujitsu
->
acpi_handle
,
&
state
);
result
=
acpi_bus_
update
_power
(
fujitsu
->
acpi_handle
,
&
state
);
if
(
result
)
{
printk
(
KERN_ERR
"Error reading power state
\n
"
);
goto
err_unregister_input_dev
;
...
...
@@ -857,7 +857,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
if
(
error
)
goto
err_free_input_dev
;
result
=
acpi_bus_
get
_power
(
fujitsu_hotkey
->
acpi_handle
,
&
state
);
result
=
acpi_bus_
update
_power
(
fujitsu_hotkey
->
acpi_handle
,
&
state
);
if
(
result
)
{
printk
(
KERN_ERR
"Error reading power state
\n
"
);
goto
err_unregister_input_dev
;
...
...
include/acpi/acpi_bus.h
View file @
07bf2805
...
...
@@ -149,8 +149,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
:
22
;
u32
reserved
:
23
;
};
/* File System */
...
...
@@ -328,8 +327,8 @@ void acpi_bus_data_handler(acpi_handle handle, void *context);
acpi_status
acpi_bus_get_status_handle
(
acpi_handle
handle
,
unsigned
long
long
*
sta
);
int
acpi_bus_get_status
(
struct
acpi_device
*
device
);
int
acpi_bus_get_power
(
acpi_handle
handle
,
int
*
state
);
int
acpi_bus_set_power
(
acpi_handle
handle
,
int
state
);
int
acpi_bus_update_power
(
acpi_handle
handle
,
int
*
state_p
);
bool
acpi_bus_power_manageable
(
acpi_handle
handle
);
bool
acpi_bus_can_wakeup
(
acpi_handle
handle
);
#ifdef CONFIG_ACPI_PROC_EVENT
...
...
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