Commit ce919ce1 authored by Len Brown's avatar Len Brown

Merge intel.com:/home/lenb/src/26-stable-dev

into intel.com:/home/lenb/src/26-latest-dev
parents d14d4021 82d6b1e6
...@@ -578,6 +578,13 @@ acpi_ds_exec_end_op ( ...@@ -578,6 +578,13 @@ acpi_ds_exec_end_op (
break; break;
} }
/* Done with this result state (Now that operand stack is built) */
status = acpi_ds_result_stack_pop (walk_state);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
/* /*
* If a result object was returned from above, push it on the * If a result object was returned from above, push it on the
* current result stack * current result stack
......
...@@ -81,75 +81,119 @@ ...@@ -81,75 +81,119 @@
* FUNCTION: acpi_ex_do_match * FUNCTION: acpi_ex_do_match
* *
* PARAMETERS: match_op - The AML match operand * PARAMETERS: match_op - The AML match operand
* package_value - Value from the target package * package_obj - Object from the target package
* match_value - Value to be matched * match_obj - Object to be matched
* *
* RETURN: TRUE if the match is successful, FALSE otherwise * RETURN: TRUE if the match is successful, FALSE otherwise
* *
* DESCRIPTION: Implements the low-level match for the ASL Match operator * DESCRIPTION: Implements the low-level match for the ASL Match operator.
* Package elements will be implicitly converted to the type of
* the match object (Integer/Buffer/String).
* *
******************************************************************************/ ******************************************************************************/
u8 u8
acpi_ex_do_match ( acpi_ex_do_match (
u32 match_op, u32 match_op,
acpi_integer package_value, union acpi_operand_object *package_obj,
acpi_integer match_value) union acpi_operand_object *match_obj)
{ {
u8 logical_result = TRUE;
acpi_status status;
/*
* Note: Since the package_obj/match_obj ordering is opposite to that of
* the standard logical operators, we have to reverse them when we call
* do_logical_op in order to make the implicit conversion rules work
* correctly. However, this means we have to flip the entire equation
* also. A bit ugly perhaps, but overall, better than fussing the
* parameters around at runtime, over and over again.
*
* Below, P[i] refers to the package element, M refers to the Match object.
*/
switch (match_op) { switch (match_op) {
case MATCH_MTR: /* always true */ case MATCH_MTR:
break; /* Always true */
break;
case MATCH_MEQ: /* true if equal */ case MATCH_MEQ:
if (package_value != match_value) { /*
* True if equal: (P[i] == M)
* Change to: (M == P[i])
*/
status = acpi_ex_do_logical_op (AML_LEQUAL_OP, match_obj, package_obj,
&logical_result);
if (ACPI_FAILURE (status)) {
return (FALSE); return (FALSE);
} }
break; break;
case MATCH_MLE:
case MATCH_MLE: /* true if less than or equal */ /*
* True if less than or equal: (P[i] <= M) (P[i] not_greater than M)
if (package_value > match_value) { * Change to: (M >= P[i]) (M not_less than P[i])
*/
status = acpi_ex_do_logical_op (AML_LLESS_OP, match_obj, package_obj,
&logical_result);
if (ACPI_FAILURE (status)) {
return (FALSE); return (FALSE);
} }
logical_result = (u8) !logical_result;
break; break;
case MATCH_MLT:
case MATCH_MLT: /* true if less than */ /*
* True if less than: (P[i] < M)
if (package_value >= match_value) { * Change to: (M > P[i])
*/
status = acpi_ex_do_logical_op (AML_LGREATER_OP, match_obj, package_obj,
&logical_result);
if (ACPI_FAILURE (status)) {
return (FALSE); return (FALSE);
} }
break; break;
case MATCH_MGE:
case MATCH_MGE: /* true if greater than or equal */ /*
* True if greater than or equal: (P[i] >= M) (P[i] not_less than M)
if (package_value < match_value) { * Change to: (M <= P[i]) (M not_greater than P[i])
*/
status = acpi_ex_do_logical_op (AML_LGREATER_OP, match_obj, package_obj,
&logical_result);
if (ACPI_FAILURE (status)) {
return (FALSE); return (FALSE);
} }
logical_result = (u8)!logical_result;
break; break;
case MATCH_MGT:
case MATCH_MGT: /* true if greater than */ /*
* True if greater than: (P[i] > M)
if (package_value <= match_value) { * Change to: (M < P[i])
*/
status = acpi_ex_do_logical_op (AML_LLESS_OP, match_obj, package_obj,
&logical_result);
if (ACPI_FAILURE (status)) {
return (FALSE); return (FALSE);
} }
break; break;
default:
default: /* undefined */ /* Undefined */
return (FALSE); return (FALSE);
} }
return logical_result;
return TRUE;
} }
...@@ -182,19 +226,21 @@ acpi_ex_opcode_6A_0T_1R ( ...@@ -182,19 +226,21 @@ acpi_ex_opcode_6A_0T_1R (
switch (walk_state->opcode) { switch (walk_state->opcode) {
case AML_MATCH_OP: case AML_MATCH_OP:
/* /*
* Match (search_package[0], match_op1[1], match_object1[2], * Match (search_pkg[0], match_op1[1], match_obj1[2],
* match_op2[3], match_object2[4], start_index[5]) * match_op2[3], match_obj2[4], start_index[5])
*/ */
/* Validate match comparison sub-opcodes */ /* Validate both Match Term Operators (MTR, MEQ, etc.) */
if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) ||
(operand[3]->integer.value > MAX_MATCH_OPERATOR)) { (operand[3]->integer.value > MAX_MATCH_OPERATOR)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "operation encoding out of range\n")); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Match operator out of range\n"));
status = AE_AML_OPERAND_VALUE; status = AE_AML_OPERAND_VALUE;
goto cleanup; goto cleanup;
} }
/* Get the package start_index, validate against the package length */
index = (u32) operand[5]->integer.value; index = (u32) operand[5]->integer.value;
if (index >= (u32) operand[0]->package.count) { if (index >= (u32) operand[0]->package.count) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n")); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n"));
...@@ -202,6 +248,8 @@ acpi_ex_opcode_6A_0T_1R ( ...@@ -202,6 +248,8 @@ acpi_ex_opcode_6A_0T_1R (
goto cleanup; goto cleanup;
} }
/* Create an integer for the return value */
return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
if (!return_desc) { if (!return_desc) {
status = AE_NO_MEMORY; status = AE_NO_MEMORY;
...@@ -214,37 +262,39 @@ acpi_ex_opcode_6A_0T_1R ( ...@@ -214,37 +262,39 @@ acpi_ex_opcode_6A_0T_1R (
return_desc->integer.value = ACPI_INTEGER_MAX; return_desc->integer.value = ACPI_INTEGER_MAX;
/* /*
* Examine each element until a match is found. Within the loop, * Examine each element until a match is found. Both match conditions
* must be satisfied for a match to occur. Within the loop,
* "continue" signifies that the current element does not match * "continue" signifies that the current element does not match
* and the next should be examined. * and the next should be examined.
* *
* Upon finding a match, the loop will terminate via "break" at * Upon finding a match, the loop will terminate via "break" at
* the bottom. If it terminates "normally", match_value will be -1 * the bottom. If it terminates "normally", match_value will be
* (its initial value) indicating that no match was found. When * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no
* returned as a Number, this will produce the Ones value as specified. * match was found.
*/ */
for ( ; index < operand[0]->package.count; index++) { for ( ; index < operand[0]->package.count; index++) {
/* Get the current package element */
this_element = operand[0]->package.elements[index]; this_element = operand[0]->package.elements[index];
/* /* Treat any uninitialized (NULL) elements as non-matching */
* Treat any NULL or non-numeric elements as non-matching.
*/ if (!this_element) {
if (!this_element ||
ACPI_GET_OBJECT_TYPE (this_element) != ACPI_TYPE_INTEGER) {
continue; continue;
} }
/* /*
* "continue" (proceed to next iteration of enclosing * Both match conditions must be satisfied. Execution of a continue
* "for" loop) signifies a non-match. * (proceed to next iteration of enclosing for loop) signifies a
* non-match.
*/ */
if (!acpi_ex_do_match ((u32) operand[1]->integer.value, if (!acpi_ex_do_match ((u32) operand[1]->integer.value,
this_element->integer.value, operand[2]->integer.value)) { this_element, operand[2])) {
continue; continue;
} }
if (!acpi_ex_do_match ((u32) operand[3]->integer.value, if (!acpi_ex_do_match ((u32) operand[3]->integer.value,
this_element->integer.value, operand[4]->integer.value)) { this_element, operand[4])) {
continue; continue;
} }
...@@ -253,7 +303,6 @@ acpi_ex_opcode_6A_0T_1R ( ...@@ -253,7 +303,6 @@ acpi_ex_opcode_6A_0T_1R (
return_desc->integer.value = index; return_desc->integer.value = index;
break; break;
} }
break; break;
......
...@@ -312,7 +312,7 @@ acpi_ex_resolve_operands ( ...@@ -312,7 +312,7 @@ acpi_ex_resolve_operands (
goto next_operand; goto next_operand;
case ARGI_ANYTYPE: case ARGI_DATAREFOBJ: /* Store operator only */
/* /*
* We don't want to resolve index_op reference objects during * We don't want to resolve index_op reference objects during
......
...@@ -206,6 +206,7 @@ acpi_ex_store_object_to_object ( ...@@ -206,6 +206,7 @@ acpi_ex_store_object_to_object (
{ {
union acpi_operand_object *actual_src_desc; union acpi_operand_object *actual_src_desc;
acpi_status status = AE_OK; acpi_status status = AE_OK;
acpi_object_type original_src_type;
ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_object", source_desc); ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_object", source_desc);
...@@ -222,7 +223,8 @@ acpi_ex_store_object_to_object ( ...@@ -222,7 +223,8 @@ acpi_ex_store_object_to_object (
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_GET_OBJECT_TYPE (dest_desc)) { original_src_type = ACPI_GET_OBJECT_TYPE (source_desc);
if (original_src_type != ACPI_GET_OBJECT_TYPE (dest_desc)) {
/* /*
* The source type does not match the type of the destination. * The source type does not match the type of the destination.
* Perform the "implicit conversion" of the source to the current type * Perform the "implicit conversion" of the source to the current type
...@@ -232,8 +234,8 @@ acpi_ex_store_object_to_object ( ...@@ -232,8 +234,8 @@ acpi_ex_store_object_to_object (
* Otherwise, actual_src_desc is a temporary object to hold the * Otherwise, actual_src_desc is a temporary object to hold the
* converted object. * converted object.
*/ */
status = acpi_ex_convert_to_target_type (ACPI_GET_OBJECT_TYPE (dest_desc), source_desc, status = acpi_ex_convert_to_target_type (ACPI_GET_OBJECT_TYPE (dest_desc),
&actual_src_desc, walk_state); source_desc, &actual_src_desc, walk_state);
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
...@@ -269,12 +271,18 @@ acpi_ex_store_object_to_object ( ...@@ -269,12 +271,18 @@ acpi_ex_store_object_to_object (
case ACPI_TYPE_BUFFER: case ACPI_TYPE_BUFFER:
status = acpi_ex_store_buffer_to_buffer (actual_src_desc, dest_desc); /*
* Note: There is different store behavior depending on the original
* source type
*/
status = acpi_ex_store_buffer_to_buffer (original_src_type, actual_src_desc,
dest_desc);
break; break;
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, &dest_desc, walk_state); status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, &dest_desc,
walk_state);
break; break;
default: default:
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
acpi_status acpi_status
acpi_ex_store_buffer_to_buffer ( acpi_ex_store_buffer_to_buffer (
acpi_object_type original_src_type,
union acpi_operand_object *source_desc, union acpi_operand_object *source_desc,
union acpi_operand_object *target_desc) union acpi_operand_object *target_desc)
{ {
...@@ -104,10 +105,17 @@ acpi_ex_store_buffer_to_buffer ( ...@@ -104,10 +105,17 @@ acpi_ex_store_buffer_to_buffer (
ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length); ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length);
ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length); ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length);
/*
* If the original source was a string, we must truncate the buffer,
* according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer
* copy must not truncate the original buffer.
*/
if (original_src_type == ACPI_TYPE_STRING) {
/* Set the new length of the target */ /* Set the new length of the target */
target_desc->buffer.length = length; target_desc->buffer.length = length;
} }
}
else { else {
/* Truncate the source, copy only what will fit */ /* Truncate the source, copy only what will fit */
......
...@@ -237,7 +237,7 @@ acpi_get_object_info ( ...@@ -237,7 +237,7 @@ acpi_get_object_info (
{ {
acpi_status status; acpi_status status;
struct acpi_namespace_node *node; struct acpi_namespace_node *node;
struct acpi_device_info info; struct acpi_device_info *info;
struct acpi_device_info *return_info; struct acpi_device_info *return_info;
struct acpi_compatible_id_list *cid_list = NULL; struct acpi_compatible_id_list *cid_list = NULL;
acpi_size size; acpi_size size;
...@@ -254,55 +254,59 @@ acpi_get_object_info ( ...@@ -254,55 +254,59 @@ acpi_get_object_info (
return (status); return (status);
} }
info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_device_info));
if (!info) {
return (AE_NO_MEMORY);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
return (status); goto cleanup;
} }
node = acpi_ns_map_handle_to_node (handle); node = acpi_ns_map_handle_to_node (handle);
if (!node) { if (!node) {
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (AE_BAD_PARAMETER); goto cleanup;
} }
/* Init return structure */ /* Init return structure */
size = sizeof (struct acpi_device_info); size = sizeof (struct acpi_device_info);
ACPI_MEMSET (&info, 0, size);
info.type = node->type; info->type = node->type;
info.name = node->name.integer; info->name = node->name.integer;
info.valid = 0; info->valid = 0;
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
return (status); goto cleanup;
} }
/* If not a device, we are all done */ /* If not a device, we are all done */
if (info.type == ACPI_TYPE_DEVICE) { if (info->type == ACPI_TYPE_DEVICE) {
/* /*
* Get extra info for ACPI Devices objects only: * Get extra info for ACPI Devices objects only:
* Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods.
* *
* Note: none of these methods are required, so they may or may * Note: none of these methods are required, so they may or may
* not be present for this device. The Info.Valid bitfield is used * not be present for this device. The Info->Valid bitfield is used
* to indicate which methods were found and ran successfully. * to indicate which methods were found and ran successfully.
*/ */
/* Execute the Device._HID method */ /* Execute the Device._HID method */
status = acpi_ut_execute_HID (node, &info.hardware_id); status = acpi_ut_execute_HID (node, &info->hardware_id);
if (ACPI_SUCCESS (status)) { if (ACPI_SUCCESS (status)) {
info.valid |= ACPI_VALID_HID; info->valid |= ACPI_VALID_HID;
} }
/* Execute the Device._UID method */ /* Execute the Device._UID method */
status = acpi_ut_execute_UID (node, &info.unique_id); status = acpi_ut_execute_UID (node, &info->unique_id);
if (ACPI_SUCCESS (status)) { if (ACPI_SUCCESS (status)) {
info.valid |= ACPI_VALID_UID; info->valid |= ACPI_VALID_UID;
} }
/* Execute the Device._CID method */ /* Execute the Device._CID method */
...@@ -311,32 +315,30 @@ acpi_get_object_info ( ...@@ -311,32 +315,30 @@ acpi_get_object_info (
if (ACPI_SUCCESS (status)) { if (ACPI_SUCCESS (status)) {
size += ((acpi_size) cid_list->count - 1) * size += ((acpi_size) cid_list->count - 1) *
sizeof (struct acpi_compatible_id); sizeof (struct acpi_compatible_id);
info.valid |= ACPI_VALID_CID; info->valid |= ACPI_VALID_CID;
} }
/* Execute the Device._STA method */ /* Execute the Device._STA method */
status = acpi_ut_execute_STA (node, &info.current_status); status = acpi_ut_execute_STA (node, &info->current_status);
if (ACPI_SUCCESS (status)) { if (ACPI_SUCCESS (status)) {
info.valid |= ACPI_VALID_STA; info->valid |= ACPI_VALID_STA;
} }
/* Execute the Device._ADR method */ /* Execute the Device._ADR method */
status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node, status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node,
&info.address); &info->address);
if (ACPI_SUCCESS (status)) { if (ACPI_SUCCESS (status)) {
info.valid |= ACPI_VALID_ADR; info->valid |= ACPI_VALID_ADR;
} }
/* Execute the Device._sx_d methods */ /* Execute the Device._sx_d methods */
status = acpi_ut_execute_sxds (node, info.highest_dstates); status = acpi_ut_execute_sxds (node, info->highest_dstates);
if (ACPI_SUCCESS (status)) { if (ACPI_SUCCESS (status)) {
info.valid |= ACPI_VALID_SXDS; info->valid |= ACPI_VALID_SXDS;
} }
status = AE_OK;
} }
/* Validate/Allocate/Clear caller buffer */ /* Validate/Allocate/Clear caller buffer */
...@@ -349,7 +351,7 @@ acpi_get_object_info ( ...@@ -349,7 +351,7 @@ acpi_get_object_info (
/* Populate the return buffer */ /* Populate the return buffer */
return_info = buffer->pointer; return_info = buffer->pointer;
ACPI_MEMCPY (return_info, &info, sizeof (struct acpi_device_info)); ACPI_MEMCPY (return_info, info, sizeof (struct acpi_device_info));
if (cid_list) { if (cid_list) {
ACPI_MEMCPY (&return_info->compatibility_id, cid_list, cid_list->size); ACPI_MEMCPY (&return_info->compatibility_id, cid_list, cid_list->size);
...@@ -357,6 +359,7 @@ acpi_get_object_info ( ...@@ -357,6 +359,7 @@ acpi_get_object_info (
cleanup: cleanup:
ACPI_MEM_FREE (info);
if (cid_list) { if (cid_list) {
ACPI_MEM_FREE (cid_list); ACPI_MEM_FREE (cid_list);
} }
......
...@@ -289,7 +289,7 @@ ...@@ -289,7 +289,7 @@
#define ARGI_LOCAL6 ARG_NONE #define ARGI_LOCAL6 ARG_NONE
#define ARGI_LOCAL7 ARG_NONE #define ARGI_LOCAL7 ARG_NONE
#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) #define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) #define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER)
#define ARGI_METHOD_OP ARGI_INVALID_OPCODE #define ARGI_METHOD_OP ARGI_INVALID_OPCODE
#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE #define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE
#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
......
...@@ -269,7 +269,7 @@ acpi_tb_convert_fadt1 ( ...@@ -269,7 +269,7 @@ acpi_tb_convert_fadt1 (
* that immediately follows. * that immediately follows.
*/ */
ACPI_MEMCPY (&local_fadt->reset_register, ACPI_MEMCPY (&local_fadt->reset_register,
&((struct fadt_descriptor_rev2_minus *) original_fadt)->reset_register, &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, original_fadt))->reset_register,
sizeof (struct acpi_generic_address) + 1); sizeof (struct acpi_generic_address) + 1);
} }
else { else {
......
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
/* Version string */ /* Version string */
#define ACPI_CA_VERSION 0x20050125 #define ACPI_CA_VERSION 0x20050211
/* /*
* OS name, used for the _OS object. The _OS object is essentially obsolete, * OS name, used for the _OS object. The _OS object is essentially obsolete,
......
...@@ -217,8 +217,8 @@ acpi_ex_opcode_6A_0T_1R ( ...@@ -217,8 +217,8 @@ acpi_ex_opcode_6A_0T_1R (
u8 u8
acpi_ex_do_match ( acpi_ex_do_match (
u32 match_op, u32 match_op,
acpi_integer package_value, union acpi_operand_object *package_obj,
acpi_integer match_value); union acpi_operand_object *match_obj);
acpi_status acpi_status
acpi_ex_get_object_reference ( acpi_ex_get_object_reference (
...@@ -617,6 +617,7 @@ acpi_ex_store_object_to_object ( ...@@ -617,6 +617,7 @@ acpi_ex_store_object_to_object (
acpi_status acpi_status
acpi_ex_store_buffer_to_buffer ( acpi_ex_store_buffer_to_buffer (
acpi_object_type original_src_type,
union acpi_operand_object *source_desc, union acpi_operand_object *source_desc,
union acpi_operand_object *target_desc); union acpi_operand_object *target_desc);
......
...@@ -81,6 +81,8 @@ ...@@ -81,6 +81,8 @@
#define ACPI_USE_NATIVE_DIVIDE #define ACPI_USE_NATIVE_DIVIDE
#endif #endif
#define __cdecl
#define ACPI_FLUSH_CPU_CACHE()
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
/* Linux uses GCC */ /* Linux uses GCC */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment