diff options
Diffstat (limited to 'drivers')
56 files changed, 3920 insertions, 1652 deletions
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 0d2cdb86158b..97991ac6f5fc 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c | |||
@@ -100,7 +100,8 @@ static void round_robin_cpu(unsigned int tsk_index) | |||
100 | struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); | 100 | struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); |
101 | cpumask_var_t tmp; | 101 | cpumask_var_t tmp; |
102 | int cpu; | 102 | int cpu; |
103 | unsigned long min_weight = -1, preferred_cpu; | 103 | unsigned long min_weight = -1; |
104 | unsigned long uninitialized_var(preferred_cpu); | ||
104 | 105 | ||
105 | if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) | 106 | if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) |
106 | return; | 107 | return; |
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index ab83919dda61..61edb156e8d0 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h | |||
@@ -296,6 +296,11 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data, | |||
296 | acpi_status validate_status, | 296 | acpi_status validate_status, |
297 | union acpi_operand_object **return_object_ptr); | 297 | union acpi_operand_object **return_object_ptr); |
298 | 298 | ||
299 | void | ||
300 | acpi_ns_remove_null_elements(struct acpi_predefined_data *data, | ||
301 | u8 package_type, | ||
302 | union acpi_operand_object *obj_desc); | ||
303 | |||
299 | /* | 304 | /* |
300 | * nssearch - Namespace searching and entry | 305 | * nssearch - Namespace searching and entry |
301 | */ | 306 | */ |
@@ -354,9 +359,7 @@ acpi_ns_externalize_name(u32 internal_name_length, | |||
354 | const char *internal_name, | 359 | const char *internal_name, |
355 | u32 * converted_name_length, char **converted_name); | 360 | u32 * converted_name_length, char **converted_name); |
356 | 361 | ||
357 | struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle); | 362 | struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle); |
358 | |||
359 | acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node); | ||
360 | 363 | ||
361 | void acpi_ns_terminate(void); | 364 | void acpi_ns_terminate(void); |
362 | 365 | ||
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index b39d682a2140..64062b1be3ee 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h | |||
@@ -180,7 +180,11 @@ struct acpi_object_method { | |||
180 | u8 sync_level; | 180 | u8 sync_level; |
181 | union acpi_operand_object *mutex; | 181 | union acpi_operand_object *mutex; |
182 | u8 *aml_start; | 182 | u8 *aml_start; |
183 | ACPI_INTERNAL_METHOD implementation; | 183 | union { |
184 | ACPI_INTERNAL_METHOD implementation; | ||
185 | union acpi_operand_object *handler; | ||
186 | } extra; | ||
187 | |||
184 | u32 aml_length; | 188 | u32 aml_length; |
185 | u8 thread_count; | 189 | u8 thread_count; |
186 | acpi_owner_id owner_id; | 190 | acpi_owner_id owner_id; |
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 567a4899a018..e786f9fd767f 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c | |||
@@ -414,7 +414,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
414 | /* Invoke an internal method if necessary */ | 414 | /* Invoke an internal method if necessary */ |
415 | 415 | ||
416 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { | 416 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { |
417 | status = obj_desc->method.implementation(next_walk_state); | 417 | status = obj_desc->method.extra.implementation(next_walk_state); |
418 | if (status == AE_OK) { | 418 | if (status == AE_OK) { |
419 | status = AE_CTRL_TERMINATE; | 419 | status = AE_CTRL_TERMINATE; |
420 | } | 420 | } |
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 10fc78517843..b40513dd6a6a 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c | |||
@@ -212,18 +212,19 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, | |||
212 | case ACPI_TYPE_BUFFER: | 212 | case ACPI_TYPE_BUFFER: |
213 | 213 | ||
214 | /* | 214 | /* |
215 | * These types we will allow, but we will change the type. This | 215 | * These types we will allow, but we will change the type. |
216 | * enables some existing code of the form: | 216 | * This enables some existing code of the form: |
217 | * | 217 | * |
218 | * Name (DEB, 0) | 218 | * Name (DEB, 0) |
219 | * Scope (DEB) { ... } | 219 | * Scope (DEB) { ... } |
220 | * | 220 | * |
221 | * Note: silently change the type here. On the second pass, we will report | 221 | * Note: silently change the type here. On the second pass, |
222 | * a warning | 222 | * we will report a warning |
223 | */ | 223 | */ |
224 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 224 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
225 | "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", | 225 | "Type override - [%4.4s] had invalid type (%s) " |
226 | path, | 226 | "for Scope operator, changed to type ANY\n", |
227 | acpi_ut_get_node_name(node), | ||
227 | acpi_ut_get_type_name(node->type))); | 228 | acpi_ut_get_type_name(node->type))); |
228 | 229 | ||
229 | node->type = ACPI_TYPE_ANY; | 230 | node->type = ACPI_TYPE_ANY; |
@@ -235,8 +236,10 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, | |||
235 | /* All other types are an error */ | 236 | /* All other types are an error */ |
236 | 237 | ||
237 | ACPI_ERROR((AE_INFO, | 238 | ACPI_ERROR((AE_INFO, |
238 | "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)", | 239 | "Invalid type (%s) for target of " |
239 | acpi_ut_get_type_name(node->type), path)); | 240 | "Scope operator [%4.4s] (Cannot override)", |
241 | acpi_ut_get_type_name(node->type), | ||
242 | acpi_ut_get_node_name(node))); | ||
240 | 243 | ||
241 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | 244 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
242 | } | 245 | } |
@@ -697,15 +700,16 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, | |||
697 | case ACPI_TYPE_BUFFER: | 700 | case ACPI_TYPE_BUFFER: |
698 | 701 | ||
699 | /* | 702 | /* |
700 | * These types we will allow, but we will change the type. This | 703 | * These types we will allow, but we will change the type. |
701 | * enables some existing code of the form: | 704 | * This enables some existing code of the form: |
702 | * | 705 | * |
703 | * Name (DEB, 0) | 706 | * Name (DEB, 0) |
704 | * Scope (DEB) { ... } | 707 | * Scope (DEB) { ... } |
705 | */ | 708 | */ |
706 | ACPI_WARNING((AE_INFO, | 709 | ACPI_WARNING((AE_INFO, |
707 | "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)", | 710 | "Type override - [%4.4s] had invalid type (%s) " |
708 | buffer_ptr, | 711 | "for Scope operator, changed to type ANY\n", |
712 | acpi_ut_get_node_name(node), | ||
709 | acpi_ut_get_type_name(node->type))); | 713 | acpi_ut_get_type_name(node->type))); |
710 | 714 | ||
711 | node->type = ACPI_TYPE_ANY; | 715 | node->type = ACPI_TYPE_ANY; |
@@ -717,9 +721,10 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, | |||
717 | /* All other types are an error */ | 721 | /* All other types are an error */ |
718 | 722 | ||
719 | ACPI_ERROR((AE_INFO, | 723 | ACPI_ERROR((AE_INFO, |
720 | "Invalid type (%s) for target of Scope operator [%4.4s]", | 724 | "Invalid type (%s) for target of " |
725 | "Scope operator [%4.4s] (Cannot override)", | ||
721 | acpi_ut_get_type_name(node->type), | 726 | acpi_ut_get_type_name(node->type), |
722 | buffer_ptr)); | 727 | acpi_ut_get_node_name(node))); |
723 | 728 | ||
724 | return (AE_AML_OPERAND_TYPE); | 729 | return (AE_AML_OPERAND_TYPE); |
725 | } | 730 | } |
@@ -1047,9 +1052,22 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) | |||
1047 | } | 1052 | } |
1048 | 1053 | ||
1049 | /* | 1054 | /* |
1050 | * If we are executing a method, initialize the region | 1055 | * The op_region is not fully parsed at this time. The only valid |
1056 | * argument is the space_id. (We must save the address of the | ||
1057 | * AML of the address and length operands) | ||
1058 | * | ||
1059 | * If we have a valid region, initialize it. The namespace is | ||
1060 | * unlocked at this point. | ||
1061 | * | ||
1062 | * Need to unlock interpreter if it is locked (if we are running | ||
1063 | * a control method), in order to allow _REG methods to be run | ||
1064 | * during acpi_ev_initialize_region. | ||
1051 | */ | 1065 | */ |
1052 | if (walk_state->method_node) { | 1066 | if (walk_state->method_node) { |
1067 | /* | ||
1068 | * Executing a method: initialize the region and unlock | ||
1069 | * the interpreter | ||
1070 | */ | ||
1053 | status = | 1071 | status = |
1054 | acpi_ex_create_region(op->named.data, | 1072 | acpi_ex_create_region(op->named.data, |
1055 | op->named.length, | 1073 | op->named.length, |
@@ -1058,21 +1076,17 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) | |||
1058 | if (ACPI_FAILURE(status)) { | 1076 | if (ACPI_FAILURE(status)) { |
1059 | return (status); | 1077 | return (status); |
1060 | } | 1078 | } |
1061 | } | ||
1062 | 1079 | ||
1063 | /* | 1080 | acpi_ex_exit_interpreter(); |
1064 | * The op_region is not fully parsed at this time. Only valid | 1081 | } |
1065 | * argument is the space_id. (We must save the address of the | ||
1066 | * AML of the address and length operands) | ||
1067 | */ | ||
1068 | 1082 | ||
1069 | /* | ||
1070 | * If we have a valid region, initialize it | ||
1071 | * Namespace is NOT locked at this point. | ||
1072 | */ | ||
1073 | status = | 1083 | status = |
1074 | acpi_ev_initialize_region | 1084 | acpi_ev_initialize_region |
1075 | (acpi_ns_get_attached_object(node), FALSE); | 1085 | (acpi_ns_get_attached_object(node), FALSE); |
1086 | if (walk_state->method_node) { | ||
1087 | acpi_ex_enter_interpreter(); | ||
1088 | } | ||
1089 | |||
1076 | if (ACPI_FAILURE(status)) { | 1090 | if (ACPI_FAILURE(status)) { |
1077 | /* | 1091 | /* |
1078 | * If AE_NOT_EXIST is returned, it is not fatal | 1092 | * If AE_NOT_EXIST is returned, it is not fatal |
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 0bc807c33a56..5336d911fbf0 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c | |||
@@ -718,7 +718,7 @@ acpi_ev_install_handler(acpi_handle obj_handle, | |||
718 | 718 | ||
719 | /* Convert and validate the device handle */ | 719 | /* Convert and validate the device handle */ |
720 | 720 | ||
721 | node = acpi_ns_map_handle_to_node(obj_handle); | 721 | node = acpi_ns_validate_handle(obj_handle); |
722 | if (!node) { | 722 | if (!node) { |
723 | return (AE_BAD_PARAMETER); | 723 | return (AE_BAD_PARAMETER); |
724 | } | 724 | } |
@@ -1087,7 +1087,7 @@ acpi_ev_reg_run(acpi_handle obj_handle, | |||
1087 | 1087 | ||
1088 | /* Convert and validate the device handle */ | 1088 | /* Convert and validate the device handle */ |
1089 | 1089 | ||
1090 | node = acpi_ns_map_handle_to_node(obj_handle); | 1090 | node = acpi_ns_validate_handle(obj_handle); |
1091 | if (!node) { | 1091 | if (!node) { |
1092 | return (AE_BAD_PARAMETER); | 1092 | return (AE_BAD_PARAMETER); |
1093 | } | 1093 | } |
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index cf29c4953028..ff168052a332 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c | |||
@@ -575,6 +575,21 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, | |||
575 | handler_obj = obj_desc->thermal_zone.handler; | 575 | handler_obj = obj_desc->thermal_zone.handler; |
576 | break; | 576 | break; |
577 | 577 | ||
578 | case ACPI_TYPE_METHOD: | ||
579 | /* | ||
580 | * If we are executing module level code, the original | ||
581 | * Node's object was replaced by this Method object and we | ||
582 | * saved the handler in the method object. | ||
583 | * | ||
584 | * See acpi_ns_exec_module_code | ||
585 | */ | ||
586 | if (obj_desc->method. | ||
587 | flags & AOPOBJ_MODULE_LEVEL) { | ||
588 | handler_obj = | ||
589 | obj_desc->method.extra.handler; | ||
590 | } | ||
591 | break; | ||
592 | |||
578 | default: | 593 | default: |
579 | /* Ignore other objects */ | 594 | /* Ignore other objects */ |
580 | break; | 595 | break; |
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 10b8543dd466..2fe0809d4eb2 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c | |||
@@ -259,7 +259,7 @@ acpi_install_notify_handler(acpi_handle device, | |||
259 | 259 | ||
260 | /* Convert and validate the device handle */ | 260 | /* Convert and validate the device handle */ |
261 | 261 | ||
262 | node = acpi_ns_map_handle_to_node(device); | 262 | node = acpi_ns_validate_handle(device); |
263 | if (!node) { | 263 | if (!node) { |
264 | status = AE_BAD_PARAMETER; | 264 | status = AE_BAD_PARAMETER; |
265 | goto unlock_and_exit; | 265 | goto unlock_and_exit; |
@@ -425,7 +425,7 @@ acpi_remove_notify_handler(acpi_handle device, | |||
425 | 425 | ||
426 | /* Convert and validate the device handle */ | 426 | /* Convert and validate the device handle */ |
427 | 427 | ||
428 | node = acpi_ns_map_handle_to_node(device); | 428 | node = acpi_ns_validate_handle(device); |
429 | if (!node) { | 429 | if (!node) { |
430 | status = AE_BAD_PARAMETER; | 430 | status = AE_BAD_PARAMETER; |
431 | goto unlock_and_exit; | 431 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 4721f58fe42c..eed7a38d25f2 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c | |||
@@ -610,7 +610,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, | |||
610 | return (status); | 610 | return (status); |
611 | } | 611 | } |
612 | 612 | ||
613 | node = acpi_ns_map_handle_to_node(gpe_device); | 613 | node = acpi_ns_validate_handle(gpe_device); |
614 | if (!node) { | 614 | if (!node) { |
615 | status = AE_BAD_PARAMETER; | 615 | status = AE_BAD_PARAMETER; |
616 | goto unlock_and_exit; | 616 | goto unlock_and_exit; |
@@ -698,7 +698,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) | |||
698 | return (status); | 698 | return (status); |
699 | } | 699 | } |
700 | 700 | ||
701 | node = acpi_ns_map_handle_to_node(gpe_device); | 701 | node = acpi_ns_validate_handle(gpe_device); |
702 | if (!node) { | 702 | if (!node) { |
703 | status = AE_BAD_PARAMETER; | 703 | status = AE_BAD_PARAMETER; |
704 | goto unlock_and_exit; | 704 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 7c3d2d356ffb..c98aa7c2d67c 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c | |||
@@ -89,7 +89,7 @@ acpi_install_address_space_handler(acpi_handle device, | |||
89 | 89 | ||
90 | /* Convert and validate the device handle */ | 90 | /* Convert and validate the device handle */ |
91 | 91 | ||
92 | node = acpi_ns_map_handle_to_node(device); | 92 | node = acpi_ns_validate_handle(device); |
93 | if (!node) { | 93 | if (!node) { |
94 | status = AE_BAD_PARAMETER; | 94 | status = AE_BAD_PARAMETER; |
95 | goto unlock_and_exit; | 95 | goto unlock_and_exit; |
@@ -155,7 +155,7 @@ acpi_remove_address_space_handler(acpi_handle device, | |||
155 | 155 | ||
156 | /* Convert and validate the device handle */ | 156 | /* Convert and validate the device handle */ |
157 | 157 | ||
158 | node = acpi_ns_map_handle_to_node(device); | 158 | node = acpi_ns_validate_handle(device); |
159 | if (!node || | 159 | if (!node || |
160 | ((node->type != ACPI_TYPE_DEVICE) && | 160 | ((node->type != ACPI_TYPE_DEVICE) && |
161 | (node->type != ACPI_TYPE_PROCESSOR) && | 161 | (node->type != ACPI_TYPE_PROCESSOR) && |
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 2f0114202b05..3c456bd575d0 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c | |||
@@ -375,6 +375,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
375 | return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); | 375 | return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); |
376 | } | 376 | } |
377 | 377 | ||
378 | /* Must have a valid thread ID */ | ||
379 | |||
380 | if (!walk_state->thread) { | ||
381 | ACPI_ERROR((AE_INFO, | ||
382 | "Cannot release Mutex [%4.4s], null thread info", | ||
383 | acpi_ut_get_node_name(obj_desc->mutex.node))); | ||
384 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
385 | } | ||
386 | |||
378 | /* | 387 | /* |
379 | * The Mutex is owned, but this thread must be the owner. | 388 | * The Mutex is owned, but this thread must be the owner. |
380 | * Special case for Global Lock, any thread can release | 389 | * Special case for Global Lock, any thread can release |
@@ -392,15 +401,6 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
392 | return_ACPI_STATUS(AE_AML_NOT_OWNER); | 401 | return_ACPI_STATUS(AE_AML_NOT_OWNER); |
393 | } | 402 | } |
394 | 403 | ||
395 | /* Must have a valid thread ID */ | ||
396 | |||
397 | if (!walk_state->thread) { | ||
398 | ACPI_ERROR((AE_INFO, | ||
399 | "Cannot release Mutex [%4.4s], null thread info", | ||
400 | acpi_ut_get_node_name(obj_desc->mutex.node))); | ||
401 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
402 | } | ||
403 | |||
404 | /* | 404 | /* |
405 | * The sync level of the mutex must be equal to the current sync level. In | 405 | * The sync level of the mutex must be equal to the current sync level. In |
406 | * other words, the current level means that at least one mutex at that | 406 | * other words, the current level means that at least one mutex at that |
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 9c3cdbe2d82a..d622ba770000 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c | |||
@@ -165,7 +165,7 @@ acpi_status acpi_ns_root_initialize(void) | |||
165 | 165 | ||
166 | obj_desc->method.method_flags = | 166 | obj_desc->method.method_flags = |
167 | AML_METHOD_INTERNAL_ONLY; | 167 | AML_METHOD_INTERNAL_ONLY; |
168 | obj_desc->method.implementation = | 168 | obj_desc->method.extra.implementation = |
169 | acpi_ut_osi_implementation; | 169 | acpi_ut_osi_implementation; |
170 | #endif | 170 | #endif |
171 | break; | 171 | break; |
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 2deb986861ca..e37836e27e29 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c | |||
@@ -180,7 +180,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, | |||
180 | return (AE_OK); | 180 | return (AE_OK); |
181 | } | 181 | } |
182 | 182 | ||
183 | this_node = acpi_ns_map_handle_to_node(obj_handle); | 183 | this_node = acpi_ns_validate_handle(obj_handle); |
184 | if (!this_node) { | 184 | if (!this_node) { |
185 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", | 185 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", |
186 | obj_handle)); | 186 | obj_handle)); |
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index f771e978c403..af9fe9103734 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c | |||
@@ -381,6 +381,18 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, | |||
381 | method_obj->method.next_object); | 381 | method_obj->method.next_object); |
382 | type = acpi_ns_get_type(parent_node); | 382 | type = acpi_ns_get_type(parent_node); |
383 | 383 | ||
384 | /* | ||
385 | * Get the region handler and save it in the method object. We may need | ||
386 | * this if an operation region declaration causes a _REG method to be run. | ||
387 | * | ||
388 | * We can't do this in acpi_ps_link_module_code because | ||
389 | * acpi_gbl_root_node->Object is NULL at PASS1. | ||
390 | */ | ||
391 | if ((type == ACPI_TYPE_DEVICE) && parent_node->object) { | ||
392 | method_obj->method.extra.handler = | ||
393 | parent_node->object->device.handler; | ||
394 | } | ||
395 | |||
384 | /* Must clear next_object (acpi_ns_attach_object needs the field) */ | 396 | /* Must clear next_object (acpi_ns_attach_object needs the field) */ |
385 | 397 | ||
386 | method_obj->method.next_object = NULL; | 398 | method_obj->method.next_object = NULL; |
@@ -415,6 +427,12 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, | |||
415 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", | 427 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", |
416 | method_obj->method.aml_start)); | 428 | method_obj->method.aml_start)); |
417 | 429 | ||
430 | /* Delete a possible implicit return value (in slack mode) */ | ||
431 | |||
432 | if (info->return_object) { | ||
433 | acpi_ut_remove_reference(info->return_object); | ||
434 | } | ||
435 | |||
418 | /* Detach the temporary method object */ | 436 | /* Detach the temporary method object */ |
419 | 437 | ||
420 | acpi_ns_detach_object(parent_node); | 438 | acpi_ns_detach_object(parent_node); |
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index af8e6bcee07e..8f9a4875ce26 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c | |||
@@ -232,7 +232,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, | |||
232 | 232 | ||
233 | ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); | 233 | ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); |
234 | 234 | ||
235 | node = acpi_ns_map_handle_to_node(target_handle); | 235 | node = acpi_ns_validate_handle(target_handle); |
236 | if (!node) { | 236 | if (!node) { |
237 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 237 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
238 | } | 238 | } |
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index b05f42903c86..d34fa59548f7 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c | |||
@@ -216,29 +216,38 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, | |||
216 | data->pathname = pathname; | 216 | data->pathname = pathname; |
217 | 217 | ||
218 | /* | 218 | /* |
219 | * Check that the type of the return object is what is expected for | 219 | * Check that the type of the main return object is what is expected |
220 | * this predefined name | 220 | * for this predefined name |
221 | */ | 221 | */ |
222 | status = acpi_ns_check_object_type(data, return_object_ptr, | 222 | status = acpi_ns_check_object_type(data, return_object_ptr, |
223 | predefined->info.expected_btypes, | 223 | predefined->info.expected_btypes, |
224 | ACPI_NOT_PACKAGE_ELEMENT); | 224 | ACPI_NOT_PACKAGE_ELEMENT); |
225 | if (ACPI_FAILURE(status)) { | 225 | if (ACPI_FAILURE(status)) { |
226 | goto check_validation_status; | 226 | goto exit; |
227 | } | 227 | } |
228 | 228 | ||
229 | /* For returned Package objects, check the type of all sub-objects */ | 229 | /* |
230 | 230 | * For returned Package objects, check the type of all sub-objects. | |
231 | if (return_object->common.type == ACPI_TYPE_PACKAGE) { | 231 | * Note: Package may have been newly created by call above. |
232 | */ | ||
233 | if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) { | ||
232 | status = acpi_ns_check_package(data, return_object_ptr); | 234 | status = acpi_ns_check_package(data, return_object_ptr); |
235 | if (ACPI_FAILURE(status)) { | ||
236 | goto exit; | ||
237 | } | ||
233 | } | 238 | } |
234 | 239 | ||
235 | /* | 240 | /* |
236 | * Perform additional, more complicated repairs on a per-name | 241 | * The return object was OK, or it was successfully repaired above. |
237 | * basis. | 242 | * Now make some additional checks such as verifying that package |
243 | * objects are sorted correctly (if required) or buffer objects have | ||
244 | * the correct data width (bytes vs. dwords). These repairs are | ||
245 | * performed on a per-name basis, i.e., the code is specific to | ||
246 | * particular predefined names. | ||
238 | */ | 247 | */ |
239 | status = acpi_ns_complex_repairs(data, node, status, return_object_ptr); | 248 | status = acpi_ns_complex_repairs(data, node, status, return_object_ptr); |
240 | 249 | ||
241 | check_validation_status: | 250 | exit: |
242 | /* | 251 | /* |
243 | * If the object validation failed or if we successfully repaired one | 252 | * If the object validation failed or if we successfully repaired one |
244 | * or more objects, mark the parent node to suppress further warning | 253 | * or more objects, mark the parent node to suppress further warning |
@@ -427,6 +436,13 @@ acpi_ns_check_package(struct acpi_predefined_data *data, | |||
427 | data->pathname, package->ret_info.type, | 436 | data->pathname, package->ret_info.type, |
428 | return_object->package.count)); | 437 | return_object->package.count)); |
429 | 438 | ||
439 | /* | ||
440 | * For variable-length Packages, we can safely remove all embedded | ||
441 | * and trailing NULL package elements | ||
442 | */ | ||
443 | acpi_ns_remove_null_elements(data, package->ret_info.type, | ||
444 | return_object); | ||
445 | |||
430 | /* Extract package count and elements array */ | 446 | /* Extract package count and elements array */ |
431 | 447 | ||
432 | elements = return_object->package.elements; | 448 | elements = return_object->package.elements; |
@@ -461,11 +477,11 @@ acpi_ns_check_package(struct acpi_predefined_data *data, | |||
461 | if (count < expected_count) { | 477 | if (count < expected_count) { |
462 | goto package_too_small; | 478 | goto package_too_small; |
463 | } else if (count > expected_count) { | 479 | } else if (count > expected_count) { |
464 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, | 480 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
465 | data->node_flags, | 481 | "%s: Return Package is larger than needed - " |
466 | "Return Package is larger than needed - " | 482 | "found %u, expected %u\n", |
467 | "found %u, expected %u", count, | 483 | data->pathname, count, |
468 | expected_count)); | 484 | expected_count)); |
469 | } | 485 | } |
470 | 486 | ||
471 | /* Validate all elements of the returned package */ | 487 | /* Validate all elements of the returned package */ |
@@ -680,53 +696,18 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, | |||
680 | union acpi_operand_object *sub_package; | 696 | union acpi_operand_object *sub_package; |
681 | union acpi_operand_object **sub_elements; | 697 | union acpi_operand_object **sub_elements; |
682 | acpi_status status; | 698 | acpi_status status; |
683 | u8 non_trailing_null = FALSE; | ||
684 | u32 expected_count; | 699 | u32 expected_count; |
685 | u32 i; | 700 | u32 i; |
686 | u32 j; | 701 | u32 j; |
687 | 702 | ||
688 | /* Validate each sub-Package in the parent Package */ | 703 | /* |
689 | 704 | * Validate each sub-Package in the parent Package | |
705 | * | ||
706 | * NOTE: assumes list of sub-packages contains no NULL elements. | ||
707 | * Any NULL elements should have been removed by earlier call | ||
708 | * to acpi_ns_remove_null_elements. | ||
709 | */ | ||
690 | for (i = 0; i < count; i++) { | 710 | for (i = 0; i < count; i++) { |
691 | /* | ||
692 | * Handling for NULL package elements. For now, we will simply allow | ||
693 | * a parent package with trailing NULL elements. This can happen if | ||
694 | * the package was defined to be longer than the initializer list. | ||
695 | * This is legal as per the ACPI specification. It is often used | ||
696 | * to allow for dynamic initialization of a Package. | ||
697 | * | ||
698 | * A future enhancement may be to simply truncate the package to | ||
699 | * remove the trailing NULL elements. | ||
700 | */ | ||
701 | if (!(*elements)) { | ||
702 | if (!non_trailing_null) { | ||
703 | |||
704 | /* Ensure the remaining elements are all NULL */ | ||
705 | |||
706 | for (j = 1; j < (count - i + 1); j++) { | ||
707 | if (elements[j]) { | ||
708 | non_trailing_null = TRUE; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | if (!non_trailing_null) { | ||
713 | |||
714 | /* Ignore the trailing NULL elements */ | ||
715 | |||
716 | return (AE_OK); | ||
717 | } | ||
718 | } | ||
719 | |||
720 | /* There are trailing non-null elements, issue warning */ | ||
721 | |||
722 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, | ||
723 | data->node_flags, | ||
724 | "Found NULL element at package index %u", | ||
725 | i)); | ||
726 | elements++; | ||
727 | continue; | ||
728 | } | ||
729 | |||
730 | sub_package = *elements; | 711 | sub_package = *elements; |
731 | sub_elements = sub_package->package.elements; | 712 | sub_elements = sub_package->package.elements; |
732 | 713 | ||
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index d563f1a564a7..4fd1bdb056b2 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c | |||
@@ -45,13 +45,52 @@ | |||
45 | #include "accommon.h" | 45 | #include "accommon.h" |
46 | #include "acnamesp.h" | 46 | #include "acnamesp.h" |
47 | #include "acinterp.h" | 47 | #include "acinterp.h" |
48 | #include "acpredef.h" | ||
49 | 48 | ||
50 | #define _COMPONENT ACPI_NAMESPACE | 49 | #define _COMPONENT ACPI_NAMESPACE |
51 | ACPI_MODULE_NAME("nsrepair") | 50 | ACPI_MODULE_NAME("nsrepair") |
52 | 51 | ||
53 | /******************************************************************************* | 52 | /******************************************************************************* |
54 | * | 53 | * |
54 | * This module attempts to repair or convert objects returned by the | ||
55 | * predefined methods to an object type that is expected, as per the ACPI | ||
56 | * specification. The need for this code is dictated by the many machines that | ||
57 | * return incorrect types for the standard predefined methods. Performing these | ||
58 | * conversions here, in one place, eliminates the need for individual ACPI | ||
59 | * device drivers to do the same. Note: Most of these conversions are different | ||
60 | * than the internal object conversion routines used for implicit object | ||
61 | * conversion. | ||
62 | * | ||
63 | * The following conversions can be performed as necessary: | ||
64 | * | ||
65 | * Integer -> String | ||
66 | * Integer -> Buffer | ||
67 | * String -> Integer | ||
68 | * String -> Buffer | ||
69 | * Buffer -> Integer | ||
70 | * Buffer -> String | ||
71 | * Buffer -> Package of Integers | ||
72 | * Package -> Package of one Package | ||
73 | * | ||
74 | ******************************************************************************/ | ||
75 | /* Local prototypes */ | ||
76 | static acpi_status | ||
77 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, | ||
78 | union acpi_operand_object **return_object); | ||
79 | |||
80 | static acpi_status | ||
81 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, | ||
82 | union acpi_operand_object **return_object); | ||
83 | |||
84 | static acpi_status | ||
85 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, | ||
86 | union acpi_operand_object **return_object); | ||
87 | |||
88 | static acpi_status | ||
89 | acpi_ns_convert_to_package(union acpi_operand_object *original_object, | ||
90 | union acpi_operand_object **return_object); | ||
91 | |||
92 | /******************************************************************************* | ||
93 | * | ||
55 | * FUNCTION: acpi_ns_repair_object | 94 | * FUNCTION: acpi_ns_repair_object |
56 | * | 95 | * |
57 | * PARAMETERS: Data - Pointer to validation data structure | 96 | * PARAMETERS: Data - Pointer to validation data structure |
@@ -68,6 +107,7 @@ ACPI_MODULE_NAME("nsrepair") | |||
68 | * not expected. | 107 | * not expected. |
69 | * | 108 | * |
70 | ******************************************************************************/ | 109 | ******************************************************************************/ |
110 | |||
71 | acpi_status | 111 | acpi_status |
72 | acpi_ns_repair_object(struct acpi_predefined_data *data, | 112 | acpi_ns_repair_object(struct acpi_predefined_data *data, |
73 | u32 expected_btypes, | 113 | u32 expected_btypes, |
@@ -76,32 +116,206 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, | |||
76 | { | 116 | { |
77 | union acpi_operand_object *return_object = *return_object_ptr; | 117 | union acpi_operand_object *return_object = *return_object_ptr; |
78 | union acpi_operand_object *new_object; | 118 | union acpi_operand_object *new_object; |
79 | acpi_size length; | ||
80 | acpi_status status; | 119 | acpi_status status; |
81 | 120 | ||
121 | ACPI_FUNCTION_NAME(ns_repair_object); | ||
122 | |||
82 | /* | 123 | /* |
83 | * At this point, we know that the type of the returned object was not | 124 | * At this point, we know that the type of the returned object was not |
84 | * one of the expected types for this predefined name. Attempt to | 125 | * one of the expected types for this predefined name. Attempt to |
85 | * repair the object. Only a limited number of repairs are possible. | 126 | * repair the object by converting it to one of the expected object |
127 | * types for this predefined name. | ||
86 | */ | 128 | */ |
87 | switch (return_object->common.type) { | 129 | if (expected_btypes & ACPI_RTYPE_INTEGER) { |
130 | status = acpi_ns_convert_to_integer(return_object, &new_object); | ||
131 | if (ACPI_SUCCESS(status)) { | ||
132 | goto object_repaired; | ||
133 | } | ||
134 | } | ||
135 | if (expected_btypes & ACPI_RTYPE_STRING) { | ||
136 | status = acpi_ns_convert_to_string(return_object, &new_object); | ||
137 | if (ACPI_SUCCESS(status)) { | ||
138 | goto object_repaired; | ||
139 | } | ||
140 | } | ||
141 | if (expected_btypes & ACPI_RTYPE_BUFFER) { | ||
142 | status = acpi_ns_convert_to_buffer(return_object, &new_object); | ||
143 | if (ACPI_SUCCESS(status)) { | ||
144 | goto object_repaired; | ||
145 | } | ||
146 | } | ||
147 | if (expected_btypes & ACPI_RTYPE_PACKAGE) { | ||
148 | status = acpi_ns_convert_to_package(return_object, &new_object); | ||
149 | if (ACPI_SUCCESS(status)) { | ||
150 | goto object_repaired; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* We cannot repair this object */ | ||
155 | |||
156 | return (AE_AML_OPERAND_TYPE); | ||
157 | |||
158 | object_repaired: | ||
159 | |||
160 | /* Object was successfully repaired */ | ||
161 | |||
162 | /* | ||
163 | * If the original object is a package element, we need to: | ||
164 | * 1. Set the reference count of the new object to match the | ||
165 | * reference count of the old object. | ||
166 | * 2. Decrement the reference count of the original object. | ||
167 | */ | ||
168 | if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { | ||
169 | new_object->common.reference_count = | ||
170 | return_object->common.reference_count; | ||
171 | |||
172 | if (return_object->common.reference_count > 1) { | ||
173 | return_object->common.reference_count--; | ||
174 | } | ||
175 | |||
176 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
177 | "%s: Converted %s to expected %s at index %u\n", | ||
178 | data->pathname, | ||
179 | acpi_ut_get_object_type_name(return_object), | ||
180 | acpi_ut_get_object_type_name(new_object), | ||
181 | package_index)); | ||
182 | } else { | ||
183 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
184 | "%s: Converted %s to expected %s\n", | ||
185 | data->pathname, | ||
186 | acpi_ut_get_object_type_name(return_object), | ||
187 | acpi_ut_get_object_type_name(new_object))); | ||
188 | } | ||
189 | |||
190 | /* Delete old object, install the new return object */ | ||
191 | |||
192 | acpi_ut_remove_reference(return_object); | ||
193 | *return_object_ptr = new_object; | ||
194 | data->flags |= ACPI_OBJECT_REPAIRED; | ||
195 | return (AE_OK); | ||
196 | } | ||
197 | |||
198 | /******************************************************************************* | ||
199 | * | ||
200 | * FUNCTION: acpi_ns_convert_to_integer | ||
201 | * | ||
202 | * PARAMETERS: original_object - Object to be converted | ||
203 | * return_object - Where the new converted object is returned | ||
204 | * | ||
205 | * RETURN: Status. AE_OK if conversion was successful. | ||
206 | * | ||
207 | * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. | ||
208 | * | ||
209 | ******************************************************************************/ | ||
210 | |||
211 | static acpi_status | ||
212 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, | ||
213 | union acpi_operand_object **return_object) | ||
214 | { | ||
215 | union acpi_operand_object *new_object; | ||
216 | acpi_status status; | ||
217 | u64 value = 0; | ||
218 | u32 i; | ||
219 | |||
220 | switch (original_object->common.type) { | ||
221 | case ACPI_TYPE_STRING: | ||
222 | |||
223 | /* String-to-Integer conversion */ | ||
224 | |||
225 | status = acpi_ut_strtoul64(original_object->string.pointer, | ||
226 | ACPI_ANY_BASE, &value); | ||
227 | if (ACPI_FAILURE(status)) { | ||
228 | return (status); | ||
229 | } | ||
230 | break; | ||
231 | |||
88 | case ACPI_TYPE_BUFFER: | 232 | case ACPI_TYPE_BUFFER: |
89 | 233 | ||
90 | /* Does the method/object legally return a string? */ | 234 | /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ |
91 | 235 | ||
92 | if (!(expected_btypes & ACPI_RTYPE_STRING)) { | 236 | if (original_object->buffer.length > 8) { |
93 | return (AE_AML_OPERAND_TYPE); | 237 | return (AE_AML_OPERAND_TYPE); |
94 | } | 238 | } |
95 | 239 | ||
240 | /* Extract each buffer byte to create the integer */ | ||
241 | |||
242 | for (i = 0; i < original_object->buffer.length; i++) { | ||
243 | value |= | ||
244 | ((u64) original_object->buffer. | ||
245 | pointer[i] << (i * 8)); | ||
246 | } | ||
247 | break; | ||
248 | |||
249 | default: | ||
250 | return (AE_AML_OPERAND_TYPE); | ||
251 | } | ||
252 | |||
253 | new_object = acpi_ut_create_integer_object(value); | ||
254 | if (!new_object) { | ||
255 | return (AE_NO_MEMORY); | ||
256 | } | ||
257 | |||
258 | *return_object = new_object; | ||
259 | return (AE_OK); | ||
260 | } | ||
261 | |||
262 | /******************************************************************************* | ||
263 | * | ||
264 | * FUNCTION: acpi_ns_convert_to_string | ||
265 | * | ||
266 | * PARAMETERS: original_object - Object to be converted | ||
267 | * return_object - Where the new converted object is returned | ||
268 | * | ||
269 | * RETURN: Status. AE_OK if conversion was successful. | ||
270 | * | ||
271 | * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. | ||
272 | * | ||
273 | ******************************************************************************/ | ||
274 | |||
275 | static acpi_status | ||
276 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, | ||
277 | union acpi_operand_object **return_object) | ||
278 | { | ||
279 | union acpi_operand_object *new_object; | ||
280 | acpi_size length; | ||
281 | acpi_status status; | ||
282 | |||
283 | switch (original_object->common.type) { | ||
284 | case ACPI_TYPE_INTEGER: | ||
285 | /* | ||
286 | * Integer-to-String conversion. Commonly, convert | ||
287 | * an integer of value 0 to a NULL string. The last element of | ||
288 | * _BIF and _BIX packages occasionally need this fix. | ||
289 | */ | ||
290 | if (original_object->integer.value == 0) { | ||
291 | |||
292 | /* Allocate a new NULL string object */ | ||
293 | |||
294 | new_object = acpi_ut_create_string_object(0); | ||
295 | if (!new_object) { | ||
296 | return (AE_NO_MEMORY); | ||
297 | } | ||
298 | } else { | ||
299 | status = | ||
300 | acpi_ex_convert_to_string(original_object, | ||
301 | &new_object, | ||
302 | ACPI_IMPLICIT_CONVERT_HEX); | ||
303 | if (ACPI_FAILURE(status)) { | ||
304 | return (status); | ||
305 | } | ||
306 | } | ||
307 | break; | ||
308 | |||
309 | case ACPI_TYPE_BUFFER: | ||
96 | /* | 310 | /* |
97 | * Have a Buffer, expected a String, convert. Use a to_string | 311 | * Buffer-to-String conversion. Use a to_string |
98 | * conversion, no transform performed on the buffer data. The best | 312 | * conversion, no transform performed on the buffer data. The best |
99 | * example of this is the _BIF method, where the string data from | 313 | * example of this is the _BIF method, where the string data from |
100 | * the battery is often (incorrectly) returned as buffer object(s). | 314 | * the battery is often (incorrectly) returned as buffer object(s). |
101 | */ | 315 | */ |
102 | length = 0; | 316 | length = 0; |
103 | while ((length < return_object->buffer.length) && | 317 | while ((length < original_object->buffer.length) && |
104 | (return_object->buffer.pointer[length])) { | 318 | (original_object->buffer.pointer[length])) { |
105 | length++; | 319 | length++; |
106 | } | 320 | } |
107 | 321 | ||
@@ -117,94 +331,176 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, | |||
117 | * terminated at Length+1. | 331 | * terminated at Length+1. |
118 | */ | 332 | */ |
119 | ACPI_MEMCPY(new_object->string.pointer, | 333 | ACPI_MEMCPY(new_object->string.pointer, |
120 | return_object->buffer.pointer, length); | 334 | original_object->buffer.pointer, length); |
121 | break; | 335 | break; |
122 | 336 | ||
337 | default: | ||
338 | return (AE_AML_OPERAND_TYPE); | ||
339 | } | ||
340 | |||
341 | *return_object = new_object; | ||
342 | return (AE_OK); | ||
343 | } | ||
344 | |||
345 | /******************************************************************************* | ||
346 | * | ||
347 | * FUNCTION: acpi_ns_convert_to_buffer | ||
348 | * | ||
349 | * PARAMETERS: original_object - Object to be converted | ||
350 | * return_object - Where the new converted object is returned | ||
351 | * | ||
352 | * RETURN: Status. AE_OK if conversion was successful. | ||
353 | * | ||
354 | * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. | ||
355 | * | ||
356 | ******************************************************************************/ | ||
357 | |||
358 | static acpi_status | ||
359 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, | ||
360 | union acpi_operand_object **return_object) | ||
361 | { | ||
362 | union acpi_operand_object *new_object; | ||
363 | acpi_status status; | ||
364 | union acpi_operand_object **elements; | ||
365 | u32 *dword_buffer; | ||
366 | u32 count; | ||
367 | u32 i; | ||
368 | |||
369 | switch (original_object->common.type) { | ||
123 | case ACPI_TYPE_INTEGER: | 370 | case ACPI_TYPE_INTEGER: |
371 | /* | ||
372 | * Integer-to-Buffer conversion. | ||
373 | * Convert the Integer to a packed-byte buffer. _MAT and other | ||
374 | * objects need this sometimes, if a read has been performed on a | ||
375 | * Field object that is less than or equal to the global integer | ||
376 | * size (32 or 64 bits). | ||
377 | */ | ||
378 | status = | ||
379 | acpi_ex_convert_to_buffer(original_object, &new_object); | ||
380 | if (ACPI_FAILURE(status)) { | ||
381 | return (status); | ||
382 | } | ||
383 | break; | ||
124 | 384 | ||
125 | /* 1) Does the method/object legally return a buffer? */ | 385 | case ACPI_TYPE_STRING: |
126 | 386 | ||
127 | if (expected_btypes & ACPI_RTYPE_BUFFER) { | 387 | /* String-to-Buffer conversion. Simple data copy */ |
128 | /* | 388 | |
129 | * Convert the Integer to a packed-byte buffer. _MAT needs | 389 | new_object = |
130 | * this sometimes, if a read has been performed on a Field | 390 | acpi_ut_create_buffer_object(original_object->string. |
131 | * object that is less than or equal to the global integer | 391 | length); |
132 | * size (32 or 64 bits). | 392 | if (!new_object) { |
133 | */ | 393 | return (AE_NO_MEMORY); |
134 | status = | ||
135 | acpi_ex_convert_to_buffer(return_object, | ||
136 | &new_object); | ||
137 | if (ACPI_FAILURE(status)) { | ||
138 | return (status); | ||
139 | } | ||
140 | } | 394 | } |
141 | 395 | ||
142 | /* 2) Does the method/object legally return a string? */ | 396 | ACPI_MEMCPY(new_object->buffer.pointer, |
397 | original_object->string.pointer, | ||
398 | original_object->string.length); | ||
399 | break; | ||
400 | |||
401 | case ACPI_TYPE_PACKAGE: | ||
402 | /* | ||
403 | * This case is often seen for predefined names that must return a | ||
404 | * Buffer object with multiple DWORD integers within. For example, | ||
405 | * _FDE and _GTM. The Package can be converted to a Buffer. | ||
406 | */ | ||
407 | |||
408 | /* All elements of the Package must be integers */ | ||
143 | 409 | ||
144 | else if (expected_btypes & ACPI_RTYPE_STRING) { | 410 | elements = original_object->package.elements; |
145 | /* | 411 | count = original_object->package.count; |
146 | * The only supported Integer-to-String conversion is to convert | 412 | |
147 | * an integer of value 0 to a NULL string. The last element of | 413 | for (i = 0; i < count; i++) { |
148 | * _BIF and _BIX packages occasionally need this fix. | 414 | if ((!*elements) || |
149 | */ | 415 | ((*elements)->common.type != ACPI_TYPE_INTEGER)) { |
150 | if (return_object->integer.value != 0) { | ||
151 | return (AE_AML_OPERAND_TYPE); | 416 | return (AE_AML_OPERAND_TYPE); |
152 | } | 417 | } |
418 | elements++; | ||
419 | } | ||
153 | 420 | ||
154 | /* Allocate a new NULL string object */ | 421 | /* Create the new buffer object to replace the Package */ |
155 | 422 | ||
156 | new_object = acpi_ut_create_string_object(0); | 423 | new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count)); |
157 | if (!new_object) { | 424 | if (!new_object) { |
158 | return (AE_NO_MEMORY); | 425 | return (AE_NO_MEMORY); |
159 | } | ||
160 | } else { | ||
161 | return (AE_AML_OPERAND_TYPE); | ||
162 | } | 426 | } |
163 | break; | ||
164 | 427 | ||
165 | default: | 428 | /* Copy the package elements (integers) to the buffer as DWORDs */ |
166 | 429 | ||
167 | /* We cannot repair this object */ | 430 | elements = original_object->package.elements; |
431 | dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer); | ||
432 | |||
433 | for (i = 0; i < count; i++) { | ||
434 | *dword_buffer = (u32) (*elements)->integer.value; | ||
435 | dword_buffer++; | ||
436 | elements++; | ||
437 | } | ||
438 | break; | ||
168 | 439 | ||
440 | default: | ||
169 | return (AE_AML_OPERAND_TYPE); | 441 | return (AE_AML_OPERAND_TYPE); |
170 | } | 442 | } |
171 | 443 | ||
172 | /* Object was successfully repaired */ | 444 | *return_object = new_object; |
445 | return (AE_OK); | ||
446 | } | ||
173 | 447 | ||
174 | /* | 448 | /******************************************************************************* |
175 | * If the original object is a package element, we need to: | 449 | * |
176 | * 1. Set the reference count of the new object to match the | 450 | * FUNCTION: acpi_ns_convert_to_package |
177 | * reference count of the old object. | 451 | * |
178 | * 2. Decrement the reference count of the original object. | 452 | * PARAMETERS: original_object - Object to be converted |
179 | */ | 453 | * return_object - Where the new converted object is returned |
180 | if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { | 454 | * |
181 | new_object->common.reference_count = | 455 | * RETURN: Status. AE_OK if conversion was successful. |
182 | return_object->common.reference_count; | 456 | * |
457 | * DESCRIPTION: Attempt to convert a Buffer object to a Package. Each byte of | ||
458 | * the buffer is converted to a single integer package element. | ||
459 | * | ||
460 | ******************************************************************************/ | ||
183 | 461 | ||
184 | if (return_object->common.reference_count > 1) { | 462 | static acpi_status |
185 | return_object->common.reference_count--; | 463 | acpi_ns_convert_to_package(union acpi_operand_object *original_object, |
464 | union acpi_operand_object **return_object) | ||
465 | { | ||
466 | union acpi_operand_object *new_object; | ||
467 | union acpi_operand_object **elements; | ||
468 | u32 length; | ||
469 | u8 *buffer; | ||
470 | |||
471 | switch (original_object->common.type) { | ||
472 | case ACPI_TYPE_BUFFER: | ||
473 | |||
474 | /* Buffer-to-Package conversion */ | ||
475 | |||
476 | length = original_object->buffer.length; | ||
477 | new_object = acpi_ut_create_package_object(length); | ||
478 | if (!new_object) { | ||
479 | return (AE_NO_MEMORY); | ||
186 | } | 480 | } |
187 | 481 | ||
188 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | 482 | /* Convert each buffer byte to an integer package element */ |
189 | "Converted %s to expected %s at index %u", | ||
190 | acpi_ut_get_object_type_name | ||
191 | (return_object), | ||
192 | acpi_ut_get_object_type_name(new_object), | ||
193 | package_index)); | ||
194 | } else { | ||
195 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | ||
196 | "Converted %s to expected %s", | ||
197 | acpi_ut_get_object_type_name | ||
198 | (return_object), | ||
199 | acpi_ut_get_object_type_name | ||
200 | (new_object))); | ||
201 | } | ||
202 | 483 | ||
203 | /* Delete old object, install the new return object */ | 484 | elements = new_object->package.elements; |
485 | buffer = original_object->buffer.pointer; | ||
204 | 486 | ||
205 | acpi_ut_remove_reference(return_object); | 487 | while (length--) { |
206 | *return_object_ptr = new_object; | 488 | *elements = |
207 | data->flags |= ACPI_OBJECT_REPAIRED; | 489 | acpi_ut_create_integer_object((u64) *buffer); |
490 | if (!*elements) { | ||
491 | acpi_ut_remove_reference(new_object); | ||
492 | return (AE_NO_MEMORY); | ||
493 | } | ||
494 | elements++; | ||
495 | buffer++; | ||
496 | } | ||
497 | break; | ||
498 | |||
499 | default: | ||
500 | return (AE_AML_OPERAND_TYPE); | ||
501 | } | ||
502 | |||
503 | *return_object = new_object; | ||
208 | return (AE_OK); | 504 | return (AE_OK); |
209 | } | 505 | } |
210 | 506 | ||
@@ -238,6 +534,8 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, | |||
238 | { | 534 | { |
239 | union acpi_operand_object *pkg_obj_desc; | 535 | union acpi_operand_object *pkg_obj_desc; |
240 | 536 | ||
537 | ACPI_FUNCTION_NAME(ns_repair_package_list); | ||
538 | |||
241 | /* | 539 | /* |
242 | * Create the new outer package and populate it. The new package will | 540 | * Create the new outer package and populate it. The new package will |
243 | * have a single element, the lone subpackage. | 541 | * have a single element, the lone subpackage. |
@@ -254,8 +552,9 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, | |||
254 | *obj_desc_ptr = pkg_obj_desc; | 552 | *obj_desc_ptr = pkg_obj_desc; |
255 | data->flags |= ACPI_OBJECT_REPAIRED; | 553 | data->flags |= ACPI_OBJECT_REPAIRED; |
256 | 554 | ||
257 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | 555 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
258 | "Repaired Incorrectly formed Package")); | 556 | "%s: Repaired incorrectly formed Package\n", |
557 | data->pathname)); | ||
259 | 558 | ||
260 | return (AE_OK); | 559 | return (AE_OK); |
261 | } | 560 | } |
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index d07b68613818..f13691c1cca5 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <acpi/acpi.h> | 45 | #include <acpi/acpi.h> |
46 | #include "accommon.h" | 46 | #include "accommon.h" |
47 | #include "acnamesp.h" | 47 | #include "acnamesp.h" |
48 | #include "acpredef.h" | ||
48 | 49 | ||
49 | #define _COMPONENT ACPI_NAMESPACE | 50 | #define _COMPONENT ACPI_NAMESPACE |
50 | ACPI_MODULE_NAME("nsrepair2") | 51 | ACPI_MODULE_NAME("nsrepair2") |
@@ -74,6 +75,10 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data, | |||
74 | union acpi_operand_object **return_object_ptr); | 75 | union acpi_operand_object **return_object_ptr); |
75 | 76 | ||
76 | static acpi_status | 77 | static acpi_status |
78 | acpi_ns_repair_FDE(struct acpi_predefined_data *data, | ||
79 | union acpi_operand_object **return_object_ptr); | ||
80 | |||
81 | static acpi_status | ||
77 | acpi_ns_repair_PSS(struct acpi_predefined_data *data, | 82 | acpi_ns_repair_PSS(struct acpi_predefined_data *data, |
78 | union acpi_operand_object **return_object_ptr); | 83 | union acpi_operand_object **return_object_ptr); |
79 | 84 | ||
@@ -89,9 +94,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
89 | u8 sort_direction, char *sort_key_name); | 94 | u8 sort_direction, char *sort_key_name); |
90 | 95 | ||
91 | static acpi_status | 96 | static acpi_status |
92 | acpi_ns_remove_null_elements(union acpi_operand_object *package); | ||
93 | |||
94 | static acpi_status | ||
95 | acpi_ns_sort_list(union acpi_operand_object **elements, | 97 | acpi_ns_sort_list(union acpi_operand_object **elements, |
96 | u32 count, u32 index, u8 sort_direction); | 98 | u32 count, u32 index, u8 sort_direction); |
97 | 99 | ||
@@ -104,17 +106,27 @@ acpi_ns_sort_list(union acpi_operand_object **elements, | |||
104 | * This table contains the names of the predefined methods for which we can | 106 | * This table contains the names of the predefined methods for which we can |
105 | * perform more complex repairs. | 107 | * perform more complex repairs. |
106 | * | 108 | * |
107 | * _ALR: Sort the list ascending by ambient_illuminance if necessary | 109 | * As necessary: |
108 | * _PSS: Sort the list descending by Power if necessary | 110 | * |
109 | * _TSS: Sort the list descending by Power if necessary | 111 | * _ALR: Sort the list ascending by ambient_illuminance |
112 | * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs | ||
113 | * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs | ||
114 | * _PSS: Sort the list descending by Power | ||
115 | * _TSS: Sort the list descending by Power | ||
110 | */ | 116 | */ |
111 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { | 117 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { |
112 | {"_ALR", acpi_ns_repair_ALR}, | 118 | {"_ALR", acpi_ns_repair_ALR}, |
119 | {"_FDE", acpi_ns_repair_FDE}, | ||
120 | {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ | ||
113 | {"_PSS", acpi_ns_repair_PSS}, | 121 | {"_PSS", acpi_ns_repair_PSS}, |
114 | {"_TSS", acpi_ns_repair_TSS}, | 122 | {"_TSS", acpi_ns_repair_TSS}, |
115 | {{0, 0, 0, 0}, NULL} /* Table terminator */ | 123 | {{0, 0, 0, 0}, NULL} /* Table terminator */ |
116 | }; | 124 | }; |
117 | 125 | ||
126 | #define ACPI_FDE_FIELD_COUNT 5 | ||
127 | #define ACPI_FDE_BYTE_BUFFER_SIZE 5 | ||
128 | #define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32)) | ||
129 | |||
118 | /****************************************************************************** | 130 | /****************************************************************************** |
119 | * | 131 | * |
120 | * FUNCTION: acpi_ns_complex_repairs | 132 | * FUNCTION: acpi_ns_complex_repairs |
@@ -215,6 +227,94 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data, | |||
215 | 227 | ||
216 | /****************************************************************************** | 228 | /****************************************************************************** |
217 | * | 229 | * |
230 | * FUNCTION: acpi_ns_repair_FDE | ||
231 | * | ||
232 | * PARAMETERS: Data - Pointer to validation data structure | ||
233 | * return_object_ptr - Pointer to the object returned from the | ||
234 | * evaluation of a method or object | ||
235 | * | ||
236 | * RETURN: Status. AE_OK if object is OK or was repaired successfully | ||
237 | * | ||
238 | * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return | ||
239 | * value is a Buffer of 5 DWORDs. This function repairs a common | ||
240 | * problem where the return value is a Buffer of BYTEs, not | ||
241 | * DWORDs. | ||
242 | * | ||
243 | *****************************************************************************/ | ||
244 | |||
245 | static acpi_status | ||
246 | acpi_ns_repair_FDE(struct acpi_predefined_data *data, | ||
247 | union acpi_operand_object **return_object_ptr) | ||
248 | { | ||
249 | union acpi_operand_object *return_object = *return_object_ptr; | ||
250 | union acpi_operand_object *buffer_object; | ||
251 | u8 *byte_buffer; | ||
252 | u32 *dword_buffer; | ||
253 | u32 i; | ||
254 | |||
255 | ACPI_FUNCTION_NAME(ns_repair_FDE); | ||
256 | |||
257 | switch (return_object->common.type) { | ||
258 | case ACPI_TYPE_BUFFER: | ||
259 | |||
260 | /* This is the expected type. Length should be (at least) 5 DWORDs */ | ||
261 | |||
262 | if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) { | ||
263 | return (AE_OK); | ||
264 | } | ||
265 | |||
266 | /* We can only repair if we have exactly 5 BYTEs */ | ||
267 | |||
268 | if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) { | ||
269 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, | ||
270 | data->node_flags, | ||
271 | "Incorrect return buffer length %u, expected %u", | ||
272 | return_object->buffer.length, | ||
273 | ACPI_FDE_DWORD_BUFFER_SIZE)); | ||
274 | |||
275 | return (AE_AML_OPERAND_TYPE); | ||
276 | } | ||
277 | |||
278 | /* Create the new (larger) buffer object */ | ||
279 | |||
280 | buffer_object = | ||
281 | acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE); | ||
282 | if (!buffer_object) { | ||
283 | return (AE_NO_MEMORY); | ||
284 | } | ||
285 | |||
286 | /* Expand each byte to a DWORD */ | ||
287 | |||
288 | byte_buffer = return_object->buffer.pointer; | ||
289 | dword_buffer = | ||
290 | ACPI_CAST_PTR(u32, buffer_object->buffer.pointer); | ||
291 | |||
292 | for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) { | ||
293 | *dword_buffer = (u32) *byte_buffer; | ||
294 | dword_buffer++; | ||
295 | byte_buffer++; | ||
296 | } | ||
297 | |||
298 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
299 | "%s Expanded Byte Buffer to expected DWord Buffer\n", | ||
300 | data->pathname)); | ||
301 | break; | ||
302 | |||
303 | default: | ||
304 | return (AE_AML_OPERAND_TYPE); | ||
305 | } | ||
306 | |||
307 | /* Delete the original return object, return the new buffer object */ | ||
308 | |||
309 | acpi_ut_remove_reference(return_object); | ||
310 | *return_object_ptr = buffer_object; | ||
311 | |||
312 | data->flags |= ACPI_OBJECT_REPAIRED; | ||
313 | return (AE_OK); | ||
314 | } | ||
315 | |||
316 | /****************************************************************************** | ||
317 | * | ||
218 | * FUNCTION: acpi_ns_repair_TSS | 318 | * FUNCTION: acpi_ns_repair_TSS |
219 | * | 319 | * |
220 | * PARAMETERS: Data - Pointer to validation data structure | 320 | * PARAMETERS: Data - Pointer to validation data structure |
@@ -345,6 +445,8 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
345 | u32 previous_value; | 445 | u32 previous_value; |
346 | acpi_status status; | 446 | acpi_status status; |
347 | 447 | ||
448 | ACPI_FUNCTION_NAME(ns_check_sorted_list); | ||
449 | |||
348 | /* The top-level object must be a package */ | 450 | /* The top-level object must be a package */ |
349 | 451 | ||
350 | if (return_object->common.type != ACPI_TYPE_PACKAGE) { | 452 | if (return_object->common.type != ACPI_TYPE_PACKAGE) { |
@@ -352,24 +454,10 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
352 | } | 454 | } |
353 | 455 | ||
354 | /* | 456 | /* |
355 | * Detect any NULL package elements and remove them from the | 457 | * NOTE: assumes list of sub-packages contains no NULL elements. |
356 | * package. | 458 | * Any NULL elements should have been removed by earlier call |
357 | * | 459 | * to acpi_ns_remove_null_elements. |
358 | * TBD: We may want to do this for all predefined names that | ||
359 | * return a variable-length package of packages. | ||
360 | */ | 460 | */ |
361 | status = acpi_ns_remove_null_elements(return_object); | ||
362 | if (status == AE_NULL_ENTRY) { | ||
363 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | ||
364 | "NULL elements removed from package")); | ||
365 | |||
366 | /* Exit if package is now zero length */ | ||
367 | |||
368 | if (!return_object->package.count) { | ||
369 | return (AE_NULL_ENTRY); | ||
370 | } | ||
371 | } | ||
372 | |||
373 | outer_elements = return_object->package.elements; | 461 | outer_elements = return_object->package.elements; |
374 | outer_element_count = return_object->package.count; | 462 | outer_element_count = return_object->package.count; |
375 | if (!outer_element_count) { | 463 | if (!outer_element_count) { |
@@ -422,10 +510,9 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
422 | 510 | ||
423 | data->flags |= ACPI_OBJECT_REPAIRED; | 511 | data->flags |= ACPI_OBJECT_REPAIRED; |
424 | 512 | ||
425 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, | 513 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
426 | data->node_flags, | 514 | "%s: Repaired unsorted list - now sorted by %s\n", |
427 | "Repaired unsorted list - now sorted by %s", | 515 | data->pathname, sort_key_name)); |
428 | sort_key_name)); | ||
429 | return (AE_OK); | 516 | return (AE_OK); |
430 | } | 517 | } |
431 | 518 | ||
@@ -440,36 +527,63 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
440 | * | 527 | * |
441 | * FUNCTION: acpi_ns_remove_null_elements | 528 | * FUNCTION: acpi_ns_remove_null_elements |
442 | * | 529 | * |
443 | * PARAMETERS: obj_desc - A Package object | 530 | * PARAMETERS: Data - Pointer to validation data structure |
531 | * package_type - An acpi_return_package_types value | ||
532 | * obj_desc - A Package object | ||
444 | * | 533 | * |
445 | * RETURN: Status. AE_NULL_ENTRY means that one or more elements were | 534 | * RETURN: None. |
446 | * removed. | ||
447 | * | 535 | * |
448 | * DESCRIPTION: Remove all NULL package elements and update the package count. | 536 | * DESCRIPTION: Remove all NULL package elements from packages that contain |
537 | * a variable number of sub-packages. | ||
449 | * | 538 | * |
450 | *****************************************************************************/ | 539 | *****************************************************************************/ |
451 | 540 | ||
452 | static acpi_status | 541 | void |
453 | acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc) | 542 | acpi_ns_remove_null_elements(struct acpi_predefined_data *data, |
543 | u8 package_type, | ||
544 | union acpi_operand_object *obj_desc) | ||
454 | { | 545 | { |
455 | union acpi_operand_object **source; | 546 | union acpi_operand_object **source; |
456 | union acpi_operand_object **dest; | 547 | union acpi_operand_object **dest; |
457 | acpi_status status = AE_OK; | ||
458 | u32 count; | 548 | u32 count; |
459 | u32 new_count; | 549 | u32 new_count; |
460 | u32 i; | 550 | u32 i; |
461 | 551 | ||
552 | ACPI_FUNCTION_NAME(ns_remove_null_elements); | ||
553 | |||
554 | /* | ||
555 | * PTYPE1 packages contain no subpackages. | ||
556 | * PTYPE2 packages contain a variable number of sub-packages. We can | ||
557 | * safely remove all NULL elements from the PTYPE2 packages. | ||
558 | */ | ||
559 | switch (package_type) { | ||
560 | case ACPI_PTYPE1_FIXED: | ||
561 | case ACPI_PTYPE1_VAR: | ||
562 | case ACPI_PTYPE1_OPTION: | ||
563 | return; | ||
564 | |||
565 | case ACPI_PTYPE2: | ||
566 | case ACPI_PTYPE2_COUNT: | ||
567 | case ACPI_PTYPE2_PKG_COUNT: | ||
568 | case ACPI_PTYPE2_FIXED: | ||
569 | case ACPI_PTYPE2_MIN: | ||
570 | case ACPI_PTYPE2_REV_FIXED: | ||
571 | break; | ||
572 | |||
573 | default: | ||
574 | return; | ||
575 | } | ||
576 | |||
462 | count = obj_desc->package.count; | 577 | count = obj_desc->package.count; |
463 | new_count = count; | 578 | new_count = count; |
464 | 579 | ||
465 | source = obj_desc->package.elements; | 580 | source = obj_desc->package.elements; |
466 | dest = source; | 581 | dest = source; |
467 | 582 | ||
468 | /* Examine all elements of the package object */ | 583 | /* Examine all elements of the package object, remove nulls */ |
469 | 584 | ||
470 | for (i = 0; i < count; i++) { | 585 | for (i = 0; i < count; i++) { |
471 | if (!*source) { | 586 | if (!*source) { |
472 | status = AE_NULL_ENTRY; | ||
473 | new_count--; | 587 | new_count--; |
474 | } else { | 588 | } else { |
475 | *dest = *source; | 589 | *dest = *source; |
@@ -478,15 +592,18 @@ acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc) | |||
478 | source++; | 592 | source++; |
479 | } | 593 | } |
480 | 594 | ||
481 | if (status == AE_NULL_ENTRY) { | 595 | /* Update parent package if any null elements were removed */ |
596 | |||
597 | if (new_count < count) { | ||
598 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
599 | "%s: Found and removed %u NULL elements\n", | ||
600 | data->pathname, (count - new_count))); | ||
482 | 601 | ||
483 | /* NULL terminate list and update the package count */ | 602 | /* NULL terminate list and update the package count */ |
484 | 603 | ||
485 | *dest = NULL; | 604 | *dest = NULL; |
486 | obj_desc->package.count = new_count; | 605 | obj_desc->package.count = new_count; |
487 | } | 606 | } |
488 | |||
489 | return (status); | ||
490 | } | 607 | } |
491 | 608 | ||
492 | /****************************************************************************** | 609 | /****************************************************************************** |
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index ea55ab4f9849..47d91e668a1b 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c | |||
@@ -671,24 +671,25 @@ acpi_ns_externalize_name(u32 internal_name_length, | |||
671 | 671 | ||
672 | /******************************************************************************* | 672 | /******************************************************************************* |
673 | * | 673 | * |
674 | * FUNCTION: acpi_ns_map_handle_to_node | 674 | * FUNCTION: acpi_ns_validate_handle |
675 | * | 675 | * |
676 | * PARAMETERS: Handle - Handle to be converted to an Node | 676 | * PARAMETERS: Handle - Handle to be validated and typecast to a |
677 | * namespace node. | ||
677 | * | 678 | * |
678 | * RETURN: A Name table entry pointer | 679 | * RETURN: A pointer to a namespace node |
679 | * | 680 | * |
680 | * DESCRIPTION: Convert a namespace handle to a real Node | 681 | * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special |
682 | * cases for the root node. | ||
681 | * | 683 | * |
682 | * Note: Real integer handles would allow for more verification | 684 | * NOTE: Real integer handles would allow for more verification |
683 | * and keep all pointers within this subsystem - however this introduces | 685 | * and keep all pointers within this subsystem - however this introduces |
684 | * more (and perhaps unnecessary) overhead. | 686 | * more overhead and has not been necessary to this point. Drivers |
685 | * | 687 | * holding handles are typically notified before a node becomes invalid |
686 | * The current implemenation is basically a placeholder until such time comes | 688 | * due to a table unload. |
687 | * that it is needed. | ||
688 | * | 689 | * |
689 | ******************************************************************************/ | 690 | ******************************************************************************/ |
690 | 691 | ||
691 | struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) | 692 | struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) |
692 | { | 693 | { |
693 | 694 | ||
694 | ACPI_FUNCTION_ENTRY(); | 695 | ACPI_FUNCTION_ENTRY(); |
@@ -710,42 +711,6 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) | |||
710 | 711 | ||
711 | /******************************************************************************* | 712 | /******************************************************************************* |
712 | * | 713 | * |
713 | * FUNCTION: acpi_ns_convert_entry_to_handle | ||
714 | * | ||
715 | * PARAMETERS: Node - Node to be converted to a Handle | ||
716 | * | ||
717 | * RETURN: A user handle | ||
718 | * | ||
719 | * DESCRIPTION: Convert a real Node to a namespace handle | ||
720 | * | ||
721 | ******************************************************************************/ | ||
722 | |||
723 | acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node) | ||
724 | { | ||
725 | |||
726 | /* | ||
727 | * Simple implementation for now; | ||
728 | */ | ||
729 | return ((acpi_handle) node); | ||
730 | |||
731 | /* Example future implementation --------------------- | ||
732 | |||
733 | if (!Node) | ||
734 | { | ||
735 | return (NULL); | ||
736 | } | ||
737 | |||
738 | if (Node == acpi_gbl_root_node) | ||
739 | { | ||
740 | return (ACPI_ROOT_OBJECT); | ||
741 | } | ||
742 | |||
743 | return ((acpi_handle) Node); | ||
744 | ------------------------------------------------------*/ | ||
745 | } | ||
746 | |||
747 | /******************************************************************************* | ||
748 | * | ||
749 | * FUNCTION: acpi_ns_terminate | 714 | * FUNCTION: acpi_ns_terminate |
750 | * | 715 | * |
751 | * PARAMETERS: none | 716 | * PARAMETERS: none |
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index f2bd1da77001..f0c0892bc7e5 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c | |||
@@ -190,7 +190,7 @@ acpi_evaluate_object(acpi_handle handle, | |||
190 | 190 | ||
191 | /* Convert and validate the device handle */ | 191 | /* Convert and validate the device handle */ |
192 | 192 | ||
193 | info->prefix_node = acpi_ns_map_handle_to_node(handle); | 193 | info->prefix_node = acpi_ns_validate_handle(handle); |
194 | if (!info->prefix_node) { | 194 | if (!info->prefix_node) { |
195 | status = AE_BAD_PARAMETER; | 195 | status = AE_BAD_PARAMETER; |
196 | goto cleanup; | 196 | goto cleanup; |
@@ -552,7 +552,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, | |||
552 | return (status); | 552 | return (status); |
553 | } | 553 | } |
554 | 554 | ||
555 | node = acpi_ns_map_handle_to_node(obj_handle); | 555 | node = acpi_ns_validate_handle(obj_handle); |
556 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 556 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
557 | if (ACPI_FAILURE(status)) { | 557 | if (ACPI_FAILURE(status)) { |
558 | return (status); | 558 | return (status); |
@@ -729,7 +729,7 @@ acpi_attach_data(acpi_handle obj_handle, | |||
729 | 729 | ||
730 | /* Convert and validate the handle */ | 730 | /* Convert and validate the handle */ |
731 | 731 | ||
732 | node = acpi_ns_map_handle_to_node(obj_handle); | 732 | node = acpi_ns_validate_handle(obj_handle); |
733 | if (!node) { | 733 | if (!node) { |
734 | status = AE_BAD_PARAMETER; | 734 | status = AE_BAD_PARAMETER; |
735 | goto unlock_and_exit; | 735 | goto unlock_and_exit; |
@@ -775,7 +775,7 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) | |||
775 | 775 | ||
776 | /* Convert and validate the handle */ | 776 | /* Convert and validate the handle */ |
777 | 777 | ||
778 | node = acpi_ns_map_handle_to_node(obj_handle); | 778 | node = acpi_ns_validate_handle(obj_handle); |
779 | if (!node) { | 779 | if (!node) { |
780 | status = AE_BAD_PARAMETER; | 780 | status = AE_BAD_PARAMETER; |
781 | goto unlock_and_exit; | 781 | goto unlock_and_exit; |
@@ -822,7 +822,7 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) | |||
822 | 822 | ||
823 | /* Convert and validate the handle */ | 823 | /* Convert and validate the handle */ |
824 | 824 | ||
825 | node = acpi_ns_map_handle_to_node(obj_handle); | 825 | node = acpi_ns_validate_handle(obj_handle); |
826 | if (!node) { | 826 | if (!node) { |
827 | status = AE_BAD_PARAMETER; | 827 | status = AE_BAD_PARAMETER; |
828 | goto unlock_and_exit; | 828 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index ddc84af6336e..e611dd961b20 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c | |||
@@ -93,7 +93,7 @@ acpi_get_handle(acpi_handle parent, | |||
93 | /* Convert a parent handle to a prefix node */ | 93 | /* Convert a parent handle to a prefix node */ |
94 | 94 | ||
95 | if (parent) { | 95 | if (parent) { |
96 | prefix_node = acpi_ns_map_handle_to_node(parent); | 96 | prefix_node = acpi_ns_validate_handle(parent); |
97 | if (!prefix_node) { | 97 | if (!prefix_node) { |
98 | return (AE_BAD_PARAMETER); | 98 | return (AE_BAD_PARAMETER); |
99 | } | 99 | } |
@@ -114,7 +114,7 @@ acpi_get_handle(acpi_handle parent, | |||
114 | 114 | ||
115 | if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { | 115 | if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { |
116 | *ret_handle = | 116 | *ret_handle = |
117 | acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); | 117 | ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); |
118 | return (AE_OK); | 118 | return (AE_OK); |
119 | } | 119 | } |
120 | } else if (!prefix_node) { | 120 | } else if (!prefix_node) { |
@@ -129,7 +129,7 @@ acpi_get_handle(acpi_handle parent, | |||
129 | status = | 129 | status = |
130 | acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); | 130 | acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); |
131 | if (ACPI_SUCCESS(status)) { | 131 | if (ACPI_SUCCESS(status)) { |
132 | *ret_handle = acpi_ns_convert_entry_to_handle(node); | 132 | *ret_handle = ACPI_CAST_PTR(acpi_handle, node); |
133 | } | 133 | } |
134 | 134 | ||
135 | return (status); | 135 | return (status); |
@@ -186,7 +186,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) | |||
186 | return (status); | 186 | return (status); |
187 | } | 187 | } |
188 | 188 | ||
189 | node = acpi_ns_map_handle_to_node(handle); | 189 | node = acpi_ns_validate_handle(handle); |
190 | if (!node) { | 190 | if (!node) { |
191 | status = AE_BAD_PARAMETER; | 191 | status = AE_BAD_PARAMETER; |
192 | goto unlock_and_exit; | 192 | goto unlock_and_exit; |
@@ -291,7 +291,7 @@ acpi_get_object_info(acpi_handle handle, | |||
291 | goto cleanup; | 291 | goto cleanup; |
292 | } | 292 | } |
293 | 293 | ||
294 | node = acpi_ns_map_handle_to_node(handle); | 294 | node = acpi_ns_validate_handle(handle); |
295 | if (!node) { | 295 | if (!node) { |
296 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 296 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
297 | return (AE_BAD_PARAMETER); | 297 | return (AE_BAD_PARAMETER); |
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 4071bad4458e..0cc6ba01a495 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c | |||
@@ -79,7 +79,7 @@ acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) | |||
79 | 79 | ||
80 | /* Convert and validate the handle */ | 80 | /* Convert and validate the handle */ |
81 | 81 | ||
82 | node = acpi_ns_map_handle_to_node(handle); | 82 | node = acpi_ns_validate_handle(handle); |
83 | if (!node) { | 83 | if (!node) { |
84 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 84 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
85 | return (AE_BAD_PARAMETER); | 85 | return (AE_BAD_PARAMETER); |
@@ -132,7 +132,7 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) | |||
132 | 132 | ||
133 | /* Convert and validate the handle */ | 133 | /* Convert and validate the handle */ |
134 | 134 | ||
135 | node = acpi_ns_map_handle_to_node(handle); | 135 | node = acpi_ns_validate_handle(handle); |
136 | if (!node) { | 136 | if (!node) { |
137 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 137 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
138 | return (AE_BAD_PARAMETER); | 138 | return (AE_BAD_PARAMETER); |
@@ -182,7 +182,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) | |||
182 | 182 | ||
183 | /* Convert and validate the handle */ | 183 | /* Convert and validate the handle */ |
184 | 184 | ||
185 | node = acpi_ns_map_handle_to_node(handle); | 185 | node = acpi_ns_validate_handle(handle); |
186 | if (!node) { | 186 | if (!node) { |
187 | status = AE_BAD_PARAMETER; | 187 | status = AE_BAD_PARAMETER; |
188 | goto unlock_and_exit; | 188 | goto unlock_and_exit; |
@@ -191,7 +191,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) | |||
191 | /* Get the parent entry */ | 191 | /* Get the parent entry */ |
192 | 192 | ||
193 | parent_node = acpi_ns_get_parent_node(node); | 193 | parent_node = acpi_ns_get_parent_node(node); |
194 | *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); | 194 | *ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node); |
195 | 195 | ||
196 | /* Return exception if parent is null */ | 196 | /* Return exception if parent is null */ |
197 | 197 | ||
@@ -251,7 +251,7 @@ acpi_get_next_object(acpi_object_type type, | |||
251 | 251 | ||
252 | /* Start search at the beginning of the specified scope */ | 252 | /* Start search at the beginning of the specified scope */ |
253 | 253 | ||
254 | parent_node = acpi_ns_map_handle_to_node(parent); | 254 | parent_node = acpi_ns_validate_handle(parent); |
255 | if (!parent_node) { | 255 | if (!parent_node) { |
256 | status = AE_BAD_PARAMETER; | 256 | status = AE_BAD_PARAMETER; |
257 | goto unlock_and_exit; | 257 | goto unlock_and_exit; |
@@ -260,7 +260,7 @@ acpi_get_next_object(acpi_object_type type, | |||
260 | /* Non-null handle, ignore the parent */ | 260 | /* Non-null handle, ignore the parent */ |
261 | /* Convert and validate the handle */ | 261 | /* Convert and validate the handle */ |
262 | 262 | ||
263 | child_node = acpi_ns_map_handle_to_node(child); | 263 | child_node = acpi_ns_validate_handle(child); |
264 | if (!child_node) { | 264 | if (!child_node) { |
265 | status = AE_BAD_PARAMETER; | 265 | status = AE_BAD_PARAMETER; |
266 | goto unlock_and_exit; | 266 | goto unlock_and_exit; |
@@ -276,7 +276,7 @@ acpi_get_next_object(acpi_object_type type, | |||
276 | } | 276 | } |
277 | 277 | ||
278 | if (ret_handle) { | 278 | if (ret_handle) { |
279 | *ret_handle = acpi_ns_convert_entry_to_handle(node); | 279 | *ret_handle = ACPI_CAST_PTR(acpi_handle, node); |
280 | } | 280 | } |
281 | 281 | ||
282 | unlock_and_exit: | 282 | unlock_and_exit: |
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 12934ad6da8e..d0c1b91eb8ca 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c | |||
@@ -287,7 +287,8 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) | |||
287 | /* Invoke an internal method if necessary */ | 287 | /* Invoke an internal method if necessary */ |
288 | 288 | ||
289 | if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { | 289 | if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { |
290 | status = info->obj_desc->method.implementation(walk_state); | 290 | status = |
291 | info->obj_desc->method.extra.implementation(walk_state); | ||
291 | info->return_object = walk_state->return_desc; | 292 | info->return_object = walk_state->return_desc; |
292 | 293 | ||
293 | /* Cleanup states */ | 294 | /* Cleanup states */ |
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 395212bcd19b..f27feb4772f6 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c | |||
@@ -104,7 +104,7 @@ acpi_rs_validate_parameters(acpi_handle device_handle, | |||
104 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 104 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
105 | } | 105 | } |
106 | 106 | ||
107 | node = acpi_ns_map_handle_to_node(device_handle); | 107 | node = acpi_ns_validate_handle(device_handle); |
108 | if (!node) { | 108 | if (!node) { |
109 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 109 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
110 | } | 110 | } |
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 0f0c64bf8ac9..f857c5efb79f 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c | |||
@@ -323,11 +323,11 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type, | |||
323 | * RETURN: Status | 323 | * RETURN: Status |
324 | * | 324 | * |
325 | * DESCRIPTION: This function is called to place a package object in a user | 325 | * DESCRIPTION: This function is called to place a package object in a user |
326 | * buffer. A package object by definition contains other objects. | 326 | * buffer. A package object by definition contains other objects. |
327 | * | 327 | * |
328 | * The buffer is assumed to have sufficient space for the object. | 328 | * The buffer is assumed to have sufficient space for the object. |
329 | * The caller must have verified the buffer length needed using the | 329 | * The caller must have verified the buffer length needed using |
330 | * acpi_ut_get_object_size function before calling this function. | 330 | * the acpi_ut_get_object_size function before calling this function. |
331 | * | 331 | * |
332 | ******************************************************************************/ | 332 | ******************************************************************************/ |
333 | 333 | ||
@@ -382,12 +382,12 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, | |||
382 | * FUNCTION: acpi_ut_copy_iobject_to_eobject | 382 | * FUNCTION: acpi_ut_copy_iobject_to_eobject |
383 | * | 383 | * |
384 | * PARAMETERS: internal_object - The internal object to be converted | 384 | * PARAMETERS: internal_object - The internal object to be converted |
385 | * buffer_ptr - Where the object is returned | 385 | * ret_buffer - Where the object is returned |
386 | * | 386 | * |
387 | * RETURN: Status | 387 | * RETURN: Status |
388 | * | 388 | * |
389 | * DESCRIPTION: This function is called to build an API object to be returned to | 389 | * DESCRIPTION: This function is called to build an API object to be returned |
390 | * the caller. | 390 | * to the caller. |
391 | * | 391 | * |
392 | ******************************************************************************/ | 392 | ******************************************************************************/ |
393 | 393 | ||
@@ -626,7 +626,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, | |||
626 | * PARAMETERS: external_object - The external object to be converted | 626 | * PARAMETERS: external_object - The external object to be converted |
627 | * internal_object - Where the internal object is returned | 627 | * internal_object - Where the internal object is returned |
628 | * | 628 | * |
629 | * RETURN: Status - the status of the call | 629 | * RETURN: Status |
630 | * | 630 | * |
631 | * DESCRIPTION: Converts an external object to an internal object. | 631 | * DESCRIPTION: Converts an external object to an internal object. |
632 | * | 632 | * |
@@ -665,7 +665,7 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object, | |||
665 | * | 665 | * |
666 | * RETURN: Status | 666 | * RETURN: Status |
667 | * | 667 | * |
668 | * DESCRIPTION: Simple copy of one internal object to another. Reference count | 668 | * DESCRIPTION: Simple copy of one internal object to another. Reference count |
669 | * of the destination object is preserved. | 669 | * of the destination object is preserved. |
670 | * | 670 | * |
671 | ******************************************************************************/ | 671 | ******************************************************************************/ |
@@ -897,10 +897,11 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type, | |||
897 | * | 897 | * |
898 | * FUNCTION: acpi_ut_copy_ipackage_to_ipackage | 898 | * FUNCTION: acpi_ut_copy_ipackage_to_ipackage |
899 | * | 899 | * |
900 | * PARAMETERS: *source_obj - Pointer to the source package object | 900 | * PARAMETERS: source_obj - Pointer to the source package object |
901 | * *dest_obj - Where the internal object is returned | 901 | * dest_obj - Where the internal object is returned |
902 | * walk_state - Current Walk state descriptor | ||
902 | * | 903 | * |
903 | * RETURN: Status - the status of the call | 904 | * RETURN: Status |
904 | * | 905 | * |
905 | * DESCRIPTION: This function is called to copy an internal package object | 906 | * DESCRIPTION: This function is called to copy an internal package object |
906 | * into another internal package object. | 907 | * into another internal package object. |
@@ -953,9 +954,9 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, | |||
953 | * | 954 | * |
954 | * FUNCTION: acpi_ut_copy_iobject_to_iobject | 955 | * FUNCTION: acpi_ut_copy_iobject_to_iobject |
955 | * | 956 | * |
956 | * PARAMETERS: walk_state - Current walk state | 957 | * PARAMETERS: source_desc - The internal object to be copied |
957 | * source_desc - The internal object to be copied | ||
958 | * dest_desc - Where the copied object is returned | 958 | * dest_desc - Where the copied object is returned |
959 | * walk_state - Current walk state | ||
959 | * | 960 | * |
960 | * RETURN: Status | 961 | * RETURN: Status |
961 | * | 962 | * |
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 3f4602b8f287..cada73ffdfa7 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -831,7 +831,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) | |||
831 | dev_name(&device->dev), event, | 831 | dev_name(&device->dev), event, |
832 | acpi_battery_present(battery)); | 832 | acpi_battery_present(battery)); |
833 | #ifdef CONFIG_ACPI_SYSFS_POWER | 833 | #ifdef CONFIG_ACPI_SYSFS_POWER |
834 | /* acpi_batter_update could remove power_supply object */ | 834 | /* acpi_battery_update could remove power_supply object */ |
835 | if (battery->bat.dev) | 835 | if (battery->bat.dev) |
836 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | 836 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); |
837 | #endif | 837 | #endif |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 741191524353..65f7e335f122 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -344,6 +344,152 @@ bool acpi_bus_can_wakeup(acpi_handle handle) | |||
344 | 344 | ||
345 | EXPORT_SYMBOL(acpi_bus_can_wakeup); | 345 | EXPORT_SYMBOL(acpi_bus_can_wakeup); |
346 | 346 | ||
347 | static void acpi_print_osc_error(acpi_handle handle, | ||
348 | struct acpi_osc_context *context, char *error) | ||
349 | { | ||
350 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; | ||
351 | int i; | ||
352 | |||
353 | if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) | ||
354 | printk(KERN_DEBUG "%s\n", error); | ||
355 | else { | ||
356 | printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); | ||
357 | kfree(buffer.pointer); | ||
358 | } | ||
359 | printk(KERN_DEBUG"_OSC request data:"); | ||
360 | for (i = 0; i < context->cap.length; i += sizeof(u32)) | ||
361 | printk("%x ", *((u32 *)(context->cap.pointer + i))); | ||
362 | printk("\n"); | ||
363 | } | ||
364 | |||
365 | static u8 hex_val(unsigned char c) | ||
366 | { | ||
367 | return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; | ||
368 | } | ||
369 | |||
370 | static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) | ||
371 | { | ||
372 | int i; | ||
373 | static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, | ||
374 | 24, 26, 28, 30, 32, 34}; | ||
375 | |||
376 | if (strlen(str) != 36) | ||
377 | return AE_BAD_PARAMETER; | ||
378 | for (i = 0; i < 36; i++) { | ||
379 | if (i == 8 || i == 13 || i == 18 || i == 23) { | ||
380 | if (str[i] != '-') | ||
381 | return AE_BAD_PARAMETER; | ||
382 | } else if (!isxdigit(str[i])) | ||
383 | return AE_BAD_PARAMETER; | ||
384 | } | ||
385 | for (i = 0; i < 16; i++) { | ||
386 | uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4; | ||
387 | uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]); | ||
388 | } | ||
389 | return AE_OK; | ||
390 | } | ||
391 | |||
392 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) | ||
393 | { | ||
394 | acpi_status status; | ||
395 | struct acpi_object_list input; | ||
396 | union acpi_object in_params[4]; | ||
397 | union acpi_object *out_obj; | ||
398 | u8 uuid[16]; | ||
399 | u32 errors; | ||
400 | |||
401 | if (!context) | ||
402 | return AE_ERROR; | ||
403 | if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid))) | ||
404 | return AE_ERROR; | ||
405 | context->ret.length = ACPI_ALLOCATE_BUFFER; | ||
406 | context->ret.pointer = NULL; | ||
407 | |||
408 | /* Setting up input parameters */ | ||
409 | input.count = 4; | ||
410 | input.pointer = in_params; | ||
411 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
412 | in_params[0].buffer.length = 16; | ||
413 | in_params[0].buffer.pointer = uuid; | ||
414 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
415 | in_params[1].integer.value = context->rev; | ||
416 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
417 | in_params[2].integer.value = context->cap.length/sizeof(u32); | ||
418 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
419 | in_params[3].buffer.length = context->cap.length; | ||
420 | in_params[3].buffer.pointer = context->cap.pointer; | ||
421 | |||
422 | status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret); | ||
423 | if (ACPI_FAILURE(status)) | ||
424 | return status; | ||
425 | |||
426 | /* return buffer should have the same length as cap buffer */ | ||
427 | if (context->ret.length != context->cap.length) | ||
428 | return AE_NULL_OBJECT; | ||
429 | |||
430 | out_obj = context->ret.pointer; | ||
431 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
432 | acpi_print_osc_error(handle, context, | ||
433 | "_OSC evaluation returned wrong type"); | ||
434 | status = AE_TYPE; | ||
435 | goto out_kfree; | ||
436 | } | ||
437 | /* Need to ignore the bit0 in result code */ | ||
438 | errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); | ||
439 | if (errors) { | ||
440 | if (errors & OSC_REQUEST_ERROR) | ||
441 | acpi_print_osc_error(handle, context, | ||
442 | "_OSC request failed"); | ||
443 | if (errors & OSC_INVALID_UUID_ERROR) | ||
444 | acpi_print_osc_error(handle, context, | ||
445 | "_OSC invalid UUID"); | ||
446 | if (errors & OSC_INVALID_REVISION_ERROR) | ||
447 | acpi_print_osc_error(handle, context, | ||
448 | "_OSC invalid revision"); | ||
449 | if (errors & OSC_CAPABILITIES_MASK_ERROR) { | ||
450 | if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE] | ||
451 | & OSC_QUERY_ENABLE) | ||
452 | goto out_success; | ||
453 | status = AE_SUPPORT; | ||
454 | goto out_kfree; | ||
455 | } | ||
456 | status = AE_ERROR; | ||
457 | goto out_kfree; | ||
458 | } | ||
459 | out_success: | ||
460 | return AE_OK; | ||
461 | |||
462 | out_kfree: | ||
463 | kfree(context->ret.pointer); | ||
464 | context->ret.pointer = NULL; | ||
465 | return status; | ||
466 | } | ||
467 | EXPORT_SYMBOL(acpi_run_osc); | ||
468 | |||
469 | static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; | ||
470 | static void acpi_bus_osc_support(void) | ||
471 | { | ||
472 | u32 capbuf[2]; | ||
473 | struct acpi_osc_context context = { | ||
474 | .uuid_str = sb_uuid_str, | ||
475 | .rev = 1, | ||
476 | .cap.length = 8, | ||
477 | .cap.pointer = capbuf, | ||
478 | }; | ||
479 | acpi_handle handle; | ||
480 | |||
481 | capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | ||
482 | capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */ | ||
483 | #ifdef CONFIG_ACPI_PROCESSOR_AGGREGATOR | ||
484 | capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT; | ||
485 | #endif | ||
486 | if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) | ||
487 | return; | ||
488 | if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) | ||
489 | kfree(context.ret.pointer); | ||
490 | /* do we need to check the returned cap? Sounds no */ | ||
491 | } | ||
492 | |||
347 | /* -------------------------------------------------------------------------- | 493 | /* -------------------------------------------------------------------------- |
348 | Event Management | 494 | Event Management |
349 | -------------------------------------------------------------------------- */ | 495 | -------------------------------------------------------------------------- */ |
@@ -734,6 +880,8 @@ static int __init acpi_bus_init(void) | |||
734 | status = acpi_ec_ecdt_probe(); | 880 | status = acpi_ec_ecdt_probe(); |
735 | /* Ignore result. Not having an ECDT is not fatal. */ | 881 | /* Ignore result. Not having an ECDT is not fatal. */ |
736 | 882 | ||
883 | acpi_bus_osc_support(); | ||
884 | |||
737 | status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); | 885 | status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); |
738 | if (ACPI_FAILURE(status)) { | 886 | if (ACPI_FAILURE(status)) { |
739 | printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); | 887 | printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); |
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 0c9c6a9a002c..8a95e8329df7 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
@@ -282,6 +282,13 @@ static int acpi_lid_send_state(struct acpi_device *device) | |||
282 | if (ret == NOTIFY_DONE) | 282 | if (ret == NOTIFY_DONE) |
283 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, | 283 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, |
284 | device); | 284 | device); |
285 | if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { | ||
286 | /* | ||
287 | * It is also regarded as success if the notifier_chain | ||
288 | * returns NOTIFY_OK or NOTIFY_DONE. | ||
289 | */ | ||
290 | ret = 0; | ||
291 | } | ||
285 | return ret; | 292 | return ret; |
286 | } | 293 | } |
287 | 294 | ||
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 8a690c3b8e23..cc421b7ae166 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
11 | #include <linux/debugfs.h> | ||
11 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
12 | #include <acpi/acpi_drivers.h> | 13 | #include <acpi/acpi_drivers.h> |
13 | 14 | ||
@@ -196,6 +197,80 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state, | |||
196 | NULL, 0644); | 197 | NULL, 0644); |
197 | 198 | ||
198 | /* -------------------------------------------------------------------------- | 199 | /* -------------------------------------------------------------------------- |
200 | DebugFS Interface | ||
201 | -------------------------------------------------------------------------- */ | ||
202 | |||
203 | static ssize_t cm_write(struct file *file, const char __user *user_buf, | ||
204 | size_t count, loff_t *ppos) | ||
205 | { | ||
206 | static char *buf; | ||
207 | static int uncopied_bytes; | ||
208 | struct acpi_table_header table; | ||
209 | acpi_status status; | ||
210 | |||
211 | if (!(*ppos)) { | ||
212 | /* parse the table header to get the table length */ | ||
213 | if (count <= sizeof(struct acpi_table_header)) | ||
214 | return -EINVAL; | ||
215 | if (copy_from_user(&table, user_buf, | ||
216 | sizeof(struct acpi_table_header))) | ||
217 | return -EFAULT; | ||
218 | uncopied_bytes = table.length; | ||
219 | buf = kzalloc(uncopied_bytes, GFP_KERNEL); | ||
220 | if (!buf) | ||
221 | return -ENOMEM; | ||
222 | } | ||
223 | |||
224 | if (uncopied_bytes < count) { | ||
225 | kfree(buf); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | if (copy_from_user(buf + (*ppos), user_buf, count)) { | ||
230 | kfree(buf); | ||
231 | return -EFAULT; | ||
232 | } | ||
233 | |||
234 | uncopied_bytes -= count; | ||
235 | *ppos += count; | ||
236 | |||
237 | if (!uncopied_bytes) { | ||
238 | status = acpi_install_method(buf); | ||
239 | kfree(buf); | ||
240 | if (ACPI_FAILURE(status)) | ||
241 | return -EINVAL; | ||
242 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); | ||
243 | } | ||
244 | |||
245 | return count; | ||
246 | } | ||
247 | |||
248 | static const struct file_operations cm_fops = { | ||
249 | .write = cm_write, | ||
250 | }; | ||
251 | |||
252 | static int acpi_debugfs_init(void) | ||
253 | { | ||
254 | struct dentry *acpi_dir, *cm_dentry; | ||
255 | |||
256 | acpi_dir = debugfs_create_dir("acpi", NULL); | ||
257 | if (!acpi_dir) | ||
258 | goto err; | ||
259 | |||
260 | cm_dentry = debugfs_create_file("custom_method", S_IWUGO, | ||
261 | acpi_dir, NULL, &cm_fops); | ||
262 | if (!cm_dentry) | ||
263 | goto err; | ||
264 | |||
265 | return 0; | ||
266 | |||
267 | err: | ||
268 | if (acpi_dir) | ||
269 | debugfs_remove(acpi_dir); | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | |||
273 | /* -------------------------------------------------------------------------- | ||
199 | FS Interface (/proc) | 274 | FS Interface (/proc) |
200 | -------------------------------------------------------------------------- */ | 275 | -------------------------------------------------------------------------- */ |
201 | #ifdef CONFIG_ACPI_PROCFS | 276 | #ifdef CONFIG_ACPI_PROCFS |
@@ -286,7 +361,7 @@ static const struct file_operations acpi_system_debug_proc_fops = { | |||
286 | }; | 361 | }; |
287 | #endif | 362 | #endif |
288 | 363 | ||
289 | int __init acpi_debug_init(void) | 364 | int __init acpi_procfs_init(void) |
290 | { | 365 | { |
291 | #ifdef CONFIG_ACPI_PROCFS | 366 | #ifdef CONFIG_ACPI_PROCFS |
292 | struct proc_dir_entry *entry; | 367 | struct proc_dir_entry *entry; |
@@ -321,3 +396,10 @@ int __init acpi_debug_init(void) | |||
321 | return 0; | 396 | return 0; |
322 | #endif | 397 | #endif |
323 | } | 398 | } |
399 | |||
400 | int __init acpi_debug_init(void) | ||
401 | { | ||
402 | acpi_debugfs_init(); | ||
403 | acpi_procfs_init(); | ||
404 | return 0; | ||
405 | } | ||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 30be3c148f7e..bbc2c1315c47 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -50,7 +50,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " | |||
50 | " before undocking"); | 50 | " before undocking"); |
51 | 51 | ||
52 | static struct atomic_notifier_head dock_notifier_list; | 52 | static struct atomic_notifier_head dock_notifier_list; |
53 | static char dock_device_name[] = "dock"; | ||
54 | 53 | ||
55 | static const struct acpi_device_id dock_device_ids[] = { | 54 | static const struct acpi_device_id dock_device_ids[] = { |
56 | {"LNXDOCK", 0}, | 55 | {"LNXDOCK", 0}, |
@@ -93,40 +92,30 @@ struct dock_dependent_device { | |||
93 | * Dock Dependent device functions * | 92 | * Dock Dependent device functions * |
94 | *****************************************************************************/ | 93 | *****************************************************************************/ |
95 | /** | 94 | /** |
96 | * alloc_dock_dependent_device - allocate and init a dependent device | 95 | * add_dock_dependent_device - associate a device with the dock station |
97 | * @handle: the acpi_handle of the dependent device | 96 | * @ds: The dock station |
97 | * @handle: handle of the dependent device | ||
98 | * | 98 | * |
99 | * Allocate memory for a dependent device structure for a device referenced | 99 | * Add the dependent device to the dock's dependent device list. |
100 | * by the acpi handle | ||
101 | */ | 100 | */ |
102 | static struct dock_dependent_device * | 101 | static int |
103 | alloc_dock_dependent_device(acpi_handle handle) | 102 | add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) |
104 | { | 103 | { |
105 | struct dock_dependent_device *dd; | 104 | struct dock_dependent_device *dd; |
106 | 105 | ||
107 | dd = kzalloc(sizeof(*dd), GFP_KERNEL); | 106 | dd = kzalloc(sizeof(*dd), GFP_KERNEL); |
108 | if (dd) { | 107 | if (!dd) |
109 | dd->handle = handle; | 108 | return -ENOMEM; |
110 | INIT_LIST_HEAD(&dd->list); | 109 | |
111 | INIT_LIST_HEAD(&dd->hotplug_list); | 110 | dd->handle = handle; |
112 | } | 111 | INIT_LIST_HEAD(&dd->list); |
113 | return dd; | 112 | INIT_LIST_HEAD(&dd->hotplug_list); |
114 | } | ||
115 | 113 | ||
116 | /** | ||
117 | * add_dock_dependent_device - associate a device with the dock station | ||
118 | * @ds: The dock station | ||
119 | * @dd: The dependent device | ||
120 | * | ||
121 | * Add the dependent device to the dock's dependent device list. | ||
122 | */ | ||
123 | static void | ||
124 | add_dock_dependent_device(struct dock_station *ds, | ||
125 | struct dock_dependent_device *dd) | ||
126 | { | ||
127 | spin_lock(&ds->dd_lock); | 114 | spin_lock(&ds->dd_lock); |
128 | list_add_tail(&dd->list, &ds->dependent_devices); | 115 | list_add_tail(&dd->list, &ds->dependent_devices); |
129 | spin_unlock(&ds->dd_lock); | 116 | spin_unlock(&ds->dd_lock); |
117 | |||
118 | return 0; | ||
130 | } | 119 | } |
131 | 120 | ||
132 | /** | 121 | /** |
@@ -249,6 +238,7 @@ static int is_battery(acpi_handle handle) | |||
249 | static int is_ejectable_bay(acpi_handle handle) | 238 | static int is_ejectable_bay(acpi_handle handle) |
250 | { | 239 | { |
251 | acpi_handle phandle; | 240 | acpi_handle phandle; |
241 | |||
252 | if (!is_ejectable(handle)) | 242 | if (!is_ejectable(handle)) |
253 | return 0; | 243 | return 0; |
254 | if (is_battery(handle) || is_ata(handle)) | 244 | if (is_battery(handle) || is_ata(handle)) |
@@ -275,14 +265,13 @@ int is_dock_device(acpi_handle handle) | |||
275 | 265 | ||
276 | if (is_dock(handle)) | 266 | if (is_dock(handle)) |
277 | return 1; | 267 | return 1; |
278 | list_for_each_entry(dock_station, &dock_stations, sibling) { | 268 | |
269 | list_for_each_entry(dock_station, &dock_stations, sibling) | ||
279 | if (find_dock_dependent_device(dock_station, handle)) | 270 | if (find_dock_dependent_device(dock_station, handle)) |
280 | return 1; | 271 | return 1; |
281 | } | ||
282 | 272 | ||
283 | return 0; | 273 | return 0; |
284 | } | 274 | } |
285 | |||
286 | EXPORT_SYMBOL_GPL(is_dock_device); | 275 | EXPORT_SYMBOL_GPL(is_dock_device); |
287 | 276 | ||
288 | /** | 277 | /** |
@@ -305,8 +294,6 @@ static int dock_present(struct dock_station *ds) | |||
305 | return 0; | 294 | return 0; |
306 | } | 295 | } |
307 | 296 | ||
308 | |||
309 | |||
310 | /** | 297 | /** |
311 | * dock_create_acpi_device - add new devices to acpi | 298 | * dock_create_acpi_device - add new devices to acpi |
312 | * @handle - handle of the device to add | 299 | * @handle - handle of the device to add |
@@ -320,7 +307,7 @@ static int dock_present(struct dock_station *ds) | |||
320 | */ | 307 | */ |
321 | static struct acpi_device * dock_create_acpi_device(acpi_handle handle) | 308 | static struct acpi_device * dock_create_acpi_device(acpi_handle handle) |
322 | { | 309 | { |
323 | struct acpi_device *device = NULL; | 310 | struct acpi_device *device; |
324 | struct acpi_device *parent_device; | 311 | struct acpi_device *parent_device; |
325 | acpi_handle parent; | 312 | acpi_handle parent; |
326 | int ret; | 313 | int ret; |
@@ -337,8 +324,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) | |||
337 | ret = acpi_bus_add(&device, parent_device, handle, | 324 | ret = acpi_bus_add(&device, parent_device, handle, |
338 | ACPI_BUS_TYPE_DEVICE); | 325 | ACPI_BUS_TYPE_DEVICE); |
339 | if (ret) { | 326 | if (ret) { |
340 | pr_debug("error adding bus, %x\n", | 327 | pr_debug("error adding bus, %x\n", -ret); |
341 | -ret); | ||
342 | return NULL; | 328 | return NULL; |
343 | } | 329 | } |
344 | } | 330 | } |
@@ -364,7 +350,6 @@ static void dock_remove_acpi_device(acpi_handle handle) | |||
364 | } | 350 | } |
365 | } | 351 | } |
366 | 352 | ||
367 | |||
368 | /** | 353 | /** |
369 | * hotplug_dock_devices - insert or remove devices on the dock station | 354 | * hotplug_dock_devices - insert or remove devices on the dock station |
370 | * @ds: the dock station | 355 | * @ds: the dock station |
@@ -384,10 +369,9 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
384 | /* | 369 | /* |
385 | * First call driver specific hotplug functions | 370 | * First call driver specific hotplug functions |
386 | */ | 371 | */ |
387 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { | 372 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) |
388 | if (dd->ops && dd->ops->handler) | 373 | if (dd->ops && dd->ops->handler) |
389 | dd->ops->handler(dd->handle, event, dd->context); | 374 | dd->ops->handler(dd->handle, event, dd->context); |
390 | } | ||
391 | 375 | ||
392 | /* | 376 | /* |
393 | * Now make sure that an acpi_device is created for each | 377 | * Now make sure that an acpi_device is created for each |
@@ -426,6 +410,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num) | |||
426 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) | 410 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) |
427 | if (dd->ops && dd->ops->uevent) | 411 | if (dd->ops && dd->ops->uevent) |
428 | dd->ops->uevent(dd->handle, event, dd->context); | 412 | dd->ops->uevent(dd->handle, event, dd->context); |
413 | |||
429 | if (num != DOCK_EVENT) | 414 | if (num != DOCK_EVENT) |
430 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | 415 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); |
431 | } | 416 | } |
@@ -456,8 +441,8 @@ static void eject_dock(struct dock_station *ds) | |||
456 | arg.type = ACPI_TYPE_INTEGER; | 441 | arg.type = ACPI_TYPE_INTEGER; |
457 | arg.integer.value = 1; | 442 | arg.integer.value = 1; |
458 | 443 | ||
459 | if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", | 444 | status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL); |
460 | &arg_list, NULL))) | 445 | if (ACPI_FAILURE(status)) |
461 | pr_debug("Failed to evaluate _EJ0!\n"); | 446 | pr_debug("Failed to evaluate _EJ0!\n"); |
462 | } | 447 | } |
463 | 448 | ||
@@ -577,7 +562,6 @@ int register_dock_notifier(struct notifier_block *nb) | |||
577 | 562 | ||
578 | return atomic_notifier_chain_register(&dock_notifier_list, nb); | 563 | return atomic_notifier_chain_register(&dock_notifier_list, nb); |
579 | } | 564 | } |
580 | |||
581 | EXPORT_SYMBOL_GPL(register_dock_notifier); | 565 | EXPORT_SYMBOL_GPL(register_dock_notifier); |
582 | 566 | ||
583 | /** | 567 | /** |
@@ -591,7 +575,6 @@ void unregister_dock_notifier(struct notifier_block *nb) | |||
591 | 575 | ||
592 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); | 576 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); |
593 | } | 577 | } |
594 | |||
595 | EXPORT_SYMBOL_GPL(unregister_dock_notifier); | 578 | EXPORT_SYMBOL_GPL(unregister_dock_notifier); |
596 | 579 | ||
597 | /** | 580 | /** |
@@ -636,7 +619,6 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, | |||
636 | 619 | ||
637 | return ret; | 620 | return ret; |
638 | } | 621 | } |
639 | |||
640 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); | 622 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); |
641 | 623 | ||
642 | /** | 624 | /** |
@@ -657,7 +639,6 @@ void unregister_hotplug_dock_device(acpi_handle handle) | |||
657 | dock_del_hotplug_device(dock_station, dd); | 639 | dock_del_hotplug_device(dock_station, dd); |
658 | } | 640 | } |
659 | } | 641 | } |
660 | |||
661 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | 642 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); |
662 | 643 | ||
663 | /** | 644 | /** |
@@ -772,7 +753,7 @@ struct dock_data { | |||
772 | 753 | ||
773 | static void acpi_dock_deferred_cb(void *context) | 754 | static void acpi_dock_deferred_cb(void *context) |
774 | { | 755 | { |
775 | struct dock_data *data = (struct dock_data *)context; | 756 | struct dock_data *data = context; |
776 | 757 | ||
777 | dock_notify(data->handle, data->event, data->ds); | 758 | dock_notify(data->handle, data->event, data->ds); |
778 | kfree(data); | 759 | kfree(data); |
@@ -782,23 +763,22 @@ static int acpi_dock_notifier_call(struct notifier_block *this, | |||
782 | unsigned long event, void *data) | 763 | unsigned long event, void *data) |
783 | { | 764 | { |
784 | struct dock_station *dock_station; | 765 | struct dock_station *dock_station; |
785 | acpi_handle handle = (acpi_handle)data; | 766 | acpi_handle handle = data; |
786 | 767 | ||
787 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK | 768 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK |
788 | && event != ACPI_NOTIFY_EJECT_REQUEST) | 769 | && event != ACPI_NOTIFY_EJECT_REQUEST) |
789 | return 0; | 770 | return 0; |
790 | list_for_each_entry(dock_station, &dock_stations, sibling) { | 771 | list_for_each_entry(dock_station, &dock_stations, sibling) { |
791 | if (dock_station->handle == handle) { | 772 | if (dock_station->handle == handle) { |
792 | struct dock_data *dock_data; | 773 | struct dock_data *dd; |
793 | 774 | ||
794 | dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); | 775 | dd = kmalloc(sizeof(*dd), GFP_KERNEL); |
795 | if (!dock_data) | 776 | if (!dd) |
796 | return 0; | 777 | return 0; |
797 | dock_data->handle = handle; | 778 | dd->handle = handle; |
798 | dock_data->event = event; | 779 | dd->event = event; |
799 | dock_data->ds = dock_station; | 780 | dd->ds = dock_station; |
800 | acpi_os_hotplug_execute(acpi_dock_deferred_cb, | 781 | acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd); |
801 | dock_data); | ||
802 | return 0 ; | 782 | return 0 ; |
803 | } | 783 | } |
804 | } | 784 | } |
@@ -826,7 +806,6 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
826 | acpi_status status; | 806 | acpi_status status; |
827 | acpi_handle tmp, parent; | 807 | acpi_handle tmp, parent; |
828 | struct dock_station *ds = context; | 808 | struct dock_station *ds = context; |
829 | struct dock_dependent_device *dd; | ||
830 | 809 | ||
831 | status = acpi_bus_get_ejd(handle, &tmp); | 810 | status = acpi_bus_get_ejd(handle, &tmp); |
832 | if (ACPI_FAILURE(status)) { | 811 | if (ACPI_FAILURE(status)) { |
@@ -840,11 +819,9 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
840 | goto fdd_out; | 819 | goto fdd_out; |
841 | } | 820 | } |
842 | 821 | ||
843 | if (tmp == ds->handle) { | 822 | if (tmp == ds->handle) |
844 | dd = alloc_dock_dependent_device(handle); | 823 | add_dock_dependent_device(ds, handle); |
845 | if (dd) | 824 | |
846 | add_dock_dependent_device(ds, dd); | ||
847 | } | ||
848 | fdd_out: | 825 | fdd_out: |
849 | return AE_OK; | 826 | return AE_OK; |
850 | } | 827 | } |
@@ -857,8 +834,7 @@ static ssize_t show_docked(struct device *dev, | |||
857 | { | 834 | { |
858 | struct acpi_device *tmp; | 835 | struct acpi_device *tmp; |
859 | 836 | ||
860 | struct dock_station *dock_station = *((struct dock_station **) | 837 | struct dock_station *dock_station = dev->platform_data; |
861 | dev->platform_data); | ||
862 | 838 | ||
863 | if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp))) | 839 | if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp))) |
864 | return snprintf(buf, PAGE_SIZE, "1\n"); | 840 | return snprintf(buf, PAGE_SIZE, "1\n"); |
@@ -872,8 +848,7 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | |||
872 | static ssize_t show_flags(struct device *dev, | 848 | static ssize_t show_flags(struct device *dev, |
873 | struct device_attribute *attr, char *buf) | 849 | struct device_attribute *attr, char *buf) |
874 | { | 850 | { |
875 | struct dock_station *dock_station = *((struct dock_station **) | 851 | struct dock_station *dock_station = dev->platform_data; |
876 | dev->platform_data); | ||
877 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); | 852 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); |
878 | 853 | ||
879 | } | 854 | } |
@@ -886,8 +861,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, | |||
886 | const char *buf, size_t count) | 861 | const char *buf, size_t count) |
887 | { | 862 | { |
888 | int ret; | 863 | int ret; |
889 | struct dock_station *dock_station = *((struct dock_station **) | 864 | struct dock_station *dock_station = dev->platform_data; |
890 | dev->platform_data); | ||
891 | 865 | ||
892 | if (!count) | 866 | if (!count) |
893 | return -EINVAL; | 867 | return -EINVAL; |
@@ -905,8 +879,7 @@ static ssize_t show_dock_uid(struct device *dev, | |||
905 | struct device_attribute *attr, char *buf) | 879 | struct device_attribute *attr, char *buf) |
906 | { | 880 | { |
907 | unsigned long long lbuf; | 881 | unsigned long long lbuf; |
908 | struct dock_station *dock_station = *((struct dock_station **) | 882 | struct dock_station *dock_station = dev->platform_data; |
909 | dev->platform_data); | ||
910 | acpi_status status = acpi_evaluate_integer(dock_station->handle, | 883 | acpi_status status = acpi_evaluate_integer(dock_station->handle, |
911 | "_UID", NULL, &lbuf); | 884 | "_UID", NULL, &lbuf); |
912 | if (ACPI_FAILURE(status)) | 885 | if (ACPI_FAILURE(status)) |
@@ -919,8 +892,7 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); | |||
919 | static ssize_t show_dock_type(struct device *dev, | 892 | static ssize_t show_dock_type(struct device *dev, |
920 | struct device_attribute *attr, char *buf) | 893 | struct device_attribute *attr, char *buf) |
921 | { | 894 | { |
922 | struct dock_station *dock_station = *((struct dock_station **) | 895 | struct dock_station *dock_station = dev->platform_data; |
923 | dev->platform_data); | ||
924 | char *type; | 896 | char *type; |
925 | 897 | ||
926 | if (dock_station->flags & DOCK_IS_DOCK) | 898 | if (dock_station->flags & DOCK_IS_DOCK) |
@@ -936,6 +908,19 @@ static ssize_t show_dock_type(struct device *dev, | |||
936 | } | 908 | } |
937 | static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); | 909 | static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); |
938 | 910 | ||
911 | static struct attribute *dock_attributes[] = { | ||
912 | &dev_attr_docked.attr, | ||
913 | &dev_attr_flags.attr, | ||
914 | &dev_attr_undock.attr, | ||
915 | &dev_attr_uid.attr, | ||
916 | &dev_attr_type.attr, | ||
917 | NULL | ||
918 | }; | ||
919 | |||
920 | static struct attribute_group dock_attribute_group = { | ||
921 | .attrs = dock_attributes | ||
922 | }; | ||
923 | |||
939 | /** | 924 | /** |
940 | * dock_add - add a new dock station | 925 | * dock_add - add a new dock station |
941 | * @handle: the dock station handle | 926 | * @handle: the dock station handle |
@@ -945,39 +930,30 @@ static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); | |||
945 | */ | 930 | */ |
946 | static int dock_add(acpi_handle handle) | 931 | static int dock_add(acpi_handle handle) |
947 | { | 932 | { |
948 | int ret; | 933 | int ret, id; |
949 | struct dock_dependent_device *dd; | 934 | struct dock_station ds, *dock_station; |
950 | struct dock_station *dock_station; | 935 | struct platform_device *dd; |
951 | struct platform_device *dock_device; | 936 | |
937 | id = dock_station_count; | ||
938 | dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds)); | ||
939 | if (IS_ERR(dd)) | ||
940 | return PTR_ERR(dd); | ||
941 | |||
942 | dock_station = dd->dev.platform_data; | ||
952 | 943 | ||
953 | /* allocate & initialize the dock_station private data */ | ||
954 | dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); | ||
955 | if (!dock_station) | ||
956 | return -ENOMEM; | ||
957 | dock_station->handle = handle; | 944 | dock_station->handle = handle; |
945 | dock_station->dock_device = dd; | ||
958 | dock_station->last_dock_time = jiffies - HZ; | 946 | dock_station->last_dock_time = jiffies - HZ; |
959 | INIT_LIST_HEAD(&dock_station->dependent_devices); | 947 | |
960 | INIT_LIST_HEAD(&dock_station->hotplug_devices); | ||
961 | INIT_LIST_HEAD(&dock_station->sibling); | ||
962 | spin_lock_init(&dock_station->dd_lock); | ||
963 | mutex_init(&dock_station->hp_lock); | 948 | mutex_init(&dock_station->hp_lock); |
949 | spin_lock_init(&dock_station->dd_lock); | ||
950 | INIT_LIST_HEAD(&dock_station->sibling); | ||
951 | INIT_LIST_HEAD(&dock_station->hotplug_devices); | ||
964 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); | 952 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); |
965 | 953 | INIT_LIST_HEAD(&dock_station->dependent_devices); | |
966 | /* initialize platform device stuff */ | ||
967 | dock_station->dock_device = | ||
968 | platform_device_register_simple(dock_device_name, | ||
969 | dock_station_count, NULL, 0); | ||
970 | dock_device = dock_station->dock_device; | ||
971 | if (IS_ERR(dock_device)) { | ||
972 | kfree(dock_station); | ||
973 | dock_station = NULL; | ||
974 | return PTR_ERR(dock_device); | ||
975 | } | ||
976 | platform_device_add_data(dock_device, &dock_station, | ||
977 | sizeof(struct dock_station *)); | ||
978 | 954 | ||
979 | /* we want the dock device to send uevents */ | 955 | /* we want the dock device to send uevents */ |
980 | dev_set_uevent_suppress(&dock_device->dev, 0); | 956 | dev_set_uevent_suppress(&dd->dev, 0); |
981 | 957 | ||
982 | if (is_dock(handle)) | 958 | if (is_dock(handle)) |
983 | dock_station->flags |= DOCK_IS_DOCK; | 959 | dock_station->flags |= DOCK_IS_DOCK; |
@@ -986,47 +962,9 @@ static int dock_add(acpi_handle handle) | |||
986 | if (is_battery(handle)) | 962 | if (is_battery(handle)) |
987 | dock_station->flags |= DOCK_IS_BAT; | 963 | dock_station->flags |= DOCK_IS_BAT; |
988 | 964 | ||
989 | ret = device_create_file(&dock_device->dev, &dev_attr_docked); | 965 | ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); |
990 | if (ret) { | ||
991 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
992 | platform_device_unregister(dock_device); | ||
993 | kfree(dock_station); | ||
994 | dock_station = NULL; | ||
995 | return ret; | ||
996 | } | ||
997 | ret = device_create_file(&dock_device->dev, &dev_attr_undock); | ||
998 | if (ret) { | ||
999 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
1000 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
1001 | platform_device_unregister(dock_device); | ||
1002 | kfree(dock_station); | ||
1003 | dock_station = NULL; | ||
1004 | return ret; | ||
1005 | } | ||
1006 | ret = device_create_file(&dock_device->dev, &dev_attr_uid); | ||
1007 | if (ret) { | ||
1008 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
1009 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
1010 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
1011 | platform_device_unregister(dock_device); | ||
1012 | kfree(dock_station); | ||
1013 | dock_station = NULL; | ||
1014 | return ret; | ||
1015 | } | ||
1016 | ret = device_create_file(&dock_device->dev, &dev_attr_flags); | ||
1017 | if (ret) { | ||
1018 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
1019 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
1020 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
1021 | device_remove_file(&dock_device->dev, &dev_attr_uid); | ||
1022 | platform_device_unregister(dock_device); | ||
1023 | kfree(dock_station); | ||
1024 | dock_station = NULL; | ||
1025 | return ret; | ||
1026 | } | ||
1027 | ret = device_create_file(&dock_device->dev, &dev_attr_type); | ||
1028 | if (ret) | 966 | if (ret) |
1029 | printk(KERN_ERR"Error %d adding sysfs file\n", ret); | 967 | goto err_unregister; |
1030 | 968 | ||
1031 | /* Find dependent devices */ | 969 | /* Find dependent devices */ |
1032 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 970 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
@@ -1034,58 +972,43 @@ static int dock_add(acpi_handle handle) | |||
1034 | dock_station, NULL); | 972 | dock_station, NULL); |
1035 | 973 | ||
1036 | /* add the dock station as a device dependent on itself */ | 974 | /* add the dock station as a device dependent on itself */ |
1037 | dd = alloc_dock_dependent_device(handle); | 975 | ret = add_dock_dependent_device(dock_station, handle); |
1038 | if (!dd) { | 976 | if (ret) |
1039 | kfree(dock_station); | 977 | goto err_rmgroup; |
1040 | dock_station = NULL; | ||
1041 | ret = -ENOMEM; | ||
1042 | goto dock_add_err_unregister; | ||
1043 | } | ||
1044 | add_dock_dependent_device(dock_station, dd); | ||
1045 | 978 | ||
1046 | dock_station_count++; | 979 | dock_station_count++; |
1047 | list_add(&dock_station->sibling, &dock_stations); | 980 | list_add(&dock_station->sibling, &dock_stations); |
1048 | return 0; | 981 | return 0; |
1049 | 982 | ||
1050 | dock_add_err_unregister: | 983 | err_rmgroup: |
1051 | device_remove_file(&dock_device->dev, &dev_attr_type); | 984 | sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); |
1052 | device_remove_file(&dock_device->dev, &dev_attr_docked); | 985 | err_unregister: |
1053 | device_remove_file(&dock_device->dev, &dev_attr_undock); | 986 | platform_device_unregister(dd); |
1054 | device_remove_file(&dock_device->dev, &dev_attr_uid); | 987 | printk(KERN_ERR "%s encountered error %d\n", __func__, ret); |
1055 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
1056 | platform_device_unregister(dock_device); | ||
1057 | kfree(dock_station); | ||
1058 | dock_station = NULL; | ||
1059 | return ret; | 988 | return ret; |
1060 | } | 989 | } |
1061 | 990 | ||
1062 | /** | 991 | /** |
1063 | * dock_remove - free up resources related to the dock station | 992 | * dock_remove - free up resources related to the dock station |
1064 | */ | 993 | */ |
1065 | static int dock_remove(struct dock_station *dock_station) | 994 | static int dock_remove(struct dock_station *ds) |
1066 | { | 995 | { |
1067 | struct dock_dependent_device *dd, *tmp; | 996 | struct dock_dependent_device *dd, *tmp; |
1068 | struct platform_device *dock_device = dock_station->dock_device; | 997 | struct platform_device *dock_device = ds->dock_device; |
1069 | 998 | ||
1070 | if (!dock_station_count) | 999 | if (!dock_station_count) |
1071 | return 0; | 1000 | return 0; |
1072 | 1001 | ||
1073 | /* remove dependent devices */ | 1002 | /* remove dependent devices */ |
1074 | list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, | 1003 | list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list) |
1075 | list) | 1004 | kfree(dd); |
1076 | kfree(dd); | 1005 | |
1006 | list_del(&ds->sibling); | ||
1077 | 1007 | ||
1078 | /* cleanup sysfs */ | 1008 | /* cleanup sysfs */ |
1079 | device_remove_file(&dock_device->dev, &dev_attr_type); | 1009 | sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group); |
1080 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
1081 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
1082 | device_remove_file(&dock_device->dev, &dev_attr_uid); | ||
1083 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
1084 | platform_device_unregister(dock_device); | 1010 | platform_device_unregister(dock_device); |
1085 | 1011 | ||
1086 | /* free dock station memory */ | ||
1087 | kfree(dock_station); | ||
1088 | dock_station = NULL; | ||
1089 | return 0; | 1012 | return 0; |
1090 | } | 1013 | } |
1091 | 1014 | ||
@@ -1103,11 +1026,10 @@ find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
1103 | { | 1026 | { |
1104 | acpi_status status = AE_OK; | 1027 | acpi_status status = AE_OK; |
1105 | 1028 | ||
1106 | if (is_dock(handle)) { | 1029 | if (is_dock(handle)) |
1107 | if (dock_add(handle) >= 0) { | 1030 | if (dock_add(handle) >= 0) |
1108 | status = AE_CTRL_TERMINATE; | 1031 | status = AE_CTRL_TERMINATE; |
1109 | } | 1032 | |
1110 | } | ||
1111 | return status; | 1033 | return status; |
1112 | } | 1034 | } |
1113 | 1035 | ||
@@ -1145,8 +1067,7 @@ static int __init dock_init(void) | |||
1145 | 1067 | ||
1146 | static void __exit dock_exit(void) | 1068 | static void __exit dock_exit(void) |
1147 | { | 1069 | { |
1148 | struct dock_station *dock_station; | 1070 | struct dock_station *tmp, *dock_station; |
1149 | struct dock_station *tmp; | ||
1150 | 1071 | ||
1151 | unregister_acpi_bus_notifier(&dock_acpi_notifier); | 1072 | unregister_acpi_bus_notifier(&dock_acpi_notifier); |
1152 | list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling) | 1073 | list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling) |
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index f419849a0d3f..acf2ab249842 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
@@ -267,7 +267,7 @@ static int acpi_fan_add(struct acpi_device *device) | |||
267 | goto end; | 267 | goto end; |
268 | } | 268 | } |
269 | 269 | ||
270 | dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id); | 270 | dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id); |
271 | 271 | ||
272 | device->driver_data = cdev; | 272 | device->driver_data = cdev; |
273 | result = sysfs_create_link(&device->dev.kobj, | 273 | result = sysfs_create_link(&device->dev.kobj, |
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 2be2fb66204e..7ad48dfc12db 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
31 | #include <linux/numa.h> | ||
31 | #include <acpi/acpi_bus.h> | 32 | #include <acpi/acpi_bus.h> |
32 | 33 | ||
33 | #define PREFIX "ACPI: " | 34 | #define PREFIX "ACPI: " |
@@ -40,14 +41,14 @@ static nodemask_t nodes_found_map = NODE_MASK_NONE; | |||
40 | 41 | ||
41 | /* maps to convert between proximity domain and logical node ID */ | 42 | /* maps to convert between proximity domain and logical node ID */ |
42 | static int pxm_to_node_map[MAX_PXM_DOMAINS] | 43 | static int pxm_to_node_map[MAX_PXM_DOMAINS] |
43 | = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; | 44 | = { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE }; |
44 | static int node_to_pxm_map[MAX_NUMNODES] | 45 | static int node_to_pxm_map[MAX_NUMNODES] |
45 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; | 46 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; |
46 | 47 | ||
47 | int pxm_to_node(int pxm) | 48 | int pxm_to_node(int pxm) |
48 | { | 49 | { |
49 | if (pxm < 0) | 50 | if (pxm < 0) |
50 | return NID_INVAL; | 51 | return NUMA_NO_NODE; |
51 | return pxm_to_node_map[pxm]; | 52 | return pxm_to_node_map[pxm]; |
52 | } | 53 | } |
53 | 54 | ||
@@ -68,9 +69,9 @@ int acpi_map_pxm_to_node(int pxm) | |||
68 | { | 69 | { |
69 | int node = pxm_to_node_map[pxm]; | 70 | int node = pxm_to_node_map[pxm]; |
70 | 71 | ||
71 | if (node < 0){ | 72 | if (node < 0) { |
72 | if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) | 73 | if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) |
73 | return NID_INVAL; | 74 | return NUMA_NO_NODE; |
74 | node = first_unset_node(nodes_found_map); | 75 | node = first_unset_node(nodes_found_map); |
75 | __acpi_map_pxm_to_node(pxm, node); | 76 | __acpi_map_pxm_to_node(pxm, node); |
76 | node_set(node, nodes_found_map); | 77 | node_set(node, nodes_found_map); |
@@ -79,16 +80,6 @@ int acpi_map_pxm_to_node(int pxm) | |||
79 | return node; | 80 | return node; |
80 | } | 81 | } |
81 | 82 | ||
82 | #if 0 | ||
83 | void __cpuinit acpi_unmap_pxm_to_node(int node) | ||
84 | { | ||
85 | int pxm = node_to_pxm_map[node]; | ||
86 | pxm_to_node_map[pxm] = NID_INVAL; | ||
87 | node_to_pxm_map[node] = PXM_INVAL; | ||
88 | node_clear(node, nodes_found_map); | ||
89 | } | ||
90 | #endif /* 0 */ | ||
91 | |||
92 | static void __init | 83 | static void __init |
93 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) | 84 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) |
94 | { | 85 | { |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 7c1c59ea9ec6..02e8464e480f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -1118,7 +1118,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); | |||
1118 | 1118 | ||
1119 | /* Check for resource conflicts between ACPI OperationRegions and native | 1119 | /* Check for resource conflicts between ACPI OperationRegions and native |
1120 | * drivers */ | 1120 | * drivers */ |
1121 | int acpi_check_resource_conflict(struct resource *res) | 1121 | int acpi_check_resource_conflict(const struct resource *res) |
1122 | { | 1122 | { |
1123 | struct acpi_res_list *res_list_elem; | 1123 | struct acpi_res_list *res_list_elem; |
1124 | int ioport; | 1124 | int ioport; |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1af808171d46..101cce3681d1 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -202,72 +202,24 @@ static void acpi_pci_bridge_scan(struct acpi_device *device) | |||
202 | } | 202 | } |
203 | } | 203 | } |
204 | 204 | ||
205 | static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, | 205 | static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; |
206 | 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | ||
207 | 206 | ||
208 | static acpi_status acpi_pci_run_osc(acpi_handle handle, | 207 | static acpi_status acpi_pci_run_osc(acpi_handle handle, |
209 | const u32 *capbuf, u32 *retval) | 208 | const u32 *capbuf, u32 *retval) |
210 | { | 209 | { |
210 | struct acpi_osc_context context = { | ||
211 | .uuid_str = pci_osc_uuid_str, | ||
212 | .rev = 1, | ||
213 | .cap.length = 12, | ||
214 | .cap.pointer = (void *)capbuf, | ||
215 | }; | ||
211 | acpi_status status; | 216 | acpi_status status; |
212 | struct acpi_object_list input; | ||
213 | union acpi_object in_params[4]; | ||
214 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
215 | union acpi_object *out_obj; | ||
216 | u32 errors; | ||
217 | |||
218 | /* Setting up input parameters */ | ||
219 | input.count = 4; | ||
220 | input.pointer = in_params; | ||
221 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
222 | in_params[0].buffer.length = 16; | ||
223 | in_params[0].buffer.pointer = OSC_UUID; | ||
224 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
225 | in_params[1].integer.value = 1; | ||
226 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
227 | in_params[2].integer.value = 3; | ||
228 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
229 | in_params[3].buffer.length = 12; | ||
230 | in_params[3].buffer.pointer = (u8 *)capbuf; | ||
231 | |||
232 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); | ||
233 | if (ACPI_FAILURE(status)) | ||
234 | return status; | ||
235 | 217 | ||
236 | if (!output.length) | 218 | status = acpi_run_osc(handle, &context); |
237 | return AE_NULL_OBJECT; | 219 | if (ACPI_SUCCESS(status)) { |
238 | 220 | *retval = *((u32 *)(context.ret.pointer + 8)); | |
239 | out_obj = output.pointer; | 221 | kfree(context.ret.pointer); |
240 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
241 | printk(KERN_DEBUG "_OSC evaluation returned wrong type\n"); | ||
242 | status = AE_TYPE; | ||
243 | goto out_kfree; | ||
244 | } | ||
245 | /* Need to ignore the bit0 in result code */ | ||
246 | errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); | ||
247 | if (errors) { | ||
248 | if (errors & OSC_REQUEST_ERROR) | ||
249 | printk(KERN_DEBUG "_OSC request failed\n"); | ||
250 | if (errors & OSC_INVALID_UUID_ERROR) | ||
251 | printk(KERN_DEBUG "_OSC invalid UUID\n"); | ||
252 | if (errors & OSC_INVALID_REVISION_ERROR) | ||
253 | printk(KERN_DEBUG "_OSC invalid revision\n"); | ||
254 | if (errors & OSC_CAPABILITIES_MASK_ERROR) { | ||
255 | if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE) | ||
256 | goto out_success; | ||
257 | printk(KERN_DEBUG | ||
258 | "Firmware did not grant requested _OSC control\n"); | ||
259 | status = AE_SUPPORT; | ||
260 | goto out_kfree; | ||
261 | } | ||
262 | status = AE_ERROR; | ||
263 | goto out_kfree; | ||
264 | } | 222 | } |
265 | out_success: | ||
266 | *retval = *((u32 *)(out_obj->buffer.pointer + 8)); | ||
267 | status = AE_OK; | ||
268 | |||
269 | out_kfree: | ||
270 | kfree(output.pointer); | ||
271 | return status; | 223 | return status; |
272 | } | 224 | } |
273 | 225 | ||
@@ -277,10 +229,10 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) | |||
277 | u32 support_set, result, capbuf[3]; | 229 | u32 support_set, result, capbuf[3]; |
278 | 230 | ||
279 | /* do _OSC query for all possible controls */ | 231 | /* do _OSC query for all possible controls */ |
280 | support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS); | 232 | support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS); |
281 | capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | 233 | capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; |
282 | capbuf[OSC_SUPPORT_TYPE] = support_set; | 234 | capbuf[OSC_SUPPORT_TYPE] = support_set; |
283 | capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; | 235 | capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; |
284 | 236 | ||
285 | status = acpi_pci_run_osc(root->device->handle, capbuf, &result); | 237 | status = acpi_pci_run_osc(root->device->handle, capbuf, &result); |
286 | if (ACPI_SUCCESS(status)) { | 238 | if (ACPI_SUCCESS(status)) { |
@@ -427,7 +379,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) | |||
427 | if (ACPI_FAILURE(status)) | 379 | if (ACPI_FAILURE(status)) |
428 | return status; | 380 | return status; |
429 | 381 | ||
430 | control_req = (flags & OSC_CONTROL_MASKS); | 382 | control_req = (flags & OSC_PCI_CONTROL_MASKS); |
431 | if (!control_req) | 383 | if (!control_req) |
432 | return AE_TYPE; | 384 | return AE_TYPE; |
433 | 385 | ||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index cb4283f5a79d..41731236f9a1 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -353,7 +353,7 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file) | |||
353 | PDE(inode)->data); | 353 | PDE(inode)->data); |
354 | } | 354 | } |
355 | 355 | ||
356 | static int acpi_processor_add_fs(struct acpi_device *device) | 356 | static int __cpuinit acpi_processor_add_fs(struct acpi_device *device) |
357 | { | 357 | { |
358 | struct proc_dir_entry *entry = NULL; | 358 | struct proc_dir_entry *entry = NULL; |
359 | 359 | ||
@@ -722,7 +722,7 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event) | |||
722 | switch (event) { | 722 | switch (event) { |
723 | case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: | 723 | case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: |
724 | saved = pr->performance_platform_limit; | 724 | saved = pr->performance_platform_limit; |
725 | acpi_processor_ppc_has_changed(pr); | 725 | acpi_processor_ppc_has_changed(pr, 1); |
726 | if (saved == pr->performance_platform_limit) | 726 | if (saved == pr->performance_platform_limit) |
727 | break; | 727 | break; |
728 | acpi_bus_generate_proc_event(device, event, | 728 | acpi_bus_generate_proc_event(device, event, |
@@ -758,7 +758,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, | |||
758 | struct acpi_processor *pr = per_cpu(processors, cpu); | 758 | struct acpi_processor *pr = per_cpu(processors, cpu); |
759 | 759 | ||
760 | if (action == CPU_ONLINE && pr) { | 760 | if (action == CPU_ONLINE && pr) { |
761 | acpi_processor_ppc_has_changed(pr); | 761 | acpi_processor_ppc_has_changed(pr, 0); |
762 | acpi_processor_cst_has_changed(pr); | 762 | acpi_processor_cst_has_changed(pr); |
763 | acpi_processor_tstate_has_changed(pr); | 763 | acpi_processor_tstate_has_changed(pr); |
764 | } | 764 | } |
@@ -830,7 +830,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
830 | arch_acpi_processor_cleanup_pdc(pr); | 830 | arch_acpi_processor_cleanup_pdc(pr); |
831 | 831 | ||
832 | #ifdef CONFIG_CPU_FREQ | 832 | #ifdef CONFIG_CPU_FREQ |
833 | acpi_processor_ppc_has_changed(pr); | 833 | acpi_processor_ppc_has_changed(pr, 0); |
834 | #endif | 834 | #endif |
835 | acpi_processor_get_throttling_info(pr); | 835 | acpi_processor_get_throttling_info(pr); |
836 | acpi_processor_get_limit_info(pr); | 836 | acpi_processor_get_limit_info(pr); |
@@ -845,7 +845,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
845 | goto err_power_exit; | 845 | goto err_power_exit; |
846 | } | 846 | } |
847 | 847 | ||
848 | dev_info(&device->dev, "registered as cooling_device%d\n", | 848 | dev_dbg(&device->dev, "registered as cooling_device%d\n", |
849 | pr->cdev->id); | 849 | pr->cdev->id); |
850 | 850 | ||
851 | result = sysfs_create_link(&device->dev.kobj, | 851 | result = sysfs_create_link(&device->dev.kobj, |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index bbd066e7f854..d1676b1754d9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -164,7 +164,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr, | |||
164 | pr->power.timer_broadcast_on_state = state; | 164 | pr->power.timer_broadcast_on_state = state; |
165 | } | 165 | } |
166 | 166 | ||
167 | static void lapic_timer_propagate_broadcast(void *arg) | 167 | static void __lapic_timer_propagate_broadcast(void *arg) |
168 | { | 168 | { |
169 | struct acpi_processor *pr = (struct acpi_processor *) arg; | 169 | struct acpi_processor *pr = (struct acpi_processor *) arg; |
170 | unsigned long reason; | 170 | unsigned long reason; |
@@ -175,6 +175,12 @@ static void lapic_timer_propagate_broadcast(void *arg) | |||
175 | clockevents_notify(reason, &pr->id); | 175 | clockevents_notify(reason, &pr->id); |
176 | } | 176 | } |
177 | 177 | ||
178 | static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) | ||
179 | { | ||
180 | smp_call_function_single(pr->id, __lapic_timer_propagate_broadcast, | ||
181 | (void *)pr, 1); | ||
182 | } | ||
183 | |||
178 | /* Power(C) State timer broadcast control */ | 184 | /* Power(C) State timer broadcast control */ |
179 | static void lapic_timer_state_broadcast(struct acpi_processor *pr, | 185 | static void lapic_timer_state_broadcast(struct acpi_processor *pr, |
180 | struct acpi_processor_cx *cx, | 186 | struct acpi_processor_cx *cx, |
@@ -638,8 +644,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) | |||
638 | working++; | 644 | working++; |
639 | } | 645 | } |
640 | 646 | ||
641 | smp_call_function_single(pr->id, lapic_timer_propagate_broadcast, | 647 | lapic_timer_propagate_broadcast(pr); |
642 | pr, 1); | ||
643 | 648 | ||
644 | return (working); | 649 | return (working); |
645 | } | 650 | } |
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 01e366d2b6fb..2cabadcc4d8c 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
@@ -152,15 +152,59 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) | |||
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr) | 155 | #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 |
156 | /* | ||
157 | * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status | ||
158 | * @handle: ACPI processor handle | ||
159 | * @status: the status code of _PPC evaluation | ||
160 | * 0: success. OSPM is now using the performance state specificed. | ||
161 | * 1: failure. OSPM has not changed the number of P-states in use | ||
162 | */ | ||
163 | static void acpi_processor_ppc_ost(acpi_handle handle, int status) | ||
164 | { | ||
165 | union acpi_object params[2] = { | ||
166 | {.type = ACPI_TYPE_INTEGER,}, | ||
167 | {.type = ACPI_TYPE_INTEGER,}, | ||
168 | }; | ||
169 | struct acpi_object_list arg_list = {2, params}; | ||
170 | acpi_handle temp; | ||
171 | |||
172 | params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; | ||
173 | params[1].integer.value = status; | ||
174 | |||
175 | /* when there is no _OST , skip it */ | ||
176 | if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) | ||
177 | return; | ||
178 | |||
179 | acpi_evaluate_object(handle, "_OST", &arg_list, NULL); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) | ||
156 | { | 184 | { |
157 | int ret; | 185 | int ret; |
158 | 186 | ||
159 | if (ignore_ppc) | 187 | if (ignore_ppc) { |
188 | /* | ||
189 | * Only when it is notification event, the _OST object | ||
190 | * will be evaluated. Otherwise it is skipped. | ||
191 | */ | ||
192 | if (event_flag) | ||
193 | acpi_processor_ppc_ost(pr->handle, 1); | ||
160 | return 0; | 194 | return 0; |
195 | } | ||
161 | 196 | ||
162 | ret = acpi_processor_get_platform_limit(pr); | 197 | ret = acpi_processor_get_platform_limit(pr); |
163 | 198 | /* | |
199 | * Only when it is notification event, the _OST object | ||
200 | * will be evaluated. Otherwise it is skipped. | ||
201 | */ | ||
202 | if (event_flag) { | ||
203 | if (ret < 0) | ||
204 | acpi_processor_ppc_ost(pr->handle, 1); | ||
205 | else | ||
206 | acpi_processor_ppc_ost(pr->handle, 0); | ||
207 | } | ||
164 | if (ret < 0) | 208 | if (ret < 0) |
165 | return (ret); | 209 | return (ret); |
166 | else | 210 | else |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 65f67815902a..9073ada88835 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
@@ -1052,6 +1052,13 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset) | |||
1052 | acpi_device_bid(device)); | 1052 | acpi_device_bid(device)); |
1053 | } | 1053 | } |
1054 | seq_puts(seq, "\n"); | 1054 | seq_puts(seq, "\n"); |
1055 | } else { | ||
1056 | seq_printf(seq, "passive (forced):"); | ||
1057 | if (tz->thermal_zone->forced_passive) | ||
1058 | seq_printf(seq, " %i C\n", | ||
1059 | tz->thermal_zone->forced_passive / 1000); | ||
1060 | else | ||
1061 | seq_printf(seq, "<not set>\n"); | ||
1055 | } | 1062 | } |
1056 | 1063 | ||
1057 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { | 1064 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index d2e698096ace..679cd08b80b4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/dmi.h> | 64 | #include <linux/dmi.h> |
65 | #include <linux/string.h> | 65 | #include <linux/string.h> |
66 | #include <linux/ctype.h> | 66 | #include <linux/ctype.h> |
67 | #include <linux/pnp.h> | ||
67 | 68 | ||
68 | #ifdef CONFIG_PPC_OF | 69 | #ifdef CONFIG_PPC_OF |
69 | #include <linux/of_device.h> | 70 | #include <linux/of_device.h> |
@@ -1919,7 +1920,7 @@ struct SPMITable { | |||
1919 | s8 spmi_id[1]; /* A '\0' terminated array starts here. */ | 1920 | s8 spmi_id[1]; /* A '\0' terminated array starts here. */ |
1920 | }; | 1921 | }; |
1921 | 1922 | ||
1922 | static __devinit int try_init_acpi(struct SPMITable *spmi) | 1923 | static __devinit int try_init_spmi(struct SPMITable *spmi) |
1923 | { | 1924 | { |
1924 | struct smi_info *info; | 1925 | struct smi_info *info; |
1925 | u8 addr_space; | 1926 | u8 addr_space; |
@@ -1940,7 +1941,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) | |||
1940 | return -ENOMEM; | 1941 | return -ENOMEM; |
1941 | } | 1942 | } |
1942 | 1943 | ||
1943 | info->addr_source = "ACPI"; | 1944 | info->addr_source = "SPMI"; |
1944 | 1945 | ||
1945 | /* Figure out the interface type. */ | 1946 | /* Figure out the interface type. */ |
1946 | switch (spmi->InterfaceType) { | 1947 | switch (spmi->InterfaceType) { |
@@ -2002,7 +2003,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) | |||
2002 | return 0; | 2003 | return 0; |
2003 | } | 2004 | } |
2004 | 2005 | ||
2005 | static __devinit void acpi_find_bmc(void) | 2006 | static __devinit void spmi_find_bmc(void) |
2006 | { | 2007 | { |
2007 | acpi_status status; | 2008 | acpi_status status; |
2008 | struct SPMITable *spmi; | 2009 | struct SPMITable *spmi; |
@@ -2020,9 +2021,106 @@ static __devinit void acpi_find_bmc(void) | |||
2020 | if (status != AE_OK) | 2021 | if (status != AE_OK) |
2021 | return; | 2022 | return; |
2022 | 2023 | ||
2023 | try_init_acpi(spmi); | 2024 | try_init_spmi(spmi); |
2024 | } | 2025 | } |
2025 | } | 2026 | } |
2027 | |||
2028 | static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, | ||
2029 | const struct pnp_device_id *dev_id) | ||
2030 | { | ||
2031 | struct acpi_device *acpi_dev; | ||
2032 | struct smi_info *info; | ||
2033 | acpi_handle handle; | ||
2034 | acpi_status status; | ||
2035 | unsigned long long tmp; | ||
2036 | |||
2037 | acpi_dev = pnp_acpi_device(dev); | ||
2038 | if (!acpi_dev) | ||
2039 | return -ENODEV; | ||
2040 | |||
2041 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
2042 | if (!info) | ||
2043 | return -ENOMEM; | ||
2044 | |||
2045 | info->addr_source = "ACPI"; | ||
2046 | |||
2047 | handle = acpi_dev->handle; | ||
2048 | |||
2049 | /* _IFT tells us the interface type: KCS, BT, etc */ | ||
2050 | status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); | ||
2051 | if (ACPI_FAILURE(status)) | ||
2052 | goto err_free; | ||
2053 | |||
2054 | switch (tmp) { | ||
2055 | case 1: | ||
2056 | info->si_type = SI_KCS; | ||
2057 | break; | ||
2058 | case 2: | ||
2059 | info->si_type = SI_SMIC; | ||
2060 | break; | ||
2061 | case 3: | ||
2062 | info->si_type = SI_BT; | ||
2063 | break; | ||
2064 | default: | ||
2065 | dev_info(&dev->dev, "unknown interface type %lld\n", tmp); | ||
2066 | goto err_free; | ||
2067 | } | ||
2068 | |||
2069 | if (pnp_port_valid(dev, 0)) { | ||
2070 | info->io_setup = port_setup; | ||
2071 | info->io.addr_type = IPMI_IO_ADDR_SPACE; | ||
2072 | info->io.addr_data = pnp_port_start(dev, 0); | ||
2073 | } else if (pnp_mem_valid(dev, 0)) { | ||
2074 | info->io_setup = mem_setup; | ||
2075 | info->io.addr_type = IPMI_MEM_ADDR_SPACE; | ||
2076 | info->io.addr_data = pnp_mem_start(dev, 0); | ||
2077 | } else { | ||
2078 | dev_err(&dev->dev, "no I/O or memory address\n"); | ||
2079 | goto err_free; | ||
2080 | } | ||
2081 | |||
2082 | info->io.regspacing = DEFAULT_REGSPACING; | ||
2083 | info->io.regsize = DEFAULT_REGSPACING; | ||
2084 | info->io.regshift = 0; | ||
2085 | |||
2086 | /* If _GPE exists, use it; otherwise use standard interrupts */ | ||
2087 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); | ||
2088 | if (ACPI_SUCCESS(status)) { | ||
2089 | info->irq = tmp; | ||
2090 | info->irq_setup = acpi_gpe_irq_setup; | ||
2091 | } else if (pnp_irq_valid(dev, 0)) { | ||
2092 | info->irq = pnp_irq(dev, 0); | ||
2093 | info->irq_setup = std_irq_setup; | ||
2094 | } | ||
2095 | |||
2096 | info->dev = &acpi_dev->dev; | ||
2097 | pnp_set_drvdata(dev, info); | ||
2098 | |||
2099 | return try_smi_init(info); | ||
2100 | |||
2101 | err_free: | ||
2102 | kfree(info); | ||
2103 | return -EINVAL; | ||
2104 | } | ||
2105 | |||
2106 | static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) | ||
2107 | { | ||
2108 | struct smi_info *info = pnp_get_drvdata(dev); | ||
2109 | |||
2110 | cleanup_one_si(info); | ||
2111 | } | ||
2112 | |||
2113 | static const struct pnp_device_id pnp_dev_table[] = { | ||
2114 | {"IPI0001", 0}, | ||
2115 | {"", 0}, | ||
2116 | }; | ||
2117 | |||
2118 | static struct pnp_driver ipmi_pnp_driver = { | ||
2119 | .name = DEVICE_NAME, | ||
2120 | .probe = ipmi_pnp_probe, | ||
2121 | .remove = __devexit_p(ipmi_pnp_remove), | ||
2122 | .id_table = pnp_dev_table, | ||
2123 | }; | ||
2026 | #endif | 2124 | #endif |
2027 | 2125 | ||
2028 | #ifdef CONFIG_DMI | 2126 | #ifdef CONFIG_DMI |
@@ -2202,7 +2300,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
2202 | int rv; | 2300 | int rv; |
2203 | int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; | 2301 | int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; |
2204 | struct smi_info *info; | 2302 | struct smi_info *info; |
2205 | int first_reg_offset = 0; | ||
2206 | 2303 | ||
2207 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 2304 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
2208 | if (!info) | 2305 | if (!info) |
@@ -2241,9 +2338,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
2241 | info->addr_source_cleanup = ipmi_pci_cleanup; | 2338 | info->addr_source_cleanup = ipmi_pci_cleanup; |
2242 | info->addr_source_data = pdev; | 2339 | info->addr_source_data = pdev; |
2243 | 2340 | ||
2244 | if (pdev->subsystem_vendor == PCI_HP_VENDOR_ID) | ||
2245 | first_reg_offset = 1; | ||
2246 | |||
2247 | if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { | 2341 | if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { |
2248 | info->io_setup = port_setup; | 2342 | info->io_setup = port_setup; |
2249 | info->io.addr_type = IPMI_IO_ADDR_SPACE; | 2343 | info->io.addr_type = IPMI_IO_ADDR_SPACE; |
@@ -3108,7 +3202,10 @@ static __devinit int init_ipmi_si(void) | |||
3108 | #endif | 3202 | #endif |
3109 | 3203 | ||
3110 | #ifdef CONFIG_ACPI | 3204 | #ifdef CONFIG_ACPI |
3111 | acpi_find_bmc(); | 3205 | spmi_find_bmc(); |
3206 | #endif | ||
3207 | #ifdef CONFIG_PNP | ||
3208 | pnp_register_driver(&ipmi_pnp_driver); | ||
3112 | #endif | 3209 | #endif |
3113 | 3210 | ||
3114 | #ifdef CONFIG_PCI | 3211 | #ifdef CONFIG_PCI |
@@ -3233,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void) | |||
3233 | #ifdef CONFIG_PCI | 3330 | #ifdef CONFIG_PCI |
3234 | pci_unregister_driver(&ipmi_pci_driver); | 3331 | pci_unregister_driver(&ipmi_pci_driver); |
3235 | #endif | 3332 | #endif |
3333 | #ifdef CONFIG_PNP | ||
3334 | pnp_unregister_driver(&ipmi_pnp_driver); | ||
3335 | #endif | ||
3236 | 3336 | ||
3237 | #ifdef CONFIG_PPC_OF | 3337 | #ifdef CONFIG_PPC_OF |
3238 | of_unregister_platform_driver(&ipmi_of_platform_driver); | 3338 | of_unregister_platform_driver(&ipmi_of_platform_driver); |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 59f4ba1b7034..1a7a9fc50ea1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -248,19 +248,6 @@ config SGI_GRU_DEBUG | |||
248 | This option enables addition debugging code for the SGI GRU driver. If | 248 | This option enables addition debugging code for the SGI GRU driver. If |
249 | you are unsure, say N. | 249 | you are unsure, say N. |
250 | 250 | ||
251 | config DELL_LAPTOP | ||
252 | tristate "Dell Laptop Extras (EXPERIMENTAL)" | ||
253 | depends on X86 | ||
254 | depends on DCDBAS | ||
255 | depends on EXPERIMENTAL | ||
256 | depends on BACKLIGHT_CLASS_DEVICE | ||
257 | depends on RFKILL | ||
258 | depends on POWER_SUPPLY | ||
259 | default n | ||
260 | ---help--- | ||
261 | This driver adds support for rfkill and backlight control to Dell | ||
262 | laptops. | ||
263 | |||
264 | config ISL29003 | 251 | config ISL29003 |
265 | tristate "Intersil ISL29003 ambient light sensor" | 252 | tristate "Intersil ISL29003 ambient light sensor" |
266 | depends on I2C && SYSFS | 253 | depends on I2C && SYSFS |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 55ca39dea42e..fc5bf9d2a3f3 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -334,6 +334,8 @@ config EEEPC_LAPTOP | |||
334 | depends on HOTPLUG_PCI | 334 | depends on HOTPLUG_PCI |
335 | select BACKLIGHT_CLASS_DEVICE | 335 | select BACKLIGHT_CLASS_DEVICE |
336 | select HWMON | 336 | select HWMON |
337 | select LEDS_CLASS | ||
338 | select NEW_LEDS | ||
337 | ---help--- | 339 | ---help--- |
338 | This driver supports the Fn-Fx keys on Eee PC laptops. | 340 | This driver supports the Fn-Fx keys on Eee PC laptops. |
339 | 341 | ||
@@ -365,6 +367,18 @@ config ACPI_WMI | |||
365 | It is safe to enable this driver even if your DSDT doesn't define | 367 | It is safe to enable this driver even if your DSDT doesn't define |
366 | any ACPI-WMI devices. | 368 | any ACPI-WMI devices. |
367 | 369 | ||
370 | config MSI_WMI | ||
371 | tristate "MSI WMI extras" | ||
372 | depends on ACPI_WMI | ||
373 | depends on INPUT | ||
374 | depends on BACKLIGHT_CLASS_DEVICE | ||
375 | select INPUT_SPARSEKMAP | ||
376 | help | ||
377 | Say Y here if you want to support WMI-based hotkeys on MSI laptops. | ||
378 | |||
379 | To compile this driver as a module, choose M here: the module will | ||
380 | be called msi-wmi. | ||
381 | |||
368 | config ACPI_ASUS | 382 | config ACPI_ASUS |
369 | tristate "ASUS/Medion Laptop Extras (DEPRECATED)" | 383 | tristate "ASUS/Medion Laptop Extras (DEPRECATED)" |
370 | depends on ACPI | 384 | depends on ACPI |
@@ -435,4 +449,19 @@ config ACPI_TOSHIBA | |||
435 | 449 | ||
436 | If you have a legacy free Toshiba laptop (such as the Libretto L1 | 450 | If you have a legacy free Toshiba laptop (such as the Libretto L1 |
437 | series), say Y. | 451 | series), say Y. |
452 | |||
453 | config TOSHIBA_BT_RFKILL | ||
454 | tristate "Toshiba Bluetooth RFKill switch support" | ||
455 | depends on ACPI | ||
456 | ---help--- | ||
457 | This driver adds support for Bluetooth events for the RFKill | ||
458 | switch on modern Toshiba laptops with full ACPI support and | ||
459 | an RFKill switch. | ||
460 | |||
461 | This driver handles RFKill events for the TOS6205 Bluetooth, | ||
462 | and re-enables it when the switch is set back to the 'on' | ||
463 | position. | ||
464 | |||
465 | If you have a modern Toshiba laptop with a Bluetooth and an | ||
466 | RFKill switch (such as the Portege R500), say Y. | ||
438 | endif # X86_PLATFORM_DEVICES | 467 | endif # X86_PLATFORM_DEVICES |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d1c16210a512..b7474b6a8bf1 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
@@ -18,6 +18,8 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o | |||
18 | obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o | 18 | obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o |
19 | obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o | 19 | obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o |
20 | obj-$(CONFIG_ACPI_WMI) += wmi.o | 20 | obj-$(CONFIG_ACPI_WMI) += wmi.o |
21 | obj-$(CONFIG_MSI_WMI) += msi-wmi.o | ||
21 | obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o | 22 | obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o |
22 | obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o | 23 | obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o |
23 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | 24 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o |
25 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o | ||
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index be27aa47e810..79b15b9d9cf0 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c | |||
@@ -52,7 +52,7 @@ | |||
52 | */ | 52 | */ |
53 | #undef START_IN_KERNEL_MODE | 53 | #undef START_IN_KERNEL_MODE |
54 | 54 | ||
55 | #define DRV_VER "0.5.18" | 55 | #define DRV_VER "0.5.20" |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * According to the Atom N270 datasheet, | 58 | * According to the Atom N270 datasheet, |
@@ -112,12 +112,14 @@ module_param_string(force_product, force_product, 16, 0); | |||
112 | MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); | 112 | MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); |
113 | 113 | ||
114 | /* | 114 | /* |
115 | * cmd_off: to switch the fan completely off / to check if the fan is off | 115 | * cmd_off: to switch the fan completely off |
116 | * chk_off: to check if the fan is off | ||
116 | * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then | 117 | * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then |
117 | * the fan speed depending on the temperature | 118 | * the fan speed depending on the temperature |
118 | */ | 119 | */ |
119 | struct fancmd { | 120 | struct fancmd { |
120 | u8 cmd_off; | 121 | u8 cmd_off; |
122 | u8 chk_off; | ||
121 | u8 cmd_auto; | 123 | u8 cmd_auto; |
122 | }; | 124 | }; |
123 | 125 | ||
@@ -134,32 +136,41 @@ struct bios_settings_t { | |||
134 | /* Register addresses and values for different BIOS versions */ | 136 | /* Register addresses and values for different BIOS versions */ |
135 | static const struct bios_settings_t bios_tbl[] = { | 137 | static const struct bios_settings_t bios_tbl[] = { |
136 | /* AOA110 */ | 138 | /* AOA110 */ |
137 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, | 139 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, |
138 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, | 140 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, |
139 | {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, | 141 | {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
140 | {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, | 142 | {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
141 | {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, | 143 | {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
142 | {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, | 144 | {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
143 | {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, | 145 | {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
144 | {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, | 146 | {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
145 | {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, | 147 | {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
146 | /* AOA150 */ | 148 | /* AOA150 */ |
147 | {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, | 149 | {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
148 | {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, | 150 | {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
149 | {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, | 151 | {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
150 | {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, | 152 | {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
151 | {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, | 153 | {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
152 | {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, | 154 | {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
153 | {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, | 155 | {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
154 | {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, | 156 | {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
157 | /* Acer 1410 */ | ||
158 | {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, | ||
155 | /* special BIOS / other */ | 159 | /* special BIOS / other */ |
156 | {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, | 160 | {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
157 | {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, | 161 | {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
158 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, | 162 | {"Gateway ", "LT31 ", "v1.3103 ", 0x55, 0x58, |
159 | {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, | 163 | {0x10, 0x0f, 0x00} }, |
160 | {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, | 164 | {"Gateway ", "LT31 ", "v1.3201 ", 0x55, 0x58, |
165 | {0x10, 0x0f, 0x00} }, | ||
166 | {"Gateway ", "LT31 ", "v1.3302 ", 0x55, 0x58, | ||
167 | {0x10, 0x0f, 0x00} }, | ||
168 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} }, | ||
169 | {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, | ||
170 | {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} }, | ||
171 | {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, | ||
161 | /* pewpew-terminator */ | 172 | /* pewpew-terminator */ |
162 | {"", "", "", 0, 0, {0, 0} } | 173 | {"", "", "", 0, 0, {0, 0, 0} } |
163 | }; | 174 | }; |
164 | 175 | ||
165 | static const struct bios_settings_t *bios_cfg __read_mostly; | 176 | static const struct bios_settings_t *bios_cfg __read_mostly; |
@@ -183,7 +194,7 @@ static int acerhdf_get_fanstate(int *state) | |||
183 | if (ec_read(bios_cfg->fanreg, &fan)) | 194 | if (ec_read(bios_cfg->fanreg, &fan)) |
184 | return -EINVAL; | 195 | return -EINVAL; |
185 | 196 | ||
186 | if (fan != bios_cfg->cmd.cmd_off) | 197 | if (fan != bios_cfg->cmd.chk_off) |
187 | *state = ACERHDF_FAN_AUTO; | 198 | *state = ACERHDF_FAN_AUTO; |
188 | else | 199 | else |
189 | *state = ACERHDF_FAN_OFF; | 200 | *state = ACERHDF_FAN_OFF; |
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index b39d2bb3e75b..61a1c7503658 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
@@ -221,6 +221,7 @@ static struct asus_hotk *hotk; | |||
221 | */ | 221 | */ |
222 | static const struct acpi_device_id asus_device_ids[] = { | 222 | static const struct acpi_device_id asus_device_ids[] = { |
223 | {"ATK0100", 0}, | 223 | {"ATK0100", 0}, |
224 | {"ATK0101", 0}, | ||
224 | {"", 0}, | 225 | {"", 0}, |
225 | }; | 226 | }; |
226 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); | 227 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); |
@@ -232,6 +233,7 @@ static void asus_hotk_notify(struct acpi_device *device, u32 event); | |||
232 | static struct acpi_driver asus_hotk_driver = { | 233 | static struct acpi_driver asus_hotk_driver = { |
233 | .name = ASUS_HOTK_NAME, | 234 | .name = ASUS_HOTK_NAME, |
234 | .class = ASUS_HOTK_CLASS, | 235 | .class = ASUS_HOTK_CLASS, |
236 | .owner = THIS_MODULE, | ||
235 | .ids = asus_device_ids, | 237 | .ids = asus_device_ids, |
236 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | 238 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, |
237 | .ops = { | 239 | .ops = { |
@@ -293,6 +295,11 @@ struct key_entry { | |||
293 | enum { KE_KEY, KE_END }; | 295 | enum { KE_KEY, KE_END }; |
294 | 296 | ||
295 | static struct key_entry asus_keymap[] = { | 297 | static struct key_entry asus_keymap[] = { |
298 | {KE_KEY, 0x02, KEY_SCREENLOCK}, | ||
299 | {KE_KEY, 0x05, KEY_WLAN}, | ||
300 | {KE_KEY, 0x08, KEY_F13}, | ||
301 | {KE_KEY, 0x17, KEY_ZOOM}, | ||
302 | {KE_KEY, 0x1f, KEY_BATTERY}, | ||
296 | {KE_KEY, 0x30, KEY_VOLUMEUP}, | 303 | {KE_KEY, 0x30, KEY_VOLUMEUP}, |
297 | {KE_KEY, 0x31, KEY_VOLUMEDOWN}, | 304 | {KE_KEY, 0x31, KEY_VOLUMEDOWN}, |
298 | {KE_KEY, 0x32, KEY_MUTE}, | 305 | {KE_KEY, 0x32, KEY_MUTE}, |
@@ -312,8 +319,11 @@ static struct key_entry asus_keymap[] = { | |||
312 | {KE_KEY, 0x5F, KEY_WLAN}, | 319 | {KE_KEY, 0x5F, KEY_WLAN}, |
313 | {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, | 320 | {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, |
314 | {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, | 321 | {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, |
315 | {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ | 322 | {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, |
323 | {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, | ||
324 | {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ | ||
316 | {KE_KEY, 0x82, KEY_CAMERA}, | 325 | {KE_KEY, 0x82, KEY_CAMERA}, |
326 | {KE_KEY, 0x88, KEY_WLAN }, | ||
317 | {KE_KEY, 0x8A, KEY_PROG1}, | 327 | {KE_KEY, 0x8A, KEY_PROG1}, |
318 | {KE_KEY, 0x95, KEY_MEDIA}, | 328 | {KE_KEY, 0x95, KEY_MEDIA}, |
319 | {KE_KEY, 0x99, KEY_PHONE}, | 329 | {KE_KEY, 0x99, KEY_PHONE}, |
@@ -1240,9 +1250,6 @@ static int asus_hotk_add(struct acpi_device *device) | |||
1240 | { | 1250 | { |
1241 | int result; | 1251 | int result; |
1242 | 1252 | ||
1243 | if (!device) | ||
1244 | return -EINVAL; | ||
1245 | |||
1246 | pr_notice("Asus Laptop Support version %s\n", | 1253 | pr_notice("Asus Laptop Support version %s\n", |
1247 | ASUS_LAPTOP_VERSION); | 1254 | ASUS_LAPTOP_VERSION); |
1248 | 1255 | ||
@@ -1283,8 +1290,8 @@ static int asus_hotk_add(struct acpi_device *device) | |||
1283 | hotk->ledd_status = 0xFFF; | 1290 | hotk->ledd_status = 0xFFF; |
1284 | 1291 | ||
1285 | /* Set initial values of light sensor and level */ | 1292 | /* Set initial values of light sensor and level */ |
1286 | hotk->light_switch = 1; /* Default to light sensor disabled */ | 1293 | hotk->light_switch = 0; /* Default to light sensor disabled */ |
1287 | hotk->light_level = 0; /* level 5 for sensor sensitivity */ | 1294 | hotk->light_level = 5; /* level 5 for sensor sensitivity */ |
1288 | 1295 | ||
1289 | if (ls_switch_handle) | 1296 | if (ls_switch_handle) |
1290 | set_light_sens_switch(hotk->light_switch); | 1297 | set_light_sens_switch(hotk->light_switch); |
@@ -1306,9 +1313,6 @@ end: | |||
1306 | 1313 | ||
1307 | static int asus_hotk_remove(struct acpi_device *device, int type) | 1314 | static int asus_hotk_remove(struct acpi_device *device, int type) |
1308 | { | 1315 | { |
1309 | if (!device || !acpi_driver_data(device)) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | kfree(hotk->name); | 1316 | kfree(hotk->name); |
1313 | kfree(hotk); | 1317 | kfree(hotk); |
1314 | 1318 | ||
@@ -1444,9 +1448,6 @@ static int __init asus_laptop_init(void) | |||
1444 | { | 1448 | { |
1445 | int result; | 1449 | int result; |
1446 | 1450 | ||
1447 | if (acpi_disabled) | ||
1448 | return -ENODEV; | ||
1449 | |||
1450 | result = acpi_bus_register_driver(&asus_hotk_driver); | 1451 | result = acpi_bus_register_driver(&asus_hotk_driver); |
1451 | if (result < 0) | 1452 | if (result < 0) |
1452 | return result; | 1453 | return result; |
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index ddf5240ade8c..0c9c53111a22 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c | |||
@@ -466,6 +466,7 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids); | |||
466 | static struct acpi_driver asus_hotk_driver = { | 466 | static struct acpi_driver asus_hotk_driver = { |
467 | .name = "asus_acpi", | 467 | .name = "asus_acpi", |
468 | .class = ACPI_HOTK_CLASS, | 468 | .class = ACPI_HOTK_CLASS, |
469 | .owner = THIS_MODULE, | ||
469 | .ids = asus_device_ids, | 470 | .ids = asus_device_ids, |
470 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | 471 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, |
471 | .ops = { | 472 | .ops = { |
@@ -1334,9 +1335,6 @@ static int asus_hotk_add(struct acpi_device *device) | |||
1334 | acpi_status status = AE_OK; | 1335 | acpi_status status = AE_OK; |
1335 | int result; | 1336 | int result; |
1336 | 1337 | ||
1337 | if (!device) | ||
1338 | return -EINVAL; | ||
1339 | |||
1340 | printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", | 1338 | printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", |
1341 | ASUS_ACPI_VERSION); | 1339 | ASUS_ACPI_VERSION); |
1342 | 1340 | ||
@@ -1392,9 +1390,6 @@ end: | |||
1392 | 1390 | ||
1393 | static int asus_hotk_remove(struct acpi_device *device, int type) | 1391 | static int asus_hotk_remove(struct acpi_device *device, int type) |
1394 | { | 1392 | { |
1395 | if (!device || !acpi_driver_data(device)) | ||
1396 | return -EINVAL; | ||
1397 | |||
1398 | asus_hotk_remove_fs(device); | 1393 | asus_hotk_remove_fs(device); |
1399 | 1394 | ||
1400 | kfree(hotk); | 1395 | kfree(hotk); |
@@ -1422,21 +1417,17 @@ static int __init asus_acpi_init(void) | |||
1422 | { | 1417 | { |
1423 | int result; | 1418 | int result; |
1424 | 1419 | ||
1425 | if (acpi_disabled) | 1420 | result = acpi_bus_register_driver(&asus_hotk_driver); |
1426 | return -ENODEV; | 1421 | if (result < 0) |
1422 | return result; | ||
1427 | 1423 | ||
1428 | asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); | 1424 | asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); |
1429 | if (!asus_proc_dir) { | 1425 | if (!asus_proc_dir) { |
1430 | printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); | 1426 | printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); |
1427 | acpi_bus_unregister_driver(&asus_hotk_driver); | ||
1431 | return -ENODEV; | 1428 | return -ENODEV; |
1432 | } | 1429 | } |
1433 | 1430 | ||
1434 | result = acpi_bus_register_driver(&asus_hotk_driver); | ||
1435 | if (result < 0) { | ||
1436 | remove_proc_entry(PROC_ASUS, acpi_root_dir); | ||
1437 | return result; | ||
1438 | } | ||
1439 | |||
1440 | /* | 1431 | /* |
1441 | * This is a bit of a kludge. We only want this module loaded | 1432 | * This is a bit of a kludge. We only want this module loaded |
1442 | * for ASUS systems, but there's currently no way to probe the | 1433 | * for ASUS systems, but there's currently no way to probe the |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 74909c4aaeea..3780994dc8f2 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -58,6 +58,14 @@ static int da_command_code; | |||
58 | static int da_num_tokens; | 58 | static int da_num_tokens; |
59 | static struct calling_interface_token *da_tokens; | 59 | static struct calling_interface_token *da_tokens; |
60 | 60 | ||
61 | static struct platform_driver platform_driver = { | ||
62 | .driver = { | ||
63 | .name = "dell-laptop", | ||
64 | .owner = THIS_MODULE, | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | static struct platform_device *platform_device; | ||
61 | static struct backlight_device *dell_backlight_device; | 69 | static struct backlight_device *dell_backlight_device; |
62 | static struct rfkill *wifi_rfkill; | 70 | static struct rfkill *wifi_rfkill; |
63 | static struct rfkill *bluetooth_rfkill; | 71 | static struct rfkill *bluetooth_rfkill; |
@@ -74,7 +82,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = { | |||
74 | { } | 82 | { } |
75 | }; | 83 | }; |
76 | 84 | ||
77 | static void parse_da_table(const struct dmi_header *dm) | 85 | static void __init parse_da_table(const struct dmi_header *dm) |
78 | { | 86 | { |
79 | /* Final token is a terminator, so we don't want to copy it */ | 87 | /* Final token is a terminator, so we don't want to copy it */ |
80 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; | 88 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; |
@@ -103,7 +111,7 @@ static void parse_da_table(const struct dmi_header *dm) | |||
103 | da_num_tokens += tokens; | 111 | da_num_tokens += tokens; |
104 | } | 112 | } |
105 | 113 | ||
106 | static void find_tokens(const struct dmi_header *dm, void *dummy) | 114 | static void __init find_tokens(const struct dmi_header *dm, void *dummy) |
107 | { | 115 | { |
108 | switch (dm->type) { | 116 | switch (dm->type) { |
109 | case 0xd4: /* Indexed IO */ | 117 | case 0xd4: /* Indexed IO */ |
@@ -197,8 +205,8 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) | |||
197 | dell_send_request(&buffer, 17, 11); | 205 | dell_send_request(&buffer, 17, 11); |
198 | status = buffer.output[1]; | 206 | status = buffer.output[1]; |
199 | 207 | ||
200 | if (status & BIT(bit)) | 208 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); |
201 | rfkill_set_hw_state(rfkill, !!(status & BIT(16))); | 209 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); |
202 | } | 210 | } |
203 | 211 | ||
204 | static const struct rfkill_ops dell_rfkill_ops = { | 212 | static const struct rfkill_ops dell_rfkill_ops = { |
@@ -206,7 +214,7 @@ static const struct rfkill_ops dell_rfkill_ops = { | |||
206 | .query = dell_rfkill_query, | 214 | .query = dell_rfkill_query, |
207 | }; | 215 | }; |
208 | 216 | ||
209 | static int dell_setup_rfkill(void) | 217 | static int __init dell_setup_rfkill(void) |
210 | { | 218 | { |
211 | struct calling_interface_buffer buffer; | 219 | struct calling_interface_buffer buffer; |
212 | int status; | 220 | int status; |
@@ -217,7 +225,8 @@ static int dell_setup_rfkill(void) | |||
217 | status = buffer.output[1]; | 225 | status = buffer.output[1]; |
218 | 226 | ||
219 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 227 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |
220 | wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, | 228 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, |
229 | RFKILL_TYPE_WLAN, | ||
221 | &dell_rfkill_ops, (void *) 1); | 230 | &dell_rfkill_ops, (void *) 1); |
222 | if (!wifi_rfkill) { | 231 | if (!wifi_rfkill) { |
223 | ret = -ENOMEM; | 232 | ret = -ENOMEM; |
@@ -229,7 +238,8 @@ static int dell_setup_rfkill(void) | |||
229 | } | 238 | } |
230 | 239 | ||
231 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | 240 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { |
232 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, | 241 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", |
242 | &platform_device->dev, | ||
233 | RFKILL_TYPE_BLUETOOTH, | 243 | RFKILL_TYPE_BLUETOOTH, |
234 | &dell_rfkill_ops, (void *) 2); | 244 | &dell_rfkill_ops, (void *) 2); |
235 | if (!bluetooth_rfkill) { | 245 | if (!bluetooth_rfkill) { |
@@ -242,7 +252,9 @@ static int dell_setup_rfkill(void) | |||
242 | } | 252 | } |
243 | 253 | ||
244 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | 254 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { |
245 | wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, | 255 | wwan_rfkill = rfkill_alloc("dell-wwan", |
256 | &platform_device->dev, | ||
257 | RFKILL_TYPE_WWAN, | ||
246 | &dell_rfkill_ops, (void *) 3); | 258 | &dell_rfkill_ops, (void *) 3); |
247 | if (!wwan_rfkill) { | 259 | if (!wwan_rfkill) { |
248 | ret = -ENOMEM; | 260 | ret = -ENOMEM; |
@@ -268,6 +280,22 @@ err_wifi: | |||
268 | return ret; | 280 | return ret; |
269 | } | 281 | } |
270 | 282 | ||
283 | static void dell_cleanup_rfkill(void) | ||
284 | { | ||
285 | if (wifi_rfkill) { | ||
286 | rfkill_unregister(wifi_rfkill); | ||
287 | rfkill_destroy(wifi_rfkill); | ||
288 | } | ||
289 | if (bluetooth_rfkill) { | ||
290 | rfkill_unregister(bluetooth_rfkill); | ||
291 | rfkill_destroy(bluetooth_rfkill); | ||
292 | } | ||
293 | if (wwan_rfkill) { | ||
294 | rfkill_unregister(wwan_rfkill); | ||
295 | rfkill_destroy(wwan_rfkill); | ||
296 | } | ||
297 | } | ||
298 | |||
271 | static int dell_send_intensity(struct backlight_device *bd) | 299 | static int dell_send_intensity(struct backlight_device *bd) |
272 | { | 300 | { |
273 | struct calling_interface_buffer buffer; | 301 | struct calling_interface_buffer buffer; |
@@ -326,11 +354,23 @@ static int __init dell_init(void) | |||
326 | return -ENODEV; | 354 | return -ENODEV; |
327 | } | 355 | } |
328 | 356 | ||
357 | ret = platform_driver_register(&platform_driver); | ||
358 | if (ret) | ||
359 | goto fail_platform_driver; | ||
360 | platform_device = platform_device_alloc("dell-laptop", -1); | ||
361 | if (!platform_device) { | ||
362 | ret = -ENOMEM; | ||
363 | goto fail_platform_device1; | ||
364 | } | ||
365 | ret = platform_device_add(platform_device); | ||
366 | if (ret) | ||
367 | goto fail_platform_device2; | ||
368 | |||
329 | ret = dell_setup_rfkill(); | 369 | ret = dell_setup_rfkill(); |
330 | 370 | ||
331 | if (ret) { | 371 | if (ret) { |
332 | printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); | 372 | printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); |
333 | goto out; | 373 | goto fail_rfkill; |
334 | } | 374 | } |
335 | 375 | ||
336 | #ifdef CONFIG_ACPI | 376 | #ifdef CONFIG_ACPI |
@@ -352,13 +392,13 @@ static int __init dell_init(void) | |||
352 | if (max_intensity) { | 392 | if (max_intensity) { |
353 | dell_backlight_device = backlight_device_register( | 393 | dell_backlight_device = backlight_device_register( |
354 | "dell_backlight", | 394 | "dell_backlight", |
355 | NULL, NULL, | 395 | &platform_device->dev, NULL, |
356 | &dell_ops); | 396 | &dell_ops); |
357 | 397 | ||
358 | if (IS_ERR(dell_backlight_device)) { | 398 | if (IS_ERR(dell_backlight_device)) { |
359 | ret = PTR_ERR(dell_backlight_device); | 399 | ret = PTR_ERR(dell_backlight_device); |
360 | dell_backlight_device = NULL; | 400 | dell_backlight_device = NULL; |
361 | goto out; | 401 | goto fail_backlight; |
362 | } | 402 | } |
363 | 403 | ||
364 | dell_backlight_device->props.max_brightness = max_intensity; | 404 | dell_backlight_device->props.max_brightness = max_intensity; |
@@ -368,13 +408,16 @@ static int __init dell_init(void) | |||
368 | } | 408 | } |
369 | 409 | ||
370 | return 0; | 410 | return 0; |
371 | out: | 411 | |
372 | if (wifi_rfkill) | 412 | fail_backlight: |
373 | rfkill_unregister(wifi_rfkill); | 413 | dell_cleanup_rfkill(); |
374 | if (bluetooth_rfkill) | 414 | fail_rfkill: |
375 | rfkill_unregister(bluetooth_rfkill); | 415 | platform_device_del(platform_device); |
376 | if (wwan_rfkill) | 416 | fail_platform_device2: |
377 | rfkill_unregister(wwan_rfkill); | 417 | platform_device_put(platform_device); |
418 | fail_platform_device1: | ||
419 | platform_driver_unregister(&platform_driver); | ||
420 | fail_platform_driver: | ||
378 | kfree(da_tokens); | 421 | kfree(da_tokens); |
379 | return ret; | 422 | return ret; |
380 | } | 423 | } |
@@ -382,12 +425,7 @@ out: | |||
382 | static void __exit dell_exit(void) | 425 | static void __exit dell_exit(void) |
383 | { | 426 | { |
384 | backlight_device_unregister(dell_backlight_device); | 427 | backlight_device_unregister(dell_backlight_device); |
385 | if (wifi_rfkill) | 428 | dell_cleanup_rfkill(); |
386 | rfkill_unregister(wifi_rfkill); | ||
387 | if (bluetooth_rfkill) | ||
388 | rfkill_unregister(bluetooth_rfkill); | ||
389 | if (wwan_rfkill) | ||
390 | rfkill_unregister(wwan_rfkill); | ||
391 | } | 429 | } |
392 | 430 | ||
393 | module_init(dell_init); | 431 | module_init(dell_init); |
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 0f900cc9fa7a..67f3fe71c509 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <acpi/acpi_drivers.h> | 31 | #include <acpi/acpi_drivers.h> |
32 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/dmi.h> | ||
34 | 35 | ||
35 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | 36 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); |
36 | MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); | 37 | MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); |
@@ -38,6 +39,8 @@ MODULE_LICENSE("GPL"); | |||
38 | 39 | ||
39 | #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" | 40 | #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" |
40 | 41 | ||
42 | static int acpi_video; | ||
43 | |||
41 | MODULE_ALIAS("wmi:"DELL_EVENT_GUID); | 44 | MODULE_ALIAS("wmi:"DELL_EVENT_GUID); |
42 | 45 | ||
43 | struct key_entry { | 46 | struct key_entry { |
@@ -54,7 +57,7 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END }; | |||
54 | * via the keyboard controller so should not be sent again. | 57 | * via the keyboard controller so should not be sent again. |
55 | */ | 58 | */ |
56 | 59 | ||
57 | static struct key_entry dell_wmi_keymap[] = { | 60 | static struct key_entry dell_legacy_wmi_keymap[] = { |
58 | {KE_KEY, 0xe045, KEY_PROG1}, | 61 | {KE_KEY, 0xe045, KEY_PROG1}, |
59 | {KE_KEY, 0xe009, KEY_EJECTCD}, | 62 | {KE_KEY, 0xe009, KEY_EJECTCD}, |
60 | 63 | ||
@@ -72,7 +75,7 @@ static struct key_entry dell_wmi_keymap[] = { | |||
72 | 75 | ||
73 | /* The next device is at offset 6, the active devices are at | 76 | /* The next device is at offset 6, the active devices are at |
74 | offset 8 and the attached devices at offset 10 */ | 77 | offset 8 and the attached devices at offset 10 */ |
75 | {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE}, | 78 | {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE}, |
76 | 79 | ||
77 | {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, | 80 | {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, |
78 | 81 | ||
@@ -96,6 +99,47 @@ static struct key_entry dell_wmi_keymap[] = { | |||
96 | {KE_END, 0} | 99 | {KE_END, 0} |
97 | }; | 100 | }; |
98 | 101 | ||
102 | static bool dell_new_hk_type; | ||
103 | |||
104 | struct dell_new_keymap_entry { | ||
105 | u16 scancode; | ||
106 | u16 keycode; | ||
107 | }; | ||
108 | |||
109 | struct dell_hotkey_table { | ||
110 | struct dmi_header header; | ||
111 | struct dell_new_keymap_entry keymap[]; | ||
112 | |||
113 | }; | ||
114 | |||
115 | static struct key_entry *dell_new_wmi_keymap; | ||
116 | |||
117 | static u16 bios_to_linux_keycode[256] = { | ||
118 | |||
119 | KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG, | ||
120 | KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
121 | KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE, | ||
122 | KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD, | ||
123 | KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN, | ||
124 | KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, | ||
125 | KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, | ||
126 | KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, | ||
127 | KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
128 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
129 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
130 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
131 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
132 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
137 | KEY_PROG3 | ||
138 | }; | ||
139 | |||
140 | |||
141 | static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap; | ||
142 | |||
99 | static struct input_dev *dell_wmi_input_dev; | 143 | static struct input_dev *dell_wmi_input_dev; |
100 | 144 | ||
101 | static struct key_entry *dell_wmi_get_entry_by_scancode(int code) | 145 | static struct key_entry *dell_wmi_get_entry_by_scancode(int code) |
@@ -164,24 +208,78 @@ static void dell_wmi_notify(u32 value, void *context) | |||
164 | obj = (union acpi_object *)response.pointer; | 208 | obj = (union acpi_object *)response.pointer; |
165 | 209 | ||
166 | if (obj && obj->type == ACPI_TYPE_BUFFER) { | 210 | if (obj && obj->type == ACPI_TYPE_BUFFER) { |
167 | int *buffer = (int *)obj->buffer.pointer; | 211 | int reported_key; |
168 | /* | 212 | u16 *buffer_entry = (u16 *)obj->buffer.pointer; |
169 | * The upper bytes of the event may contain | 213 | if (dell_new_hk_type && (buffer_entry[1] != 0x10)) { |
170 | * additional information, so mask them off for the | 214 | printk(KERN_INFO "dell-wmi: Received unknown WMI event" |
171 | * scancode lookup | 215 | " (0x%x)\n", buffer_entry[1]); |
172 | */ | 216 | return; |
173 | key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF); | 217 | } |
174 | if (key) { | 218 | |
219 | if (dell_new_hk_type) | ||
220 | reported_key = (int)buffer_entry[2]; | ||
221 | else | ||
222 | reported_key = (int)buffer_entry[1] & 0xffff; | ||
223 | |||
224 | key = dell_wmi_get_entry_by_scancode(reported_key); | ||
225 | |||
226 | if (!key) { | ||
227 | printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", | ||
228 | reported_key); | ||
229 | } else if ((key->keycode == KEY_BRIGHTNESSUP || | ||
230 | key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) { | ||
231 | /* Don't report brightness notifications that will also | ||
232 | * come via ACPI */ | ||
233 | return; | ||
234 | } else { | ||
175 | input_report_key(dell_wmi_input_dev, key->keycode, 1); | 235 | input_report_key(dell_wmi_input_dev, key->keycode, 1); |
176 | input_sync(dell_wmi_input_dev); | 236 | input_sync(dell_wmi_input_dev); |
177 | input_report_key(dell_wmi_input_dev, key->keycode, 0); | 237 | input_report_key(dell_wmi_input_dev, key->keycode, 0); |
178 | input_sync(dell_wmi_input_dev); | 238 | input_sync(dell_wmi_input_dev); |
179 | } else if (buffer[1] & 0xFFFF) | 239 | } |
180 | printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", | ||
181 | buffer[1] & 0xFFFF); | ||
182 | } | 240 | } |
183 | } | 241 | } |
184 | 242 | ||
243 | |||
244 | static void setup_new_hk_map(const struct dmi_header *dm) | ||
245 | { | ||
246 | |||
247 | int i; | ||
248 | int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry); | ||
249 | struct dell_hotkey_table *table = | ||
250 | container_of(dm, struct dell_hotkey_table, header); | ||
251 | |||
252 | dell_new_wmi_keymap = kzalloc((hotkey_num+1) * | ||
253 | sizeof(struct key_entry), GFP_KERNEL); | ||
254 | |||
255 | for (i = 0; i < hotkey_num; i++) { | ||
256 | dell_new_wmi_keymap[i].type = KE_KEY; | ||
257 | dell_new_wmi_keymap[i].code = table->keymap[i].scancode; | ||
258 | dell_new_wmi_keymap[i].keycode = | ||
259 | (table->keymap[i].keycode > 255) ? 0 : | ||
260 | bios_to_linux_keycode[table->keymap[i].keycode]; | ||
261 | } | ||
262 | |||
263 | dell_new_wmi_keymap[i].type = KE_END; | ||
264 | dell_new_wmi_keymap[i].code = 0; | ||
265 | dell_new_wmi_keymap[i].keycode = 0; | ||
266 | |||
267 | dell_wmi_keymap = dell_new_wmi_keymap; | ||
268 | |||
269 | } | ||
270 | |||
271 | |||
272 | static void find_hk_type(const struct dmi_header *dm, void *dummy) | ||
273 | { | ||
274 | |||
275 | if ((dm->type == 0xb2) && (dm->length > 6)) { | ||
276 | dell_new_hk_type = true; | ||
277 | setup_new_hk_map(dm); | ||
278 | } | ||
279 | |||
280 | } | ||
281 | |||
282 | |||
185 | static int __init dell_wmi_input_setup(void) | 283 | static int __init dell_wmi_input_setup(void) |
186 | { | 284 | { |
187 | struct key_entry *key; | 285 | struct key_entry *key; |
@@ -226,6 +324,9 @@ static int __init dell_wmi_init(void) | |||
226 | int err; | 324 | int err; |
227 | 325 | ||
228 | if (wmi_has_guid(DELL_EVENT_GUID)) { | 326 | if (wmi_has_guid(DELL_EVENT_GUID)) { |
327 | |||
328 | dmi_walk(find_hk_type, NULL); | ||
329 | |||
229 | err = dell_wmi_input_setup(); | 330 | err = dell_wmi_input_setup(); |
230 | 331 | ||
231 | if (err) | 332 | if (err) |
@@ -240,6 +341,8 @@ static int __init dell_wmi_init(void) | |||
240 | return err; | 341 | return err; |
241 | } | 342 | } |
242 | 343 | ||
344 | acpi_video = acpi_video_backlight_support(); | ||
345 | |||
243 | } else | 346 | } else |
244 | printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); | 347 | printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); |
245 | 348 | ||
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index e647a856b9bf..5838c69b2fb3 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * eepc-laptop.c - Asus Eee PC extras | 2 | * eeepc-laptop.c - Asus Eee PC extras |
3 | * | 3 | * |
4 | * Based on asus_acpi.c as patched for the Eee PC by Asus: | 4 | * Based on asus_acpi.c as patched for the Eee PC by Asus: |
5 | * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar | 5 | * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar |
@@ -34,20 +34,23 @@ | |||
34 | #include <linux/rfkill.h> | 34 | #include <linux/rfkill.h> |
35 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
36 | #include <linux/pci_hotplug.h> | 36 | #include <linux/pci_hotplug.h> |
37 | #include <linux/leds.h> | ||
37 | 38 | ||
38 | #define EEEPC_LAPTOP_VERSION "0.1" | 39 | #define EEEPC_LAPTOP_VERSION "0.1" |
40 | #define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" | ||
41 | #define EEEPC_LAPTOP_FILE "eeepc" | ||
39 | 42 | ||
40 | #define EEEPC_HOTK_NAME "Eee PC Hotkey Driver" | 43 | #define EEEPC_ACPI_CLASS "hotkey" |
41 | #define EEEPC_HOTK_FILE "eeepc" | 44 | #define EEEPC_ACPI_DEVICE_NAME "Hotkey" |
42 | #define EEEPC_HOTK_CLASS "hotkey" | 45 | #define EEEPC_ACPI_HID "ASUS010" |
43 | #define EEEPC_HOTK_DEVICE_NAME "Hotkey" | ||
44 | #define EEEPC_HOTK_HID "ASUS010" | ||
45 | 46 | ||
47 | MODULE_AUTHOR("Corentin Chary, Eric Cooper"); | ||
48 | MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME); | ||
49 | MODULE_LICENSE("GPL"); | ||
46 | 50 | ||
47 | /* | 51 | /* |
48 | * Definitions for Asus EeePC | 52 | * Definitions for Asus EeePC |
49 | */ | 53 | */ |
50 | #define NOTIFY_WLAN_ON 0x10 | ||
51 | #define NOTIFY_BRN_MIN 0x20 | 54 | #define NOTIFY_BRN_MIN 0x20 |
52 | #define NOTIFY_BRN_MAX 0x2f | 55 | #define NOTIFY_BRN_MAX 0x2f |
53 | 56 | ||
@@ -117,58 +120,6 @@ static const char *cm_setv[] = { | |||
117 | NULL, NULL, "PBPS", "TPDS" | 120 | NULL, NULL, "PBPS", "TPDS" |
118 | }; | 121 | }; |
119 | 122 | ||
120 | #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." | ||
121 | |||
122 | #define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */ | ||
123 | #define EEEPC_EC_SC02 0x63 | ||
124 | #define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */ | ||
125 | #define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */ | ||
126 | #define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */ | ||
127 | #define EEEPC_EC_SFB3 0xD3 | ||
128 | |||
129 | /* | ||
130 | * This is the main structure, we can use it to store useful information | ||
131 | * about the hotk device | ||
132 | */ | ||
133 | struct eeepc_hotk { | ||
134 | struct acpi_device *device; /* the device we are in */ | ||
135 | acpi_handle handle; /* the handle of the hotk device */ | ||
136 | u32 cm_supported; /* the control methods supported | ||
137 | by this BIOS */ | ||
138 | uint init_flag; /* Init flags */ | ||
139 | u16 event_count[128]; /* count for each event */ | ||
140 | struct input_dev *inputdev; | ||
141 | u16 *keycode_map; | ||
142 | struct rfkill *wlan_rfkill; | ||
143 | struct rfkill *bluetooth_rfkill; | ||
144 | struct rfkill *wwan3g_rfkill; | ||
145 | struct rfkill *wimax_rfkill; | ||
146 | struct hotplug_slot *hotplug_slot; | ||
147 | struct mutex hotplug_lock; | ||
148 | }; | ||
149 | |||
150 | /* The actual device the driver binds to */ | ||
151 | static struct eeepc_hotk *ehotk; | ||
152 | |||
153 | /* Platform device/driver */ | ||
154 | static int eeepc_hotk_thaw(struct device *device); | ||
155 | static int eeepc_hotk_restore(struct device *device); | ||
156 | |||
157 | static const struct dev_pm_ops eeepc_pm_ops = { | ||
158 | .thaw = eeepc_hotk_thaw, | ||
159 | .restore = eeepc_hotk_restore, | ||
160 | }; | ||
161 | |||
162 | static struct platform_driver platform_driver = { | ||
163 | .driver = { | ||
164 | .name = EEEPC_HOTK_FILE, | ||
165 | .owner = THIS_MODULE, | ||
166 | .pm = &eeepc_pm_ops, | ||
167 | } | ||
168 | }; | ||
169 | |||
170 | static struct platform_device *platform_device; | ||
171 | |||
172 | struct key_entry { | 123 | struct key_entry { |
173 | char type; | 124 | char type; |
174 | u8 code; | 125 | u8 code; |
@@ -177,7 +128,7 @@ struct key_entry { | |||
177 | 128 | ||
178 | enum { KE_KEY, KE_END }; | 129 | enum { KE_KEY, KE_END }; |
179 | 130 | ||
180 | static struct key_entry eeepc_keymap[] = { | 131 | static const struct key_entry eeepc_keymap[] = { |
181 | /* Sleep already handled via generic ACPI code */ | 132 | /* Sleep already handled via generic ACPI code */ |
182 | {KE_KEY, 0x10, KEY_WLAN }, | 133 | {KE_KEY, 0x10, KEY_WLAN }, |
183 | {KE_KEY, 0x11, KEY_WLAN }, | 134 | {KE_KEY, 0x11, KEY_WLAN }, |
@@ -185,77 +136,56 @@ static struct key_entry eeepc_keymap[] = { | |||
185 | {KE_KEY, 0x13, KEY_MUTE }, | 136 | {KE_KEY, 0x13, KEY_MUTE }, |
186 | {KE_KEY, 0x14, KEY_VOLUMEDOWN }, | 137 | {KE_KEY, 0x14, KEY_VOLUMEDOWN }, |
187 | {KE_KEY, 0x15, KEY_VOLUMEUP }, | 138 | {KE_KEY, 0x15, KEY_VOLUMEUP }, |
139 | {KE_KEY, 0x16, KEY_DISPLAY_OFF }, | ||
188 | {KE_KEY, 0x1a, KEY_COFFEE }, | 140 | {KE_KEY, 0x1a, KEY_COFFEE }, |
189 | {KE_KEY, 0x1b, KEY_ZOOM }, | 141 | {KE_KEY, 0x1b, KEY_ZOOM }, |
190 | {KE_KEY, 0x1c, KEY_PROG2 }, | 142 | {KE_KEY, 0x1c, KEY_PROG2 }, |
191 | {KE_KEY, 0x1d, KEY_PROG3 }, | 143 | {KE_KEY, 0x1d, KEY_PROG3 }, |
192 | {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN }, | 144 | {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN }, |
193 | {KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP }, | 145 | {KE_KEY, NOTIFY_BRN_MAX, KEY_BRIGHTNESSUP }, |
194 | {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, | 146 | {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, |
195 | {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, | 147 | {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, |
196 | {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, | 148 | {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, |
149 | {KE_KEY, 0x37, KEY_F13 }, /* Disable Touchpad */ | ||
150 | {KE_KEY, 0x38, KEY_F14 }, | ||
197 | {KE_END, 0}, | 151 | {KE_END, 0}, |
198 | }; | 152 | }; |
199 | 153 | ||
154 | |||
200 | /* | 155 | /* |
201 | * The hotkey driver declaration | 156 | * This is the main structure, we can use it to store useful information |
202 | */ | 157 | */ |
203 | static int eeepc_hotk_add(struct acpi_device *device); | 158 | struct eeepc_laptop { |
204 | static int eeepc_hotk_remove(struct acpi_device *device, int type); | 159 | acpi_handle handle; /* the handle of the acpi device */ |
205 | static void eeepc_hotk_notify(struct acpi_device *device, u32 event); | 160 | u32 cm_supported; /* the control methods supported |
206 | 161 | by this BIOS */ | |
207 | static const struct acpi_device_id eeepc_device_ids[] = { | 162 | u16 event_count[128]; /* count for each event */ |
208 | {EEEPC_HOTK_HID, 0}, | ||
209 | {"", 0}, | ||
210 | }; | ||
211 | MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); | ||
212 | |||
213 | static struct acpi_driver eeepc_hotk_driver = { | ||
214 | .name = EEEPC_HOTK_NAME, | ||
215 | .class = EEEPC_HOTK_CLASS, | ||
216 | .ids = eeepc_device_ids, | ||
217 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | ||
218 | .ops = { | ||
219 | .add = eeepc_hotk_add, | ||
220 | .remove = eeepc_hotk_remove, | ||
221 | .notify = eeepc_hotk_notify, | ||
222 | }, | ||
223 | }; | ||
224 | 163 | ||
225 | /* PCI hotplug ops */ | 164 | struct platform_device *platform_device; |
226 | static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value); | 165 | struct device *hwmon_device; |
166 | struct backlight_device *backlight_device; | ||
227 | 167 | ||
228 | static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { | 168 | struct input_dev *inputdev; |
229 | .owner = THIS_MODULE, | 169 | struct key_entry *keymap; |
230 | .get_adapter_status = eeepc_get_adapter_status, | ||
231 | .get_power_status = eeepc_get_adapter_status, | ||
232 | }; | ||
233 | 170 | ||
234 | /* The backlight device /sys/class/backlight */ | 171 | struct rfkill *wlan_rfkill; |
235 | static struct backlight_device *eeepc_backlight_device; | 172 | struct rfkill *bluetooth_rfkill; |
173 | struct rfkill *wwan3g_rfkill; | ||
174 | struct rfkill *wimax_rfkill; | ||
236 | 175 | ||
237 | /* The hwmon device */ | 176 | struct hotplug_slot *hotplug_slot; |
238 | static struct device *eeepc_hwmon_device; | 177 | struct mutex hotplug_lock; |
239 | 178 | ||
240 | /* | 179 | struct led_classdev tpd_led; |
241 | * The backlight class declaration | 180 | int tpd_led_wk; |
242 | */ | 181 | struct workqueue_struct *led_workqueue; |
243 | static int read_brightness(struct backlight_device *bd); | 182 | struct work_struct tpd_led_work; |
244 | static int update_bl_status(struct backlight_device *bd); | ||
245 | static struct backlight_ops eeepcbl_ops = { | ||
246 | .get_brightness = read_brightness, | ||
247 | .update_status = update_bl_status, | ||
248 | }; | 183 | }; |
249 | 184 | ||
250 | MODULE_AUTHOR("Corentin Chary, Eric Cooper"); | ||
251 | MODULE_DESCRIPTION(EEEPC_HOTK_NAME); | ||
252 | MODULE_LICENSE("GPL"); | ||
253 | |||
254 | /* | 185 | /* |
255 | * ACPI Helpers | 186 | * ACPI Helpers |
256 | */ | 187 | */ |
257 | static int write_acpi_int(acpi_handle handle, const char *method, int val, | 188 | static int write_acpi_int(acpi_handle handle, const char *method, int val) |
258 | struct acpi_buffer *output) | ||
259 | { | 189 | { |
260 | struct acpi_object_list params; | 190 | struct acpi_object_list params; |
261 | union acpi_object in_obj; | 191 | union acpi_object in_obj; |
@@ -266,7 +196,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val, | |||
266 | in_obj.type = ACPI_TYPE_INTEGER; | 196 | in_obj.type = ACPI_TYPE_INTEGER; |
267 | in_obj.integer.value = val; | 197 | in_obj.integer.value = val; |
268 | 198 | ||
269 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); | 199 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, NULL); |
270 | return (status == AE_OK ? 0 : -1); | 200 | return (status == AE_OK ? 0 : -1); |
271 | } | 201 | } |
272 | 202 | ||
@@ -285,81 +215,56 @@ static int read_acpi_int(acpi_handle handle, const char *method, int *val) | |||
285 | } | 215 | } |
286 | } | 216 | } |
287 | 217 | ||
288 | static int set_acpi(int cm, int value) | 218 | static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value) |
289 | { | 219 | { |
290 | if (ehotk->cm_supported & (0x1 << cm)) { | 220 | const char *method = cm_setv[cm]; |
291 | const char *method = cm_setv[cm]; | ||
292 | if (method == NULL) | ||
293 | return -ENODEV; | ||
294 | if (write_acpi_int(ehotk->handle, method, value, NULL)) | ||
295 | pr_warning("Error writing %s\n", method); | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | 221 | ||
300 | static int get_acpi(int cm) | 222 | if (method == NULL) |
301 | { | 223 | return -ENODEV; |
302 | int value = -ENODEV; | 224 | if ((eeepc->cm_supported & (0x1 << cm)) == 0) |
303 | if ((ehotk->cm_supported & (0x1 << cm))) { | 225 | return -ENODEV; |
304 | const char *method = cm_getv[cm]; | ||
305 | if (method == NULL) | ||
306 | return -ENODEV; | ||
307 | if (read_acpi_int(ehotk->handle, method, &value)) | ||
308 | pr_warning("Error reading %s\n", method); | ||
309 | } | ||
310 | return value; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Backlight | ||
315 | */ | ||
316 | static int read_brightness(struct backlight_device *bd) | ||
317 | { | ||
318 | return get_acpi(CM_ASL_PANELBRIGHT); | ||
319 | } | ||
320 | 226 | ||
321 | static int set_brightness(struct backlight_device *bd, int value) | 227 | if (write_acpi_int(eeepc->handle, method, value)) |
322 | { | 228 | pr_warning("Error writing %s\n", method); |
323 | value = max(0, min(15, value)); | 229 | return 0; |
324 | return set_acpi(CM_ASL_PANELBRIGHT, value); | ||
325 | } | 230 | } |
326 | 231 | ||
327 | static int update_bl_status(struct backlight_device *bd) | 232 | static int get_acpi(struct eeepc_laptop *eeepc, int cm) |
328 | { | 233 | { |
329 | return set_brightness(bd, bd->props.brightness); | 234 | const char *method = cm_getv[cm]; |
330 | } | 235 | int value; |
331 | 236 | ||
332 | /* | 237 | if (method == NULL) |
333 | * Rfkill helpers | 238 | return -ENODEV; |
334 | */ | 239 | if ((eeepc->cm_supported & (0x1 << cm)) == 0) |
240 | return -ENODEV; | ||
335 | 241 | ||
336 | static bool eeepc_wlan_rfkill_blocked(void) | 242 | if (read_acpi_int(eeepc->handle, method, &value)) |
337 | { | 243 | pr_warning("Error reading %s\n", method); |
338 | if (get_acpi(CM_ASL_WLAN) == 1) | 244 | return value; |
339 | return false; | ||
340 | return true; | ||
341 | } | 245 | } |
342 | 246 | ||
343 | static int eeepc_rfkill_set(void *data, bool blocked) | 247 | static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm, |
248 | acpi_handle *handle) | ||
344 | { | 249 | { |
345 | unsigned long asl = (unsigned long)data; | 250 | const char *method = cm_setv[cm]; |
346 | return set_acpi(asl, !blocked); | 251 | acpi_status status; |
347 | } | ||
348 | 252 | ||
349 | static const struct rfkill_ops eeepc_rfkill_ops = { | 253 | if (method == NULL) |
350 | .set_block = eeepc_rfkill_set, | 254 | return -ENODEV; |
351 | }; | 255 | if ((eeepc->cm_supported & (0x1 << cm)) == 0) |
256 | return -ENODEV; | ||
352 | 257 | ||
353 | static void __devinit eeepc_enable_camera(void) | 258 | status = acpi_get_handle(eeepc->handle, (char *)method, |
354 | { | 259 | handle); |
355 | /* | 260 | if (status != AE_OK) { |
356 | * If the following call to set_acpi() fails, it's because there's no | 261 | pr_warning("Error finding %s\n", method); |
357 | * camera so we can ignore the error. | 262 | return -ENODEV; |
358 | */ | 263 | } |
359 | if (get_acpi(CM_ASL_CAMERA) == 0) | 264 | return 0; |
360 | set_acpi(CM_ASL_CAMERA, 1); | ||
361 | } | 265 | } |
362 | 266 | ||
267 | |||
363 | /* | 268 | /* |
364 | * Sys helpers | 269 | * Sys helpers |
365 | */ | 270 | */ |
@@ -372,60 +277,63 @@ static int parse_arg(const char *buf, unsigned long count, int *val) | |||
372 | return count; | 277 | return count; |
373 | } | 278 | } |
374 | 279 | ||
375 | static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) | 280 | static ssize_t store_sys_acpi(struct device *dev, int cm, |
281 | const char *buf, size_t count) | ||
376 | { | 282 | { |
283 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
377 | int rv, value; | 284 | int rv, value; |
378 | 285 | ||
379 | rv = parse_arg(buf, count, &value); | 286 | rv = parse_arg(buf, count, &value); |
380 | if (rv > 0) | 287 | if (rv > 0) |
381 | value = set_acpi(cm, value); | 288 | value = set_acpi(eeepc, cm, value); |
382 | if (value < 0) | 289 | if (value < 0) |
383 | return value; | 290 | return -EIO; |
384 | return rv; | 291 | return rv; |
385 | } | 292 | } |
386 | 293 | ||
387 | static ssize_t show_sys_acpi(int cm, char *buf) | 294 | static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf) |
388 | { | 295 | { |
389 | int value = get_acpi(cm); | 296 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); |
297 | int value = get_acpi(eeepc, cm); | ||
390 | 298 | ||
391 | if (value < 0) | 299 | if (value < 0) |
392 | return value; | 300 | return -EIO; |
393 | return sprintf(buf, "%d\n", value); | 301 | return sprintf(buf, "%d\n", value); |
394 | } | 302 | } |
395 | 303 | ||
396 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ | 304 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ |
397 | static ssize_t show_##_name(struct device *dev, \ | 305 | static ssize_t show_##_name(struct device *dev, \ |
398 | struct device_attribute *attr, \ | 306 | struct device_attribute *attr, \ |
399 | char *buf) \ | 307 | char *buf) \ |
400 | { \ | 308 | { \ |
401 | return show_sys_acpi(_cm, buf); \ | 309 | return show_sys_acpi(dev, _cm, buf); \ |
402 | } \ | 310 | } \ |
403 | static ssize_t store_##_name(struct device *dev, \ | 311 | static ssize_t store_##_name(struct device *dev, \ |
404 | struct device_attribute *attr, \ | 312 | struct device_attribute *attr, \ |
405 | const char *buf, size_t count) \ | 313 | const char *buf, size_t count) \ |
406 | { \ | 314 | { \ |
407 | return store_sys_acpi(_cm, buf, count); \ | 315 | return store_sys_acpi(dev, _cm, buf, count); \ |
408 | } \ | 316 | } \ |
409 | static struct device_attribute dev_attr_##_name = { \ | 317 | static struct device_attribute dev_attr_##_name = { \ |
410 | .attr = { \ | 318 | .attr = { \ |
411 | .name = __stringify(_name), \ | 319 | .name = __stringify(_name), \ |
412 | .mode = 0644 }, \ | 320 | .mode = _mode }, \ |
413 | .show = show_##_name, \ | 321 | .show = show_##_name, \ |
414 | .store = store_##_name, \ | 322 | .store = store_##_name, \ |
415 | } | 323 | } |
416 | 324 | ||
417 | EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); | 325 | EEEPC_CREATE_DEVICE_ATTR(camera, 0644, CM_ASL_CAMERA); |
418 | EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); | 326 | EEEPC_CREATE_DEVICE_ATTR(cardr, 0644, CM_ASL_CARDREADER); |
419 | EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); | 327 | EEEPC_CREATE_DEVICE_ATTR(disp, 0200, CM_ASL_DISPLAYSWITCH); |
420 | 328 | ||
421 | struct eeepc_cpufv { | 329 | struct eeepc_cpufv { |
422 | int num; | 330 | int num; |
423 | int cur; | 331 | int cur; |
424 | }; | 332 | }; |
425 | 333 | ||
426 | static int get_cpufv(struct eeepc_cpufv *c) | 334 | static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c) |
427 | { | 335 | { |
428 | c->cur = get_acpi(CM_ASL_CPUFV); | 336 | c->cur = get_acpi(eeepc, CM_ASL_CPUFV); |
429 | c->num = (c->cur >> 8) & 0xff; | 337 | c->num = (c->cur >> 8) & 0xff; |
430 | c->cur &= 0xff; | 338 | c->cur &= 0xff; |
431 | if (c->cur < 0 || c->num <= 0 || c->num > 12) | 339 | if (c->cur < 0 || c->num <= 0 || c->num > 12) |
@@ -437,11 +345,12 @@ static ssize_t show_available_cpufv(struct device *dev, | |||
437 | struct device_attribute *attr, | 345 | struct device_attribute *attr, |
438 | char *buf) | 346 | char *buf) |
439 | { | 347 | { |
348 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
440 | struct eeepc_cpufv c; | 349 | struct eeepc_cpufv c; |
441 | int i; | 350 | int i; |
442 | ssize_t len = 0; | 351 | ssize_t len = 0; |
443 | 352 | ||
444 | if (get_cpufv(&c)) | 353 | if (get_cpufv(eeepc, &c)) |
445 | return -ENODEV; | 354 | return -ENODEV; |
446 | for (i = 0; i < c.num; i++) | 355 | for (i = 0; i < c.num; i++) |
447 | len += sprintf(buf + len, "%d ", i); | 356 | len += sprintf(buf + len, "%d ", i); |
@@ -453,9 +362,10 @@ static ssize_t show_cpufv(struct device *dev, | |||
453 | struct device_attribute *attr, | 362 | struct device_attribute *attr, |
454 | char *buf) | 363 | char *buf) |
455 | { | 364 | { |
365 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
456 | struct eeepc_cpufv c; | 366 | struct eeepc_cpufv c; |
457 | 367 | ||
458 | if (get_cpufv(&c)) | 368 | if (get_cpufv(eeepc, &c)) |
459 | return -ENODEV; | 369 | return -ENODEV; |
460 | return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); | 370 | return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); |
461 | } | 371 | } |
@@ -464,17 +374,18 @@ static ssize_t store_cpufv(struct device *dev, | |||
464 | struct device_attribute *attr, | 374 | struct device_attribute *attr, |
465 | const char *buf, size_t count) | 375 | const char *buf, size_t count) |
466 | { | 376 | { |
377 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
467 | struct eeepc_cpufv c; | 378 | struct eeepc_cpufv c; |
468 | int rv, value; | 379 | int rv, value; |
469 | 380 | ||
470 | if (get_cpufv(&c)) | 381 | if (get_cpufv(eeepc, &c)) |
471 | return -ENODEV; | 382 | return -ENODEV; |
472 | rv = parse_arg(buf, count, &value); | 383 | rv = parse_arg(buf, count, &value); |
473 | if (rv < 0) | 384 | if (rv < 0) |
474 | return rv; | 385 | return rv; |
475 | if (!rv || value < 0 || value >= c.num) | 386 | if (!rv || value < 0 || value >= c.num) |
476 | return -EINVAL; | 387 | return -EINVAL; |
477 | set_acpi(CM_ASL_CPUFV, value); | 388 | set_acpi(eeepc, CM_ASL_CPUFV, value); |
478 | return rv; | 389 | return rv; |
479 | } | 390 | } |
480 | 391 | ||
@@ -506,156 +417,125 @@ static struct attribute_group platform_attribute_group = { | |||
506 | .attrs = platform_attributes | 417 | .attrs = platform_attributes |
507 | }; | 418 | }; |
508 | 419 | ||
509 | /* | 420 | static int eeepc_platform_init(struct eeepc_laptop *eeepc) |
510 | * Hotkey functions | ||
511 | */ | ||
512 | static struct key_entry *eepc_get_entry_by_scancode(int code) | ||
513 | { | 421 | { |
514 | struct key_entry *key; | 422 | int result; |
515 | |||
516 | for (key = eeepc_keymap; key->type != KE_END; key++) | ||
517 | if (code == key->code) | ||
518 | return key; | ||
519 | 423 | ||
520 | return NULL; | 424 | eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1); |
521 | } | 425 | if (!eeepc->platform_device) |
426 | return -ENOMEM; | ||
427 | platform_set_drvdata(eeepc->platform_device, eeepc); | ||
522 | 428 | ||
523 | static struct key_entry *eepc_get_entry_by_keycode(int code) | 429 | result = platform_device_add(eeepc->platform_device); |
524 | { | 430 | if (result) |
525 | struct key_entry *key; | 431 | goto fail_platform_device; |
526 | 432 | ||
527 | for (key = eeepc_keymap; key->type != KE_END; key++) | 433 | result = sysfs_create_group(&eeepc->platform_device->dev.kobj, |
528 | if (code == key->keycode && key->type == KE_KEY) | 434 | &platform_attribute_group); |
529 | return key; | 435 | if (result) |
436 | goto fail_sysfs; | ||
437 | return 0; | ||
530 | 438 | ||
531 | return NULL; | 439 | fail_sysfs: |
440 | platform_device_del(eeepc->platform_device); | ||
441 | fail_platform_device: | ||
442 | platform_device_put(eeepc->platform_device); | ||
443 | return result; | ||
532 | } | 444 | } |
533 | 445 | ||
534 | static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) | 446 | static void eeepc_platform_exit(struct eeepc_laptop *eeepc) |
535 | { | 447 | { |
536 | struct key_entry *key = eepc_get_entry_by_scancode(scancode); | 448 | sysfs_remove_group(&eeepc->platform_device->dev.kobj, |
449 | &platform_attribute_group); | ||
450 | platform_device_unregister(eeepc->platform_device); | ||
451 | } | ||
537 | 452 | ||
538 | if (key && key->type == KE_KEY) { | 453 | /* |
539 | *keycode = key->keycode; | 454 | * LEDs |
540 | return 0; | 455 | */ |
541 | } | 456 | /* |
457 | * These functions actually update the LED's, and are called from a | ||
458 | * workqueue. By doing this as separate work rather than when the LED | ||
459 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | ||
460 | * potentially bad time, such as a timer interrupt. | ||
461 | */ | ||
462 | static void tpd_led_update(struct work_struct *work) | ||
463 | { | ||
464 | struct eeepc_laptop *eeepc; | ||
542 | 465 | ||
543 | return -EINVAL; | 466 | eeepc = container_of(work, struct eeepc_laptop, tpd_led_work); |
467 | |||
468 | set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk); | ||
544 | } | 469 | } |
545 | 470 | ||
546 | static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) | 471 | static void tpd_led_set(struct led_classdev *led_cdev, |
472 | enum led_brightness value) | ||
547 | { | 473 | { |
548 | struct key_entry *key; | 474 | struct eeepc_laptop *eeepc; |
549 | int old_keycode; | ||
550 | 475 | ||
551 | if (keycode < 0 || keycode > KEY_MAX) | 476 | eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led); |
552 | return -EINVAL; | ||
553 | 477 | ||
554 | key = eepc_get_entry_by_scancode(scancode); | 478 | eeepc->tpd_led_wk = (value > 0) ? 1 : 0; |
555 | if (key && key->type == KE_KEY) { | 479 | queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); |
556 | old_keycode = key->keycode; | ||
557 | key->keycode = keycode; | ||
558 | set_bit(keycode, dev->keybit); | ||
559 | if (!eepc_get_entry_by_keycode(old_keycode)) | ||
560 | clear_bit(old_keycode, dev->keybit); | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | return -EINVAL; | ||
565 | } | 480 | } |
566 | 481 | ||
567 | static void cmsg_quirk(int cm, const char *name) | 482 | static int eeepc_led_init(struct eeepc_laptop *eeepc) |
568 | { | 483 | { |
569 | int dummy; | 484 | int rv; |
570 | 485 | ||
571 | /* Some BIOSes do not report cm although it is avaliable. | 486 | if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV) |
572 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | 487 | return 0; |
573 | if (!(ehotk->cm_supported & (1 << cm)) | ||
574 | && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) { | ||
575 | pr_info("%s (%x) not reported by BIOS," | ||
576 | " enabling anyway\n", name, 1 << cm); | ||
577 | ehotk->cm_supported |= 1 << cm; | ||
578 | } | ||
579 | } | ||
580 | 488 | ||
581 | static void cmsg_quirks(void) | 489 | eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); |
582 | { | 490 | if (!eeepc->led_workqueue) |
583 | cmsg_quirk(CM_ASL_LID, "LID"); | 491 | return -ENOMEM; |
584 | cmsg_quirk(CM_ASL_TYPE, "TYPE"); | 492 | INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); |
585 | cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER"); | ||
586 | cmsg_quirk(CM_ASL_TPD, "TPD"); | ||
587 | } | ||
588 | 493 | ||
589 | static int eeepc_hotk_check(void) | 494 | eeepc->tpd_led.name = "eeepc::touchpad"; |
590 | { | 495 | eeepc->tpd_led.brightness_set = tpd_led_set; |
591 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 496 | eeepc->tpd_led.max_brightness = 1; |
592 | int result; | ||
593 | 497 | ||
594 | result = acpi_bus_get_status(ehotk->device); | 498 | rv = led_classdev_register(&eeepc->platform_device->dev, |
595 | if (result) | 499 | &eeepc->tpd_led); |
596 | return result; | 500 | if (rv) { |
597 | if (ehotk->device->status.present) { | 501 | destroy_workqueue(eeepc->led_workqueue); |
598 | if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, | 502 | return rv; |
599 | &buffer)) { | ||
600 | pr_err("Hotkey initialization failed\n"); | ||
601 | return -ENODEV; | ||
602 | } else { | ||
603 | pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag); | ||
604 | } | ||
605 | /* get control methods supported */ | ||
606 | if (read_acpi_int(ehotk->handle, "CMSG" | ||
607 | , &ehotk->cm_supported)) { | ||
608 | pr_err("Get control methods supported failed\n"); | ||
609 | return -ENODEV; | ||
610 | } else { | ||
611 | cmsg_quirks(); | ||
612 | pr_info("Get control methods supported: 0x%x\n", | ||
613 | ehotk->cm_supported); | ||
614 | } | ||
615 | } else { | ||
616 | pr_err("Hotkey device not present, aborting\n"); | ||
617 | return -EINVAL; | ||
618 | } | 503 | } |
504 | |||
619 | return 0; | 505 | return 0; |
620 | } | 506 | } |
621 | 507 | ||
622 | static int notify_brn(void) | 508 | static void eeepc_led_exit(struct eeepc_laptop *eeepc) |
623 | { | 509 | { |
624 | /* returns the *previous* brightness, or -1 */ | 510 | if (eeepc->tpd_led.dev) |
625 | struct backlight_device *bd = eeepc_backlight_device; | 511 | led_classdev_unregister(&eeepc->tpd_led); |
626 | if (bd) { | 512 | if (eeepc->led_workqueue) |
627 | int old = bd->props.brightness; | 513 | destroy_workqueue(eeepc->led_workqueue); |
628 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); | ||
629 | return old; | ||
630 | } | ||
631 | return -1; | ||
632 | } | 514 | } |
633 | 515 | ||
634 | static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, | ||
635 | u8 *value) | ||
636 | { | ||
637 | int val = get_acpi(CM_ASL_WLAN); | ||
638 | 516 | ||
639 | if (val == 1 || val == 0) | 517 | /* |
640 | *value = val; | 518 | * PCI hotplug (for wlan rfkill) |
641 | else | 519 | */ |
642 | return -EINVAL; | 520 | static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc) |
643 | 521 | { | |
644 | return 0; | 522 | if (get_acpi(eeepc, CM_ASL_WLAN) == 1) |
523 | return false; | ||
524 | return true; | ||
645 | } | 525 | } |
646 | 526 | ||
647 | static void eeepc_rfkill_hotplug(void) | 527 | static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) |
648 | { | 528 | { |
649 | struct pci_dev *dev; | 529 | struct pci_dev *dev; |
650 | struct pci_bus *bus; | 530 | struct pci_bus *bus; |
651 | bool blocked = eeepc_wlan_rfkill_blocked(); | 531 | bool blocked = eeepc_wlan_rfkill_blocked(eeepc); |
652 | 532 | ||
653 | if (ehotk->wlan_rfkill) | 533 | if (eeepc->wlan_rfkill) |
654 | rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); | 534 | rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); |
655 | 535 | ||
656 | mutex_lock(&ehotk->hotplug_lock); | 536 | mutex_lock(&eeepc->hotplug_lock); |
657 | 537 | ||
658 | if (ehotk->hotplug_slot) { | 538 | if (eeepc->hotplug_slot) { |
659 | bus = pci_find_bus(0, 1); | 539 | bus = pci_find_bus(0, 1); |
660 | if (!bus) { | 540 | if (!bus) { |
661 | pr_warning("Unable to find PCI bus 1?\n"); | 541 | pr_warning("Unable to find PCI bus 1?\n"); |
@@ -685,69 +565,23 @@ static void eeepc_rfkill_hotplug(void) | |||
685 | } | 565 | } |
686 | 566 | ||
687 | out_unlock: | 567 | out_unlock: |
688 | mutex_unlock(&ehotk->hotplug_lock); | 568 | mutex_unlock(&eeepc->hotplug_lock); |
689 | } | 569 | } |
690 | 570 | ||
691 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | 571 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) |
692 | { | 572 | { |
573 | struct eeepc_laptop *eeepc = data; | ||
574 | |||
693 | if (event != ACPI_NOTIFY_BUS_CHECK) | 575 | if (event != ACPI_NOTIFY_BUS_CHECK) |
694 | return; | 576 | return; |
695 | 577 | ||
696 | eeepc_rfkill_hotplug(); | 578 | eeepc_rfkill_hotplug(eeepc); |
697 | } | 579 | } |
698 | 580 | ||
699 | static void eeepc_hotk_notify(struct acpi_device *device, u32 event) | 581 | static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, |
582 | char *node) | ||
700 | { | 583 | { |
701 | static struct key_entry *key; | 584 | acpi_status status; |
702 | u16 count; | ||
703 | int brn = -ENODEV; | ||
704 | |||
705 | if (!ehotk) | ||
706 | return; | ||
707 | if (event > ACPI_MAX_SYS_NOTIFY) | ||
708 | return; | ||
709 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) | ||
710 | brn = notify_brn(); | ||
711 | count = ehotk->event_count[event % 128]++; | ||
712 | acpi_bus_generate_proc_event(ehotk->device, event, count); | ||
713 | acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class, | ||
714 | dev_name(&ehotk->device->dev), event, | ||
715 | count); | ||
716 | if (ehotk->inputdev) { | ||
717 | if (brn != -ENODEV) { | ||
718 | /* brightness-change events need special | ||
719 | * handling for conversion to key events | ||
720 | */ | ||
721 | if (brn < 0) | ||
722 | brn = event; | ||
723 | else | ||
724 | brn += NOTIFY_BRN_MIN; | ||
725 | if (event < brn) | ||
726 | event = NOTIFY_BRN_MIN; /* brightness down */ | ||
727 | else if (event > brn) | ||
728 | event = NOTIFY_BRN_MIN + 2; /* ... up */ | ||
729 | else | ||
730 | event = NOTIFY_BRN_MIN + 1; /* ... unchanged */ | ||
731 | } | ||
732 | key = eepc_get_entry_by_scancode(event); | ||
733 | if (key) { | ||
734 | switch (key->type) { | ||
735 | case KE_KEY: | ||
736 | input_report_key(ehotk->inputdev, key->keycode, | ||
737 | 1); | ||
738 | input_sync(ehotk->inputdev); | ||
739 | input_report_key(ehotk->inputdev, key->keycode, | ||
740 | 0); | ||
741 | input_sync(ehotk->inputdev); | ||
742 | break; | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | |||
748 | static int eeepc_register_rfkill_notifier(char *node) | ||
749 | { | ||
750 | acpi_status status = AE_OK; | ||
751 | acpi_handle handle; | 585 | acpi_handle handle; |
752 | 586 | ||
753 | status = acpi_get_handle(NULL, node, &handle); | 587 | status = acpi_get_handle(NULL, node, &handle); |
@@ -756,7 +590,7 @@ static int eeepc_register_rfkill_notifier(char *node) | |||
756 | status = acpi_install_notify_handler(handle, | 590 | status = acpi_install_notify_handler(handle, |
757 | ACPI_SYSTEM_NOTIFY, | 591 | ACPI_SYSTEM_NOTIFY, |
758 | eeepc_rfkill_notify, | 592 | eeepc_rfkill_notify, |
759 | NULL); | 593 | eeepc); |
760 | if (ACPI_FAILURE(status)) | 594 | if (ACPI_FAILURE(status)) |
761 | pr_warning("Failed to register notify on %s\n", node); | 595 | pr_warning("Failed to register notify on %s\n", node); |
762 | } else | 596 | } else |
@@ -765,7 +599,8 @@ static int eeepc_register_rfkill_notifier(char *node) | |||
765 | return 0; | 599 | return 0; |
766 | } | 600 | } |
767 | 601 | ||
768 | static void eeepc_unregister_rfkill_notifier(char *node) | 602 | static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, |
603 | char *node) | ||
769 | { | 604 | { |
770 | acpi_status status = AE_OK; | 605 | acpi_status status = AE_OK; |
771 | acpi_handle handle; | 606 | acpi_handle handle; |
@@ -782,13 +617,33 @@ static void eeepc_unregister_rfkill_notifier(char *node) | |||
782 | } | 617 | } |
783 | } | 618 | } |
784 | 619 | ||
620 | static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, | ||
621 | u8 *value) | ||
622 | { | ||
623 | struct eeepc_laptop *eeepc = hotplug_slot->private; | ||
624 | int val = get_acpi(eeepc, CM_ASL_WLAN); | ||
625 | |||
626 | if (val == 1 || val == 0) | ||
627 | *value = val; | ||
628 | else | ||
629 | return -EINVAL; | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
785 | static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) | 634 | static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) |
786 | { | 635 | { |
787 | kfree(hotplug_slot->info); | 636 | kfree(hotplug_slot->info); |
788 | kfree(hotplug_slot); | 637 | kfree(hotplug_slot); |
789 | } | 638 | } |
790 | 639 | ||
791 | static int eeepc_setup_pci_hotplug(void) | 640 | static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { |
641 | .owner = THIS_MODULE, | ||
642 | .get_adapter_status = eeepc_get_adapter_status, | ||
643 | .get_power_status = eeepc_get_adapter_status, | ||
644 | }; | ||
645 | |||
646 | static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc) | ||
792 | { | 647 | { |
793 | int ret = -ENOMEM; | 648 | int ret = -ENOMEM; |
794 | struct pci_bus *bus = pci_find_bus(0, 1); | 649 | struct pci_bus *bus = pci_find_bus(0, 1); |
@@ -798,22 +653,22 @@ static int eeepc_setup_pci_hotplug(void) | |||
798 | return -ENODEV; | 653 | return -ENODEV; |
799 | } | 654 | } |
800 | 655 | ||
801 | ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | 656 | eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); |
802 | if (!ehotk->hotplug_slot) | 657 | if (!eeepc->hotplug_slot) |
803 | goto error_slot; | 658 | goto error_slot; |
804 | 659 | ||
805 | ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), | 660 | eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), |
806 | GFP_KERNEL); | 661 | GFP_KERNEL); |
807 | if (!ehotk->hotplug_slot->info) | 662 | if (!eeepc->hotplug_slot->info) |
808 | goto error_info; | 663 | goto error_info; |
809 | 664 | ||
810 | ehotk->hotplug_slot->private = ehotk; | 665 | eeepc->hotplug_slot->private = eeepc; |
811 | ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; | 666 | eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; |
812 | ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops; | 667 | eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; |
813 | eeepc_get_adapter_status(ehotk->hotplug_slot, | 668 | eeepc_get_adapter_status(eeepc->hotplug_slot, |
814 | &ehotk->hotplug_slot->info->adapter_status); | 669 | &eeepc->hotplug_slot->info->adapter_status); |
815 | 670 | ||
816 | ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi"); | 671 | ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); |
817 | if (ret) { | 672 | if (ret) { |
818 | pr_err("Unable to register hotplug slot - %d\n", ret); | 673 | pr_err("Unable to register hotplug slot - %d\n", ret); |
819 | goto error_register; | 674 | goto error_register; |
@@ -822,17 +677,156 @@ static int eeepc_setup_pci_hotplug(void) | |||
822 | return 0; | 677 | return 0; |
823 | 678 | ||
824 | error_register: | 679 | error_register: |
825 | kfree(ehotk->hotplug_slot->info); | 680 | kfree(eeepc->hotplug_slot->info); |
826 | error_info: | 681 | error_info: |
827 | kfree(ehotk->hotplug_slot); | 682 | kfree(eeepc->hotplug_slot); |
828 | ehotk->hotplug_slot = NULL; | 683 | eeepc->hotplug_slot = NULL; |
829 | error_slot: | 684 | error_slot: |
830 | return ret; | 685 | return ret; |
831 | } | 686 | } |
832 | 687 | ||
688 | /* | ||
689 | * Rfkill devices | ||
690 | */ | ||
691 | static int eeepc_rfkill_set(void *data, bool blocked) | ||
692 | { | ||
693 | acpi_handle handle = data; | ||
694 | |||
695 | return write_acpi_int(handle, NULL, !blocked); | ||
696 | } | ||
697 | |||
698 | static const struct rfkill_ops eeepc_rfkill_ops = { | ||
699 | .set_block = eeepc_rfkill_set, | ||
700 | }; | ||
701 | |||
702 | static int eeepc_new_rfkill(struct eeepc_laptop *eeepc, | ||
703 | struct rfkill **rfkill, | ||
704 | const char *name, | ||
705 | enum rfkill_type type, int cm) | ||
706 | { | ||
707 | acpi_handle handle; | ||
708 | int result; | ||
709 | |||
710 | result = acpi_setter_handle(eeepc, cm, &handle); | ||
711 | if (result < 0) | ||
712 | return result; | ||
713 | |||
714 | *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, | ||
715 | &eeepc_rfkill_ops, handle); | ||
716 | |||
717 | if (!*rfkill) | ||
718 | return -EINVAL; | ||
719 | |||
720 | rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1); | ||
721 | result = rfkill_register(*rfkill); | ||
722 | if (result) { | ||
723 | rfkill_destroy(*rfkill); | ||
724 | *rfkill = NULL; | ||
725 | return result; | ||
726 | } | ||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) | ||
731 | { | ||
732 | eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); | ||
733 | eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); | ||
734 | eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); | ||
735 | if (eeepc->wlan_rfkill) { | ||
736 | rfkill_unregister(eeepc->wlan_rfkill); | ||
737 | rfkill_destroy(eeepc->wlan_rfkill); | ||
738 | eeepc->wlan_rfkill = NULL; | ||
739 | } | ||
740 | /* | ||
741 | * Refresh pci hotplug in case the rfkill state was changed after | ||
742 | * eeepc_unregister_rfkill_notifier() | ||
743 | */ | ||
744 | eeepc_rfkill_hotplug(eeepc); | ||
745 | if (eeepc->hotplug_slot) | ||
746 | pci_hp_deregister(eeepc->hotplug_slot); | ||
747 | |||
748 | if (eeepc->bluetooth_rfkill) { | ||
749 | rfkill_unregister(eeepc->bluetooth_rfkill); | ||
750 | rfkill_destroy(eeepc->bluetooth_rfkill); | ||
751 | eeepc->bluetooth_rfkill = NULL; | ||
752 | } | ||
753 | if (eeepc->wwan3g_rfkill) { | ||
754 | rfkill_unregister(eeepc->wwan3g_rfkill); | ||
755 | rfkill_destroy(eeepc->wwan3g_rfkill); | ||
756 | eeepc->wwan3g_rfkill = NULL; | ||
757 | } | ||
758 | if (eeepc->wimax_rfkill) { | ||
759 | rfkill_unregister(eeepc->wimax_rfkill); | ||
760 | rfkill_destroy(eeepc->wimax_rfkill); | ||
761 | eeepc->wimax_rfkill = NULL; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) | ||
766 | { | ||
767 | int result = 0; | ||
768 | |||
769 | mutex_init(&eeepc->hotplug_lock); | ||
770 | |||
771 | result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, | ||
772 | "eeepc-wlan", RFKILL_TYPE_WLAN, | ||
773 | CM_ASL_WLAN); | ||
774 | |||
775 | if (result && result != -ENODEV) | ||
776 | goto exit; | ||
777 | |||
778 | result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, | ||
779 | "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
780 | CM_ASL_BLUETOOTH); | ||
781 | |||
782 | if (result && result != -ENODEV) | ||
783 | goto exit; | ||
784 | |||
785 | result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, | ||
786 | "eeepc-wwan3g", RFKILL_TYPE_WWAN, | ||
787 | CM_ASL_3G); | ||
788 | |||
789 | if (result && result != -ENODEV) | ||
790 | goto exit; | ||
791 | |||
792 | result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill, | ||
793 | "eeepc-wimax", RFKILL_TYPE_WIMAX, | ||
794 | CM_ASL_WIMAX); | ||
795 | |||
796 | if (result && result != -ENODEV) | ||
797 | goto exit; | ||
798 | |||
799 | result = eeepc_setup_pci_hotplug(eeepc); | ||
800 | /* | ||
801 | * If we get -EBUSY then something else is handling the PCI hotplug - | ||
802 | * don't fail in this case | ||
803 | */ | ||
804 | if (result == -EBUSY) | ||
805 | result = 0; | ||
806 | |||
807 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); | ||
808 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); | ||
809 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); | ||
810 | /* | ||
811 | * Refresh pci hotplug in case the rfkill state was changed during | ||
812 | * setup. | ||
813 | */ | ||
814 | eeepc_rfkill_hotplug(eeepc); | ||
815 | |||
816 | exit: | ||
817 | if (result && result != -ENODEV) | ||
818 | eeepc_rfkill_exit(eeepc); | ||
819 | return result; | ||
820 | } | ||
821 | |||
822 | /* | ||
823 | * Platform driver - hibernate/resume callbacks | ||
824 | */ | ||
833 | static int eeepc_hotk_thaw(struct device *device) | 825 | static int eeepc_hotk_thaw(struct device *device) |
834 | { | 826 | { |
835 | if (ehotk->wlan_rfkill) { | 827 | struct eeepc_laptop *eeepc = dev_get_drvdata(device); |
828 | |||
829 | if (eeepc->wlan_rfkill) { | ||
836 | bool wlan; | 830 | bool wlan; |
837 | 831 | ||
838 | /* | 832 | /* |
@@ -840,8 +834,8 @@ static int eeepc_hotk_thaw(struct device *device) | |||
840 | * during suspend. Normally it restores it on resume, but | 834 | * during suspend. Normally it restores it on resume, but |
841 | * we should kick it ourselves in case hibernation is aborted. | 835 | * we should kick it ourselves in case hibernation is aborted. |
842 | */ | 836 | */ |
843 | wlan = get_acpi(CM_ASL_WLAN); | 837 | wlan = get_acpi(eeepc, CM_ASL_WLAN); |
844 | set_acpi(CM_ASL_WLAN, wlan); | 838 | set_acpi(eeepc, CM_ASL_WLAN, wlan); |
845 | } | 839 | } |
846 | 840 | ||
847 | return 0; | 841 | return 0; |
@@ -849,70 +843,96 @@ static int eeepc_hotk_thaw(struct device *device) | |||
849 | 843 | ||
850 | static int eeepc_hotk_restore(struct device *device) | 844 | static int eeepc_hotk_restore(struct device *device) |
851 | { | 845 | { |
846 | struct eeepc_laptop *eeepc = dev_get_drvdata(device); | ||
847 | |||
852 | /* Refresh both wlan rfkill state and pci hotplug */ | 848 | /* Refresh both wlan rfkill state and pci hotplug */ |
853 | if (ehotk->wlan_rfkill) | 849 | if (eeepc->wlan_rfkill) |
854 | eeepc_rfkill_hotplug(); | 850 | eeepc_rfkill_hotplug(eeepc); |
855 | 851 | ||
856 | if (ehotk->bluetooth_rfkill) | 852 | if (eeepc->bluetooth_rfkill) |
857 | rfkill_set_sw_state(ehotk->bluetooth_rfkill, | 853 | rfkill_set_sw_state(eeepc->bluetooth_rfkill, |
858 | get_acpi(CM_ASL_BLUETOOTH) != 1); | 854 | get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1); |
859 | if (ehotk->wwan3g_rfkill) | 855 | if (eeepc->wwan3g_rfkill) |
860 | rfkill_set_sw_state(ehotk->wwan3g_rfkill, | 856 | rfkill_set_sw_state(eeepc->wwan3g_rfkill, |
861 | get_acpi(CM_ASL_3G) != 1); | 857 | get_acpi(eeepc, CM_ASL_3G) != 1); |
862 | if (ehotk->wimax_rfkill) | 858 | if (eeepc->wimax_rfkill) |
863 | rfkill_set_sw_state(ehotk->wimax_rfkill, | 859 | rfkill_set_sw_state(eeepc->wimax_rfkill, |
864 | get_acpi(CM_ASL_WIMAX) != 1); | 860 | get_acpi(eeepc, CM_ASL_WIMAX) != 1); |
865 | 861 | ||
866 | return 0; | 862 | return 0; |
867 | } | 863 | } |
868 | 864 | ||
865 | static const struct dev_pm_ops eeepc_pm_ops = { | ||
866 | .thaw = eeepc_hotk_thaw, | ||
867 | .restore = eeepc_hotk_restore, | ||
868 | }; | ||
869 | |||
870 | static struct platform_driver platform_driver = { | ||
871 | .driver = { | ||
872 | .name = EEEPC_LAPTOP_FILE, | ||
873 | .owner = THIS_MODULE, | ||
874 | .pm = &eeepc_pm_ops, | ||
875 | } | ||
876 | }; | ||
877 | |||
869 | /* | 878 | /* |
870 | * Hwmon | 879 | * Hwmon device |
871 | */ | 880 | */ |
881 | |||
882 | #define EEEPC_EC_SC00 0x61 | ||
883 | #define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */ | ||
884 | #define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */ | ||
885 | #define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */ | ||
886 | |||
887 | #define EEEPC_EC_SFB0 0xD0 | ||
888 | #define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */ | ||
889 | |||
872 | static int eeepc_get_fan_pwm(void) | 890 | static int eeepc_get_fan_pwm(void) |
873 | { | 891 | { |
874 | int value = 0; | 892 | u8 value = 0; |
875 | 893 | ||
876 | read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value); | 894 | ec_read(EEEPC_EC_FAN_PWM, &value); |
877 | value = value * 255 / 100; | 895 | return value * 255 / 100; |
878 | return (value); | ||
879 | } | 896 | } |
880 | 897 | ||
881 | static void eeepc_set_fan_pwm(int value) | 898 | static void eeepc_set_fan_pwm(int value) |
882 | { | 899 | { |
883 | value = SENSORS_LIMIT(value, 0, 255); | 900 | value = SENSORS_LIMIT(value, 0, 255); |
884 | value = value * 100 / 255; | 901 | value = value * 100 / 255; |
885 | ec_write(EEEPC_EC_SC02, value); | 902 | ec_write(EEEPC_EC_FAN_PWM, value); |
886 | } | 903 | } |
887 | 904 | ||
888 | static int eeepc_get_fan_rpm(void) | 905 | static int eeepc_get_fan_rpm(void) |
889 | { | 906 | { |
890 | int high = 0; | 907 | u8 high = 0; |
891 | int low = 0; | 908 | u8 low = 0; |
892 | 909 | ||
893 | read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high); | 910 | ec_read(EEEPC_EC_FAN_HRPM, &high); |
894 | read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low); | 911 | ec_read(EEEPC_EC_FAN_LRPM, &low); |
895 | return (high << 8 | low); | 912 | return high << 8 | low; |
896 | } | 913 | } |
897 | 914 | ||
898 | static int eeepc_get_fan_ctrl(void) | 915 | static int eeepc_get_fan_ctrl(void) |
899 | { | 916 | { |
900 | int value = 0; | 917 | u8 value = 0; |
901 | 918 | ||
902 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); | 919 | ec_read(EEEPC_EC_FAN_CTRL, &value); |
903 | return ((value & 0x02 ? 1 : 0)); | 920 | if (value & 0x02) |
921 | return 1; /* manual */ | ||
922 | else | ||
923 | return 2; /* automatic */ | ||
904 | } | 924 | } |
905 | 925 | ||
906 | static void eeepc_set_fan_ctrl(int manual) | 926 | static void eeepc_set_fan_ctrl(int manual) |
907 | { | 927 | { |
908 | int value = 0; | 928 | u8 value = 0; |
909 | 929 | ||
910 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); | 930 | ec_read(EEEPC_EC_FAN_CTRL, &value); |
911 | if (manual) | 931 | if (manual == 1) |
912 | value |= 0x02; | 932 | value |= 0x02; |
913 | else | 933 | else |
914 | value &= ~0x02; | 934 | value &= ~0x02; |
915 | ec_write(EEEPC_EC_SFB3, value); | 935 | ec_write(EEEPC_EC_FAN_CTRL, value); |
916 | } | 936 | } |
917 | 937 | ||
918 | static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) | 938 | static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) |
@@ -970,348 +990,485 @@ static struct attribute_group hwmon_attribute_group = { | |||
970 | .attrs = hwmon_attributes | 990 | .attrs = hwmon_attributes |
971 | }; | 991 | }; |
972 | 992 | ||
973 | /* | 993 | static void eeepc_hwmon_exit(struct eeepc_laptop *eeepc) |
974 | * exit/init | ||
975 | */ | ||
976 | static void eeepc_backlight_exit(void) | ||
977 | { | 994 | { |
978 | if (eeepc_backlight_device) | 995 | struct device *hwmon; |
979 | backlight_device_unregister(eeepc_backlight_device); | 996 | |
980 | eeepc_backlight_device = NULL; | 997 | hwmon = eeepc->hwmon_device; |
998 | if (!hwmon) | ||
999 | return; | ||
1000 | sysfs_remove_group(&hwmon->kobj, | ||
1001 | &hwmon_attribute_group); | ||
1002 | hwmon_device_unregister(hwmon); | ||
1003 | eeepc->hwmon_device = NULL; | ||
981 | } | 1004 | } |
982 | 1005 | ||
983 | static void eeepc_rfkill_exit(void) | 1006 | static int eeepc_hwmon_init(struct eeepc_laptop *eeepc) |
984 | { | 1007 | { |
985 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5"); | 1008 | struct device *hwmon; |
986 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); | 1009 | int result; |
987 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); | 1010 | |
988 | if (ehotk->wlan_rfkill) { | 1011 | hwmon = hwmon_device_register(&eeepc->platform_device->dev); |
989 | rfkill_unregister(ehotk->wlan_rfkill); | 1012 | if (IS_ERR(hwmon)) { |
990 | rfkill_destroy(ehotk->wlan_rfkill); | 1013 | pr_err("Could not register eeepc hwmon device\n"); |
991 | ehotk->wlan_rfkill = NULL; | 1014 | eeepc->hwmon_device = NULL; |
992 | } | 1015 | return PTR_ERR(hwmon); |
993 | /* | ||
994 | * Refresh pci hotplug in case the rfkill state was changed after | ||
995 | * eeepc_unregister_rfkill_notifier() | ||
996 | */ | ||
997 | eeepc_rfkill_hotplug(); | ||
998 | if (ehotk->hotplug_slot) | ||
999 | pci_hp_deregister(ehotk->hotplug_slot); | ||
1000 | |||
1001 | if (ehotk->bluetooth_rfkill) { | ||
1002 | rfkill_unregister(ehotk->bluetooth_rfkill); | ||
1003 | rfkill_destroy(ehotk->bluetooth_rfkill); | ||
1004 | ehotk->bluetooth_rfkill = NULL; | ||
1005 | } | ||
1006 | if (ehotk->wwan3g_rfkill) { | ||
1007 | rfkill_unregister(ehotk->wwan3g_rfkill); | ||
1008 | rfkill_destroy(ehotk->wwan3g_rfkill); | ||
1009 | ehotk->wwan3g_rfkill = NULL; | ||
1010 | } | ||
1011 | if (ehotk->wimax_rfkill) { | ||
1012 | rfkill_unregister(ehotk->wimax_rfkill); | ||
1013 | rfkill_destroy(ehotk->wimax_rfkill); | ||
1014 | ehotk->wimax_rfkill = NULL; | ||
1015 | } | 1016 | } |
1017 | eeepc->hwmon_device = hwmon; | ||
1018 | result = sysfs_create_group(&hwmon->kobj, | ||
1019 | &hwmon_attribute_group); | ||
1020 | if (result) | ||
1021 | eeepc_hwmon_exit(eeepc); | ||
1022 | return result; | ||
1016 | } | 1023 | } |
1017 | 1024 | ||
1018 | static void eeepc_input_exit(void) | 1025 | /* |
1026 | * Backlight device | ||
1027 | */ | ||
1028 | static int read_brightness(struct backlight_device *bd) | ||
1019 | { | 1029 | { |
1020 | if (ehotk->inputdev) | 1030 | struct eeepc_laptop *eeepc = bl_get_data(bd); |
1021 | input_unregister_device(ehotk->inputdev); | 1031 | |
1032 | return get_acpi(eeepc, CM_ASL_PANELBRIGHT); | ||
1022 | } | 1033 | } |
1023 | 1034 | ||
1024 | static void eeepc_hwmon_exit(void) | 1035 | static int set_brightness(struct backlight_device *bd, int value) |
1025 | { | 1036 | { |
1026 | struct device *hwmon; | 1037 | struct eeepc_laptop *eeepc = bl_get_data(bd); |
1027 | 1038 | ||
1028 | hwmon = eeepc_hwmon_device; | 1039 | return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value); |
1029 | if (!hwmon) | ||
1030 | return ; | ||
1031 | sysfs_remove_group(&hwmon->kobj, | ||
1032 | &hwmon_attribute_group); | ||
1033 | hwmon_device_unregister(hwmon); | ||
1034 | eeepc_hwmon_device = NULL; | ||
1035 | } | 1040 | } |
1036 | 1041 | ||
1037 | static int eeepc_new_rfkill(struct rfkill **rfkill, | 1042 | static int update_bl_status(struct backlight_device *bd) |
1038 | const char *name, struct device *dev, | ||
1039 | enum rfkill_type type, int cm) | ||
1040 | { | 1043 | { |
1041 | int result; | 1044 | return set_brightness(bd, bd->props.brightness); |
1045 | } | ||
1042 | 1046 | ||
1043 | result = get_acpi(cm); | 1047 | static struct backlight_ops eeepcbl_ops = { |
1044 | if (result < 0) | 1048 | .get_brightness = read_brightness, |
1045 | return result; | 1049 | .update_status = update_bl_status, |
1050 | }; | ||
1046 | 1051 | ||
1047 | *rfkill = rfkill_alloc(name, dev, type, | 1052 | static int eeepc_backlight_notify(struct eeepc_laptop *eeepc) |
1048 | &eeepc_rfkill_ops, (void *)(unsigned long)cm); | 1053 | { |
1054 | struct backlight_device *bd = eeepc->backlight_device; | ||
1055 | int old = bd->props.brightness; | ||
1049 | 1056 | ||
1050 | if (!*rfkill) | 1057 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); |
1051 | return -EINVAL; | ||
1052 | 1058 | ||
1053 | rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1); | 1059 | return old; |
1054 | result = rfkill_register(*rfkill); | ||
1055 | if (result) { | ||
1056 | rfkill_destroy(*rfkill); | ||
1057 | *rfkill = NULL; | ||
1058 | return result; | ||
1059 | } | ||
1060 | return 0; | ||
1061 | } | 1060 | } |
1062 | 1061 | ||
1063 | 1062 | static int eeepc_backlight_init(struct eeepc_laptop *eeepc) | |
1064 | static int eeepc_rfkill_init(struct device *dev) | ||
1065 | { | 1063 | { |
1066 | int result = 0; | 1064 | struct backlight_device *bd; |
1067 | |||
1068 | mutex_init(&ehotk->hotplug_lock); | ||
1069 | 1065 | ||
1070 | result = eeepc_new_rfkill(&ehotk->wlan_rfkill, | 1066 | bd = backlight_device_register(EEEPC_LAPTOP_FILE, |
1071 | "eeepc-wlan", dev, | 1067 | &eeepc->platform_device->dev, |
1072 | RFKILL_TYPE_WLAN, CM_ASL_WLAN); | 1068 | eeepc, &eeepcbl_ops); |
1069 | if (IS_ERR(bd)) { | ||
1070 | pr_err("Could not register eeepc backlight device\n"); | ||
1071 | eeepc->backlight_device = NULL; | ||
1072 | return PTR_ERR(bd); | ||
1073 | } | ||
1074 | eeepc->backlight_device = bd; | ||
1075 | bd->props.max_brightness = 15; | ||
1076 | bd->props.brightness = read_brightness(bd); | ||
1077 | bd->props.power = FB_BLANK_UNBLANK; | ||
1078 | backlight_update_status(bd); | ||
1079 | return 0; | ||
1080 | } | ||
1073 | 1081 | ||
1074 | if (result && result != -ENODEV) | 1082 | static void eeepc_backlight_exit(struct eeepc_laptop *eeepc) |
1075 | goto exit; | 1083 | { |
1084 | if (eeepc->backlight_device) | ||
1085 | backlight_device_unregister(eeepc->backlight_device); | ||
1086 | eeepc->backlight_device = NULL; | ||
1087 | } | ||
1076 | 1088 | ||
1077 | result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill, | ||
1078 | "eeepc-bluetooth", dev, | ||
1079 | RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH); | ||
1080 | 1089 | ||
1081 | if (result && result != -ENODEV) | 1090 | /* |
1082 | goto exit; | 1091 | * Input device (i.e. hotkeys) |
1092 | */ | ||
1093 | static struct key_entry *eeepc_get_entry_by_scancode( | ||
1094 | struct eeepc_laptop *eeepc, | ||
1095 | int code) | ||
1096 | { | ||
1097 | struct key_entry *key; | ||
1083 | 1098 | ||
1084 | result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill, | 1099 | for (key = eeepc->keymap; key->type != KE_END; key++) |
1085 | "eeepc-wwan3g", dev, | 1100 | if (code == key->code) |
1086 | RFKILL_TYPE_WWAN, CM_ASL_3G); | 1101 | return key; |
1087 | 1102 | ||
1088 | if (result && result != -ENODEV) | 1103 | return NULL; |
1089 | goto exit; | 1104 | } |
1090 | 1105 | ||
1091 | result = eeepc_new_rfkill(&ehotk->wimax_rfkill, | 1106 | static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event) |
1092 | "eeepc-wimax", dev, | 1107 | { |
1093 | RFKILL_TYPE_WIMAX, CM_ASL_WIMAX); | 1108 | static struct key_entry *key; |
1094 | 1109 | ||
1095 | if (result && result != -ENODEV) | 1110 | key = eeepc_get_entry_by_scancode(eeepc, event); |
1096 | goto exit; | 1111 | if (key) { |
1112 | switch (key->type) { | ||
1113 | case KE_KEY: | ||
1114 | input_report_key(eeepc->inputdev, key->keycode, | ||
1115 | 1); | ||
1116 | input_sync(eeepc->inputdev); | ||
1117 | input_report_key(eeepc->inputdev, key->keycode, | ||
1118 | 0); | ||
1119 | input_sync(eeepc->inputdev); | ||
1120 | break; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1097 | 1124 | ||
1098 | result = eeepc_setup_pci_hotplug(); | 1125 | static struct key_entry *eeepc_get_entry_by_keycode( |
1099 | /* | 1126 | struct eeepc_laptop *eeepc, int code) |
1100 | * If we get -EBUSY then something else is handling the PCI hotplug - | 1127 | { |
1101 | * don't fail in this case | 1128 | struct key_entry *key; |
1102 | */ | ||
1103 | if (result == -EBUSY) | ||
1104 | result = 0; | ||
1105 | 1129 | ||
1106 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5"); | 1130 | for (key = eeepc->keymap; key->type != KE_END; key++) |
1107 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); | 1131 | if (code == key->keycode && key->type == KE_KEY) |
1108 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); | 1132 | return key; |
1109 | /* | ||
1110 | * Refresh pci hotplug in case the rfkill state was changed during | ||
1111 | * setup. | ||
1112 | */ | ||
1113 | eeepc_rfkill_hotplug(); | ||
1114 | 1133 | ||
1115 | exit: | 1134 | return NULL; |
1116 | if (result && result != -ENODEV) | ||
1117 | eeepc_rfkill_exit(); | ||
1118 | return result; | ||
1119 | } | 1135 | } |
1120 | 1136 | ||
1121 | static int eeepc_backlight_init(struct device *dev) | 1137 | static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) |
1122 | { | 1138 | { |
1123 | struct backlight_device *bd; | 1139 | struct eeepc_laptop *eeepc = input_get_drvdata(dev); |
1140 | struct key_entry *key = eeepc_get_entry_by_scancode(eeepc, scancode); | ||
1124 | 1141 | ||
1125 | bd = backlight_device_register(EEEPC_HOTK_FILE, dev, | 1142 | if (key && key->type == KE_KEY) { |
1126 | NULL, &eeepcbl_ops); | 1143 | *keycode = key->keycode; |
1127 | if (IS_ERR(bd)) { | 1144 | return 0; |
1128 | pr_err("Could not register eeepc backlight device\n"); | ||
1129 | eeepc_backlight_device = NULL; | ||
1130 | return PTR_ERR(bd); | ||
1131 | } | 1145 | } |
1132 | eeepc_backlight_device = bd; | 1146 | |
1133 | bd->props.max_brightness = 15; | 1147 | return -EINVAL; |
1134 | bd->props.brightness = read_brightness(NULL); | ||
1135 | bd->props.power = FB_BLANK_UNBLANK; | ||
1136 | backlight_update_status(bd); | ||
1137 | return 0; | ||
1138 | } | 1148 | } |
1139 | 1149 | ||
1140 | static int eeepc_hwmon_init(struct device *dev) | 1150 | static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) |
1141 | { | 1151 | { |
1142 | struct device *hwmon; | 1152 | struct eeepc_laptop *eeepc = input_get_drvdata(dev); |
1143 | int result; | 1153 | struct key_entry *key; |
1154 | int old_keycode; | ||
1144 | 1155 | ||
1145 | hwmon = hwmon_device_register(dev); | 1156 | if (keycode < 0 || keycode > KEY_MAX) |
1146 | if (IS_ERR(hwmon)) { | 1157 | return -EINVAL; |
1147 | pr_err("Could not register eeepc hwmon device\n"); | 1158 | |
1148 | eeepc_hwmon_device = NULL; | 1159 | key = eeepc_get_entry_by_scancode(eeepc, scancode); |
1149 | return PTR_ERR(hwmon); | 1160 | if (key && key->type == KE_KEY) { |
1161 | old_keycode = key->keycode; | ||
1162 | key->keycode = keycode; | ||
1163 | set_bit(keycode, dev->keybit); | ||
1164 | if (!eeepc_get_entry_by_keycode(eeepc, old_keycode)) | ||
1165 | clear_bit(old_keycode, dev->keybit); | ||
1166 | return 0; | ||
1150 | } | 1167 | } |
1151 | eeepc_hwmon_device = hwmon; | 1168 | |
1152 | result = sysfs_create_group(&hwmon->kobj, | 1169 | return -EINVAL; |
1153 | &hwmon_attribute_group); | ||
1154 | if (result) | ||
1155 | eeepc_hwmon_exit(); | ||
1156 | return result; | ||
1157 | } | 1170 | } |
1158 | 1171 | ||
1159 | static int eeepc_input_init(struct device *dev) | 1172 | static int eeepc_input_init(struct eeepc_laptop *eeepc) |
1160 | { | 1173 | { |
1161 | const struct key_entry *key; | 1174 | const struct key_entry *key; |
1162 | int result; | 1175 | int result; |
1163 | 1176 | ||
1164 | ehotk->inputdev = input_allocate_device(); | 1177 | eeepc->inputdev = input_allocate_device(); |
1165 | if (!ehotk->inputdev) { | 1178 | if (!eeepc->inputdev) { |
1166 | pr_info("Unable to allocate input device\n"); | 1179 | pr_info("Unable to allocate input device\n"); |
1167 | return -ENOMEM; | 1180 | return -ENOMEM; |
1168 | } | 1181 | } |
1169 | ehotk->inputdev->name = "Asus EeePC extra buttons"; | 1182 | eeepc->inputdev->name = "Asus EeePC extra buttons"; |
1170 | ehotk->inputdev->dev.parent = dev; | 1183 | eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; |
1171 | ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; | 1184 | eeepc->inputdev->phys = EEEPC_LAPTOP_FILE "/input0"; |
1172 | ehotk->inputdev->id.bustype = BUS_HOST; | 1185 | eeepc->inputdev->id.bustype = BUS_HOST; |
1173 | ehotk->inputdev->getkeycode = eeepc_getkeycode; | 1186 | eeepc->inputdev->getkeycode = eeepc_getkeycode; |
1174 | ehotk->inputdev->setkeycode = eeepc_setkeycode; | 1187 | eeepc->inputdev->setkeycode = eeepc_setkeycode; |
1175 | 1188 | input_set_drvdata(eeepc->inputdev, eeepc); | |
1189 | |||
1190 | eeepc->keymap = kmemdup(eeepc_keymap, sizeof(eeepc_keymap), | ||
1191 | GFP_KERNEL); | ||
1176 | for (key = eeepc_keymap; key->type != KE_END; key++) { | 1192 | for (key = eeepc_keymap; key->type != KE_END; key++) { |
1177 | switch (key->type) { | 1193 | switch (key->type) { |
1178 | case KE_KEY: | 1194 | case KE_KEY: |
1179 | set_bit(EV_KEY, ehotk->inputdev->evbit); | 1195 | set_bit(EV_KEY, eeepc->inputdev->evbit); |
1180 | set_bit(key->keycode, ehotk->inputdev->keybit); | 1196 | set_bit(key->keycode, eeepc->inputdev->keybit); |
1181 | break; | 1197 | break; |
1182 | } | 1198 | } |
1183 | } | 1199 | } |
1184 | result = input_register_device(ehotk->inputdev); | 1200 | result = input_register_device(eeepc->inputdev); |
1185 | if (result) { | 1201 | if (result) { |
1186 | pr_info("Unable to register input device\n"); | 1202 | pr_info("Unable to register input device\n"); |
1187 | input_free_device(ehotk->inputdev); | 1203 | input_free_device(eeepc->inputdev); |
1188 | return result; | 1204 | return result; |
1189 | } | 1205 | } |
1190 | return 0; | 1206 | return 0; |
1191 | } | 1207 | } |
1192 | 1208 | ||
1193 | static int __devinit eeepc_hotk_add(struct acpi_device *device) | 1209 | static void eeepc_input_exit(struct eeepc_laptop *eeepc) |
1194 | { | 1210 | { |
1195 | struct device *dev; | 1211 | if (eeepc->inputdev) { |
1212 | input_unregister_device(eeepc->inputdev); | ||
1213 | kfree(eeepc->keymap); | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | /* | ||
1218 | * ACPI driver | ||
1219 | */ | ||
1220 | static void eeepc_acpi_notify(struct acpi_device *device, u32 event) | ||
1221 | { | ||
1222 | struct eeepc_laptop *eeepc = acpi_driver_data(device); | ||
1223 | u16 count; | ||
1224 | |||
1225 | if (event > ACPI_MAX_SYS_NOTIFY) | ||
1226 | return; | ||
1227 | count = eeepc->event_count[event % 128]++; | ||
1228 | acpi_bus_generate_proc_event(device, event, count); | ||
1229 | acpi_bus_generate_netlink_event(device->pnp.device_class, | ||
1230 | dev_name(&device->dev), event, | ||
1231 | count); | ||
1232 | |||
1233 | /* Brightness events are special */ | ||
1234 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) { | ||
1235 | |||
1236 | /* Ignore them completely if the acpi video driver is used */ | ||
1237 | if (eeepc->backlight_device != NULL) { | ||
1238 | int old_brightness, new_brightness; | ||
1239 | |||
1240 | /* Update the backlight device. */ | ||
1241 | old_brightness = eeepc_backlight_notify(eeepc); | ||
1242 | |||
1243 | /* Convert event to keypress (obsolescent hack) */ | ||
1244 | new_brightness = event - NOTIFY_BRN_MIN; | ||
1245 | |||
1246 | if (new_brightness < old_brightness) { | ||
1247 | event = NOTIFY_BRN_MIN; /* brightness down */ | ||
1248 | } else if (new_brightness > old_brightness) { | ||
1249 | event = NOTIFY_BRN_MAX; /* brightness up */ | ||
1250 | } else { | ||
1251 | /* | ||
1252 | * no change in brightness - already at min/max, | ||
1253 | * event will be desired value (or else ignored) | ||
1254 | */ | ||
1255 | } | ||
1256 | eeepc_input_notify(eeepc, event); | ||
1257 | } | ||
1258 | } else { | ||
1259 | /* Everything else is a bona-fide keypress event */ | ||
1260 | eeepc_input_notify(eeepc, event); | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) | ||
1265 | { | ||
1266 | int dummy; | ||
1267 | |||
1268 | /* Some BIOSes do not report cm although it is avaliable. | ||
1269 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | ||
1270 | if (!(eeepc->cm_supported & (1 << cm)) | ||
1271 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { | ||
1272 | pr_info("%s (%x) not reported by BIOS," | ||
1273 | " enabling anyway\n", name, 1 << cm); | ||
1274 | eeepc->cm_supported |= 1 << cm; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | static void cmsg_quirks(struct eeepc_laptop *eeepc) | ||
1279 | { | ||
1280 | cmsg_quirk(eeepc, CM_ASL_LID, "LID"); | ||
1281 | cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE"); | ||
1282 | cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER"); | ||
1283 | cmsg_quirk(eeepc, CM_ASL_TPD, "TPD"); | ||
1284 | } | ||
1285 | |||
1286 | static int eeepc_acpi_init(struct eeepc_laptop *eeepc, | ||
1287 | struct acpi_device *device) | ||
1288 | { | ||
1289 | unsigned int init_flags; | ||
1196 | int result; | 1290 | int result; |
1197 | 1291 | ||
1198 | if (!device) | 1292 | result = acpi_bus_get_status(device); |
1199 | return -EINVAL; | ||
1200 | pr_notice(EEEPC_HOTK_NAME "\n"); | ||
1201 | ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); | ||
1202 | if (!ehotk) | ||
1203 | return -ENOMEM; | ||
1204 | ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; | ||
1205 | ehotk->handle = device->handle; | ||
1206 | strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); | ||
1207 | strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); | ||
1208 | device->driver_data = ehotk; | ||
1209 | ehotk->device = device; | ||
1210 | |||
1211 | result = eeepc_hotk_check(); | ||
1212 | if (result) | 1293 | if (result) |
1213 | goto fail_platform_driver; | 1294 | return result; |
1214 | eeepc_enable_camera(); | 1295 | if (!device->status.present) { |
1296 | pr_err("Hotkey device not present, aborting\n"); | ||
1297 | return -ENODEV; | ||
1298 | } | ||
1215 | 1299 | ||
1216 | /* Register platform stuff */ | 1300 | init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; |
1217 | result = platform_driver_register(&platform_driver); | 1301 | pr_notice("Hotkey init flags 0x%x\n", init_flags); |
1218 | if (result) | 1302 | |
1219 | goto fail_platform_driver; | 1303 | if (write_acpi_int(eeepc->handle, "INIT", init_flags)) { |
1220 | platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1); | 1304 | pr_err("Hotkey initialization failed\n"); |
1221 | if (!platform_device) { | 1305 | return -ENODEV; |
1222 | result = -ENOMEM; | ||
1223 | goto fail_platform_device1; | ||
1224 | } | 1306 | } |
1225 | result = platform_device_add(platform_device); | 1307 | |
1226 | if (result) | 1308 | /* get control methods supported */ |
1227 | goto fail_platform_device2; | 1309 | if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) { |
1228 | result = sysfs_create_group(&platform_device->dev.kobj, | 1310 | pr_err("Get control methods supported failed\n"); |
1229 | &platform_attribute_group); | 1311 | return -ENODEV; |
1312 | } | ||
1313 | cmsg_quirks(eeepc); | ||
1314 | pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported); | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static void __devinit eeepc_enable_camera(struct eeepc_laptop *eeepc) | ||
1320 | { | ||
1321 | /* | ||
1322 | * If the following call to set_acpi() fails, it's because there's no | ||
1323 | * camera so we can ignore the error. | ||
1324 | */ | ||
1325 | if (get_acpi(eeepc, CM_ASL_CAMERA) == 0) | ||
1326 | set_acpi(eeepc, CM_ASL_CAMERA, 1); | ||
1327 | } | ||
1328 | |||
1329 | static bool eeepc_device_present; | ||
1330 | |||
1331 | static int __devinit eeepc_acpi_add(struct acpi_device *device) | ||
1332 | { | ||
1333 | struct eeepc_laptop *eeepc; | ||
1334 | int result; | ||
1335 | |||
1336 | pr_notice(EEEPC_LAPTOP_NAME "\n"); | ||
1337 | eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL); | ||
1338 | if (!eeepc) | ||
1339 | return -ENOMEM; | ||
1340 | eeepc->handle = device->handle; | ||
1341 | strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); | ||
1342 | strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); | ||
1343 | device->driver_data = eeepc; | ||
1344 | |||
1345 | result = eeepc_acpi_init(eeepc, device); | ||
1230 | if (result) | 1346 | if (result) |
1231 | goto fail_sysfs; | 1347 | goto fail_platform; |
1348 | eeepc_enable_camera(eeepc); | ||
1232 | 1349 | ||
1233 | dev = &platform_device->dev; | 1350 | /* |
1351 | * Register the platform device first. It is used as a parent for the | ||
1352 | * sub-devices below. | ||
1353 | * | ||
1354 | * Note that if there are multiple instances of this ACPI device it | ||
1355 | * will bail out, because the platform device is registered with a | ||
1356 | * fixed name. Of course it doesn't make sense to have more than one, | ||
1357 | * and machine-specific scripts find the fixed name convenient. But | ||
1358 | * It's also good for us to exclude multiple instances because both | ||
1359 | * our hwmon and our wlan rfkill subdevice use global ACPI objects | ||
1360 | * (the EC and the wlan PCI slot respectively). | ||
1361 | */ | ||
1362 | result = eeepc_platform_init(eeepc); | ||
1363 | if (result) | ||
1364 | goto fail_platform; | ||
1234 | 1365 | ||
1235 | if (!acpi_video_backlight_support()) { | 1366 | if (!acpi_video_backlight_support()) { |
1236 | result = eeepc_backlight_init(dev); | 1367 | result = eeepc_backlight_init(eeepc); |
1237 | if (result) | 1368 | if (result) |
1238 | goto fail_backlight; | 1369 | goto fail_backlight; |
1239 | } else | 1370 | } else |
1240 | pr_info("Backlight controlled by ACPI video " | 1371 | pr_info("Backlight controlled by ACPI video driver\n"); |
1241 | "driver\n"); | ||
1242 | 1372 | ||
1243 | result = eeepc_input_init(dev); | 1373 | result = eeepc_input_init(eeepc); |
1244 | if (result) | 1374 | if (result) |
1245 | goto fail_input; | 1375 | goto fail_input; |
1246 | 1376 | ||
1247 | result = eeepc_hwmon_init(dev); | 1377 | result = eeepc_hwmon_init(eeepc); |
1248 | if (result) | 1378 | if (result) |
1249 | goto fail_hwmon; | 1379 | goto fail_hwmon; |
1250 | 1380 | ||
1251 | result = eeepc_rfkill_init(dev); | 1381 | result = eeepc_led_init(eeepc); |
1382 | if (result) | ||
1383 | goto fail_led; | ||
1384 | |||
1385 | result = eeepc_rfkill_init(eeepc); | ||
1252 | if (result) | 1386 | if (result) |
1253 | goto fail_rfkill; | 1387 | goto fail_rfkill; |
1254 | 1388 | ||
1389 | eeepc_device_present = true; | ||
1255 | return 0; | 1390 | return 0; |
1256 | 1391 | ||
1257 | fail_rfkill: | 1392 | fail_rfkill: |
1258 | eeepc_hwmon_exit(); | 1393 | eeepc_led_exit(eeepc); |
1394 | fail_led: | ||
1395 | eeepc_hwmon_exit(eeepc); | ||
1259 | fail_hwmon: | 1396 | fail_hwmon: |
1260 | eeepc_input_exit(); | 1397 | eeepc_input_exit(eeepc); |
1261 | fail_input: | 1398 | fail_input: |
1262 | eeepc_backlight_exit(); | 1399 | eeepc_backlight_exit(eeepc); |
1263 | fail_backlight: | 1400 | fail_backlight: |
1264 | sysfs_remove_group(&platform_device->dev.kobj, | 1401 | eeepc_platform_exit(eeepc); |
1265 | &platform_attribute_group); | 1402 | fail_platform: |
1266 | fail_sysfs: | 1403 | kfree(eeepc); |
1267 | platform_device_del(platform_device); | ||
1268 | fail_platform_device2: | ||
1269 | platform_device_put(platform_device); | ||
1270 | fail_platform_device1: | ||
1271 | platform_driver_unregister(&platform_driver); | ||
1272 | fail_platform_driver: | ||
1273 | kfree(ehotk); | ||
1274 | 1404 | ||
1275 | return result; | 1405 | return result; |
1276 | } | 1406 | } |
1277 | 1407 | ||
1278 | static int eeepc_hotk_remove(struct acpi_device *device, int type) | 1408 | static int eeepc_acpi_remove(struct acpi_device *device, int type) |
1279 | { | 1409 | { |
1280 | if (!device || !acpi_driver_data(device)) | 1410 | struct eeepc_laptop *eeepc = acpi_driver_data(device); |
1281 | return -EINVAL; | ||
1282 | 1411 | ||
1283 | eeepc_backlight_exit(); | 1412 | eeepc_backlight_exit(eeepc); |
1284 | eeepc_rfkill_exit(); | 1413 | eeepc_rfkill_exit(eeepc); |
1285 | eeepc_input_exit(); | 1414 | eeepc_input_exit(eeepc); |
1286 | eeepc_hwmon_exit(); | 1415 | eeepc_hwmon_exit(eeepc); |
1287 | sysfs_remove_group(&platform_device->dev.kobj, | 1416 | eeepc_led_exit(eeepc); |
1288 | &platform_attribute_group); | 1417 | eeepc_platform_exit(eeepc); |
1289 | platform_device_unregister(platform_device); | ||
1290 | platform_driver_unregister(&platform_driver); | ||
1291 | 1418 | ||
1292 | kfree(ehotk); | 1419 | kfree(eeepc); |
1293 | return 0; | 1420 | return 0; |
1294 | } | 1421 | } |
1295 | 1422 | ||
1423 | |||
1424 | static const struct acpi_device_id eeepc_device_ids[] = { | ||
1425 | {EEEPC_ACPI_HID, 0}, | ||
1426 | {"", 0}, | ||
1427 | }; | ||
1428 | MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); | ||
1429 | |||
1430 | static struct acpi_driver eeepc_acpi_driver = { | ||
1431 | .name = EEEPC_LAPTOP_NAME, | ||
1432 | .class = EEEPC_ACPI_CLASS, | ||
1433 | .owner = THIS_MODULE, | ||
1434 | .ids = eeepc_device_ids, | ||
1435 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | ||
1436 | .ops = { | ||
1437 | .add = eeepc_acpi_add, | ||
1438 | .remove = eeepc_acpi_remove, | ||
1439 | .notify = eeepc_acpi_notify, | ||
1440 | }, | ||
1441 | }; | ||
1442 | |||
1443 | |||
1296 | static int __init eeepc_laptop_init(void) | 1444 | static int __init eeepc_laptop_init(void) |
1297 | { | 1445 | { |
1298 | int result; | 1446 | int result; |
1299 | 1447 | ||
1300 | if (acpi_disabled) | 1448 | result = platform_driver_register(&platform_driver); |
1301 | return -ENODEV; | ||
1302 | result = acpi_bus_register_driver(&eeepc_hotk_driver); | ||
1303 | if (result < 0) | 1449 | if (result < 0) |
1304 | return result; | 1450 | return result; |
1305 | if (!ehotk) { | 1451 | |
1306 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 1452 | result = acpi_bus_register_driver(&eeepc_acpi_driver); |
1307 | return -ENODEV; | 1453 | if (result < 0) |
1454 | goto fail_acpi_driver; | ||
1455 | if (!eeepc_device_present) { | ||
1456 | result = -ENODEV; | ||
1457 | goto fail_no_device; | ||
1308 | } | 1458 | } |
1309 | return 0; | 1459 | return 0; |
1460 | |||
1461 | fail_no_device: | ||
1462 | acpi_bus_unregister_driver(&eeepc_acpi_driver); | ||
1463 | fail_acpi_driver: | ||
1464 | platform_driver_unregister(&platform_driver); | ||
1465 | return result; | ||
1310 | } | 1466 | } |
1311 | 1467 | ||
1312 | static void __exit eeepc_laptop_exit(void) | 1468 | static void __exit eeepc_laptop_exit(void) |
1313 | { | 1469 | { |
1314 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 1470 | acpi_bus_unregister_driver(&eeepc_acpi_driver); |
1471 | platform_driver_unregister(&platform_driver); | ||
1315 | } | 1472 | } |
1316 | 1473 | ||
1317 | module_init(eeepc_laptop_init); | 1474 | module_init(eeepc_laptop_init); |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f00a71c58e69..63c3e658a884 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -51,6 +51,12 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
51 | #define HPWMI_WIRELESS_QUERY 0x5 | 51 | #define HPWMI_WIRELESS_QUERY 0x5 |
52 | #define HPWMI_HOTKEY_QUERY 0xc | 52 | #define HPWMI_HOTKEY_QUERY 0xc |
53 | 53 | ||
54 | enum hp_wmi_radio { | ||
55 | HPWMI_WIFI = 0, | ||
56 | HPWMI_BLUETOOTH = 1, | ||
57 | HPWMI_WWAN = 2, | ||
58 | }; | ||
59 | |||
54 | static int __init hp_wmi_bios_setup(struct platform_device *device); | 60 | static int __init hp_wmi_bios_setup(struct platform_device *device); |
55 | static int __exit hp_wmi_bios_remove(struct platform_device *device); | 61 | static int __exit hp_wmi_bios_remove(struct platform_device *device); |
56 | static int hp_wmi_resume_handler(struct device *device); | 62 | static int hp_wmi_resume_handler(struct device *device); |
@@ -175,8 +181,8 @@ static int hp_wmi_tablet_state(void) | |||
175 | 181 | ||
176 | static int hp_wmi_set_block(void *data, bool blocked) | 182 | static int hp_wmi_set_block(void *data, bool blocked) |
177 | { | 183 | { |
178 | unsigned long b = (unsigned long) data; | 184 | enum hp_wmi_radio r = (enum hp_wmi_radio) data; |
179 | int query = BIT(b + 8) | ((!blocked) << b); | 185 | int query = BIT(r + 8) | ((!blocked) << r); |
180 | 186 | ||
181 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); | 187 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); |
182 | } | 188 | } |
@@ -185,31 +191,23 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { | |||
185 | .set_block = hp_wmi_set_block, | 191 | .set_block = hp_wmi_set_block, |
186 | }; | 192 | }; |
187 | 193 | ||
188 | static bool hp_wmi_wifi_state(void) | 194 | static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) |
189 | { | ||
190 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | ||
191 | |||
192 | if (wireless & 0x100) | ||
193 | return false; | ||
194 | else | ||
195 | return true; | ||
196 | } | ||
197 | |||
198 | static bool hp_wmi_bluetooth_state(void) | ||
199 | { | 195 | { |
200 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 196 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
197 | int mask = 0x200 << (r * 8); | ||
201 | 198 | ||
202 | if (wireless & 0x10000) | 199 | if (wireless & mask) |
203 | return false; | 200 | return false; |
204 | else | 201 | else |
205 | return true; | 202 | return true; |
206 | } | 203 | } |
207 | 204 | ||
208 | static bool hp_wmi_wwan_state(void) | 205 | static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) |
209 | { | 206 | { |
210 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 207 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
208 | int mask = 0x800 << (r * 8); | ||
211 | 209 | ||
212 | if (wireless & 0x1000000) | 210 | if (wireless & mask) |
213 | return false; | 211 | return false; |
214 | else | 212 | else |
215 | return true; | 213 | return true; |
@@ -334,49 +332,55 @@ static void hp_wmi_notify(u32 value, void *context) | |||
334 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | 332 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; |
335 | static struct key_entry *key; | 333 | static struct key_entry *key; |
336 | union acpi_object *obj; | 334 | union acpi_object *obj; |
335 | int eventcode; | ||
337 | 336 | ||
338 | wmi_get_event_data(value, &response); | 337 | wmi_get_event_data(value, &response); |
339 | 338 | ||
340 | obj = (union acpi_object *)response.pointer; | 339 | obj = (union acpi_object *)response.pointer; |
341 | 340 | ||
342 | if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) { | 341 | if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) { |
343 | int eventcode = *((u8 *) obj->buffer.pointer); | 342 | printk(KERN_INFO "HP WMI: Unknown response received\n"); |
344 | if (eventcode == 0x4) | 343 | return; |
345 | eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, | 344 | } |
346 | 0); | 345 | |
347 | key = hp_wmi_get_entry_by_scancode(eventcode); | 346 | eventcode = *((u8 *) obj->buffer.pointer); |
348 | if (key) { | 347 | if (eventcode == 0x4) |
349 | switch (key->type) { | 348 | eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, |
350 | case KE_KEY: | 349 | 0); |
351 | input_report_key(hp_wmi_input_dev, | 350 | key = hp_wmi_get_entry_by_scancode(eventcode); |
352 | key->keycode, 1); | 351 | if (key) { |
353 | input_sync(hp_wmi_input_dev); | 352 | switch (key->type) { |
354 | input_report_key(hp_wmi_input_dev, | 353 | case KE_KEY: |
355 | key->keycode, 0); | 354 | input_report_key(hp_wmi_input_dev, |
356 | input_sync(hp_wmi_input_dev); | 355 | key->keycode, 1); |
357 | break; | 356 | input_sync(hp_wmi_input_dev); |
358 | } | 357 | input_report_key(hp_wmi_input_dev, |
359 | } else if (eventcode == 0x1) { | 358 | key->keycode, 0); |
360 | input_report_switch(hp_wmi_input_dev, SW_DOCK, | ||
361 | hp_wmi_dock_state()); | ||
362 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, | ||
363 | hp_wmi_tablet_state()); | ||
364 | input_sync(hp_wmi_input_dev); | 359 | input_sync(hp_wmi_input_dev); |
365 | } else if (eventcode == 0x5) { | 360 | break; |
366 | if (wifi_rfkill) | 361 | } |
367 | rfkill_set_sw_state(wifi_rfkill, | 362 | } else if (eventcode == 0x1) { |
368 | hp_wmi_wifi_state()); | 363 | input_report_switch(hp_wmi_input_dev, SW_DOCK, |
369 | if (bluetooth_rfkill) | 364 | hp_wmi_dock_state()); |
370 | rfkill_set_sw_state(bluetooth_rfkill, | 365 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, |
371 | hp_wmi_bluetooth_state()); | 366 | hp_wmi_tablet_state()); |
372 | if (wwan_rfkill) | 367 | input_sync(hp_wmi_input_dev); |
373 | rfkill_set_sw_state(wwan_rfkill, | 368 | } else if (eventcode == 0x5) { |
374 | hp_wmi_wwan_state()); | 369 | if (wifi_rfkill) |
375 | } else | 370 | rfkill_set_states(wifi_rfkill, |
376 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", | 371 | hp_wmi_get_sw_state(HPWMI_WIFI), |
377 | eventcode); | 372 | hp_wmi_get_hw_state(HPWMI_WIFI)); |
373 | if (bluetooth_rfkill) | ||
374 | rfkill_set_states(bluetooth_rfkill, | ||
375 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH), | ||
376 | hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); | ||
377 | if (wwan_rfkill) | ||
378 | rfkill_set_states(wwan_rfkill, | ||
379 | hp_wmi_get_sw_state(HPWMI_WWAN), | ||
380 | hp_wmi_get_hw_state(HPWMI_WWAN)); | ||
378 | } else | 381 | } else |
379 | printk(KERN_INFO "HP WMI: Unknown response received\n"); | 382 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", |
383 | eventcode); | ||
380 | } | 384 | } |
381 | 385 | ||
382 | static int __init hp_wmi_input_setup(void) | 386 | static int __init hp_wmi_input_setup(void) |
@@ -455,7 +459,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
455 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, | 459 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
456 | RFKILL_TYPE_WLAN, | 460 | RFKILL_TYPE_WLAN, |
457 | &hp_wmi_rfkill_ops, | 461 | &hp_wmi_rfkill_ops, |
458 | (void *) 0); | 462 | (void *) HPWMI_WIFI); |
463 | rfkill_init_sw_state(wifi_rfkill, | ||
464 | hp_wmi_get_sw_state(HPWMI_WIFI)); | ||
465 | rfkill_set_hw_state(wifi_rfkill, | ||
466 | hp_wmi_get_hw_state(HPWMI_WIFI)); | ||
459 | err = rfkill_register(wifi_rfkill); | 467 | err = rfkill_register(wifi_rfkill); |
460 | if (err) | 468 | if (err) |
461 | goto register_wifi_error; | 469 | goto register_wifi_error; |
@@ -465,7 +473,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
465 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, | 473 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, |
466 | RFKILL_TYPE_BLUETOOTH, | 474 | RFKILL_TYPE_BLUETOOTH, |
467 | &hp_wmi_rfkill_ops, | 475 | &hp_wmi_rfkill_ops, |
468 | (void *) 1); | 476 | (void *) HPWMI_BLUETOOTH); |
477 | rfkill_init_sw_state(bluetooth_rfkill, | ||
478 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); | ||
479 | rfkill_set_hw_state(bluetooth_rfkill, | ||
480 | hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); | ||
469 | err = rfkill_register(bluetooth_rfkill); | 481 | err = rfkill_register(bluetooth_rfkill); |
470 | if (err) | 482 | if (err) |
471 | goto register_bluetooth_error; | 483 | goto register_bluetooth_error; |
@@ -475,7 +487,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
475 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, | 487 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, |
476 | RFKILL_TYPE_WWAN, | 488 | RFKILL_TYPE_WWAN, |
477 | &hp_wmi_rfkill_ops, | 489 | &hp_wmi_rfkill_ops, |
478 | (void *) 2); | 490 | (void *) HPWMI_WWAN); |
491 | rfkill_init_sw_state(wwan_rfkill, | ||
492 | hp_wmi_get_sw_state(HPWMI_WWAN)); | ||
493 | rfkill_set_hw_state(wwan_rfkill, | ||
494 | hp_wmi_get_hw_state(HPWMI_WWAN)); | ||
479 | err = rfkill_register(wwan_rfkill); | 495 | err = rfkill_register(wwan_rfkill); |
480 | if (err) | 496 | if (err) |
481 | goto register_wwan_err; | 497 | goto register_wwan_err; |
@@ -533,6 +549,19 @@ static int hp_wmi_resume_handler(struct device *device) | |||
533 | input_sync(hp_wmi_input_dev); | 549 | input_sync(hp_wmi_input_dev); |
534 | } | 550 | } |
535 | 551 | ||
552 | if (wifi_rfkill) | ||
553 | rfkill_set_states(wifi_rfkill, | ||
554 | hp_wmi_get_sw_state(HPWMI_WIFI), | ||
555 | hp_wmi_get_hw_state(HPWMI_WIFI)); | ||
556 | if (bluetooth_rfkill) | ||
557 | rfkill_set_states(bluetooth_rfkill, | ||
558 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH), | ||
559 | hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); | ||
560 | if (wwan_rfkill) | ||
561 | rfkill_set_states(wwan_rfkill, | ||
562 | hp_wmi_get_sw_state(HPWMI_WWAN), | ||
563 | hp_wmi_get_hw_state(HPWMI_WWAN)); | ||
564 | |||
536 | return 0; | 565 | return 0; |
537 | } | 566 | } |
538 | 567 | ||
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c new file mode 100644 index 000000000000..0c8fe145c4af --- /dev/null +++ b/drivers/platform/x86/msi-wmi.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /* | ||
2 | * MSI WMI hotkeys | ||
3 | * | ||
4 | * Copyright (C) 2009 Novell <trenn@suse.de> | ||
5 | * | ||
6 | * Most stuff taken over from hp-wmi | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <linux/input/sparse-keymap.h> | ||
27 | #include <linux/acpi.h> | ||
28 | #include <linux/backlight.h> | ||
29 | |||
30 | MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); | ||
31 | MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45"); | ||
35 | MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"); | ||
36 | |||
37 | /* Temporary workaround until the WMI sysfs interface goes in | ||
38 | { "svn", DMI_SYS_VENDOR }, | ||
39 | { "pn", DMI_PRODUCT_NAME }, | ||
40 | { "pvr", DMI_PRODUCT_VERSION }, | ||
41 | { "rvn", DMI_BOARD_VENDOR }, | ||
42 | { "rn", DMI_BOARD_NAME }, | ||
43 | */ | ||
44 | |||
45 | MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-6638:*"); | ||
46 | |||
47 | #define DRV_NAME "msi-wmi" | ||
48 | #define DRV_PFX DRV_NAME ": " | ||
49 | |||
50 | #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45" | ||
51 | #define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" | ||
52 | |||
53 | #define dprintk(msg...) pr_debug(DRV_PFX msg) | ||
54 | |||
55 | #define KEYCODE_BASE 0xD0 | ||
56 | #define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE | ||
57 | #define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1) | ||
58 | #define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2) | ||
59 | #define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3) | ||
60 | static struct key_entry msi_wmi_keymap[] = { | ||
61 | { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, | ||
62 | { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} }, | ||
63 | { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} }, | ||
64 | { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, | ||
65 | { KE_END, 0} | ||
66 | }; | ||
67 | static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; | ||
68 | |||
69 | struct backlight_device *backlight; | ||
70 | |||
71 | static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF }; | ||
72 | |||
73 | static struct input_dev *msi_wmi_input_dev; | ||
74 | |||
75 | static int msi_wmi_query_block(int instance, int *ret) | ||
76 | { | ||
77 | acpi_status status; | ||
78 | union acpi_object *obj; | ||
79 | |||
80 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
81 | |||
82 | status = wmi_query_block(MSIWMI_BIOS_GUID, instance, &output); | ||
83 | |||
84 | obj = output.pointer; | ||
85 | |||
86 | if (!obj || obj->type != ACPI_TYPE_INTEGER) { | ||
87 | if (obj) { | ||
88 | printk(KERN_ERR DRV_PFX "query block returned object " | ||
89 | "type: %d - buffer length:%d\n", obj->type, | ||
90 | obj->type == ACPI_TYPE_BUFFER ? | ||
91 | obj->buffer.length : 0); | ||
92 | } | ||
93 | kfree(obj); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | *ret = obj->integer.value; | ||
97 | kfree(obj); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int msi_wmi_set_block(int instance, int value) | ||
102 | { | ||
103 | acpi_status status; | ||
104 | |||
105 | struct acpi_buffer input = { sizeof(int), &value }; | ||
106 | |||
107 | dprintk("Going to set block of instance: %d - value: %d\n", | ||
108 | instance, value); | ||
109 | |||
110 | status = wmi_set_block(MSIWMI_BIOS_GUID, instance, &input); | ||
111 | |||
112 | return ACPI_SUCCESS(status) ? 0 : 1; | ||
113 | } | ||
114 | |||
115 | static int bl_get(struct backlight_device *bd) | ||
116 | { | ||
117 | int level, err, ret; | ||
118 | |||
119 | /* Instance 1 is "get backlight", cmp with DSDT */ | ||
120 | err = msi_wmi_query_block(1, &ret); | ||
121 | if (err) { | ||
122 | printk(KERN_ERR DRV_PFX "Could not query backlight: %d\n", err); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | dprintk("Get: Query block returned: %d\n", ret); | ||
126 | for (level = 0; level < ARRAY_SIZE(backlight_map); level++) { | ||
127 | if (backlight_map[level] == ret) { | ||
128 | dprintk("Current backlight level: 0x%X - index: %d\n", | ||
129 | backlight_map[level], level); | ||
130 | break; | ||
131 | } | ||
132 | } | ||
133 | if (level == ARRAY_SIZE(backlight_map)) { | ||
134 | printk(KERN_ERR DRV_PFX "get: Invalid brightness value: 0x%X\n", | ||
135 | ret); | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | return level; | ||
139 | } | ||
140 | |||
141 | static int bl_set_status(struct backlight_device *bd) | ||
142 | { | ||
143 | int bright = bd->props.brightness; | ||
144 | if (bright >= ARRAY_SIZE(backlight_map) || bright < 0) | ||
145 | return -EINVAL; | ||
146 | |||
147 | /* Instance 0 is "set backlight" */ | ||
148 | return msi_wmi_set_block(0, backlight_map[bright]); | ||
149 | } | ||
150 | |||
151 | static struct backlight_ops msi_backlight_ops = { | ||
152 | .get_brightness = bl_get, | ||
153 | .update_status = bl_set_status, | ||
154 | }; | ||
155 | |||
156 | static void msi_wmi_notify(u32 value, void *context) | ||
157 | { | ||
158 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
159 | static struct key_entry *key; | ||
160 | union acpi_object *obj; | ||
161 | ktime_t cur; | ||
162 | |||
163 | wmi_get_event_data(value, &response); | ||
164 | |||
165 | obj = (union acpi_object *)response.pointer; | ||
166 | |||
167 | if (obj && obj->type == ACPI_TYPE_INTEGER) { | ||
168 | int eventcode = obj->integer.value; | ||
169 | dprintk("Eventcode: 0x%x\n", eventcode); | ||
170 | key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev, | ||
171 | eventcode); | ||
172 | if (key) { | ||
173 | ktime_t diff; | ||
174 | cur = ktime_get_real(); | ||
175 | diff = ktime_sub(cur, last_pressed[key->code - | ||
176 | KEYCODE_BASE]); | ||
177 | /* Ignore event if the same event happened in a 50 ms | ||
178 | timeframe -> Key press may result in 10-20 GPEs */ | ||
179 | if (ktime_to_us(diff) < 1000 * 50) { | ||
180 | dprintk("Suppressed key event 0x%X - " | ||
181 | "Last press was %lld us ago\n", | ||
182 | key->code, ktime_to_us(diff)); | ||
183 | return; | ||
184 | } | ||
185 | last_pressed[key->code - KEYCODE_BASE] = cur; | ||
186 | |||
187 | if (key->type == KE_KEY && | ||
188 | /* Brightness is served via acpi video driver */ | ||
189 | (!acpi_video_backlight_support() || | ||
190 | (key->code != MSI_WMI_BRIGHTNESSUP && | ||
191 | key->code != MSI_WMI_BRIGHTNESSDOWN))) { | ||
192 | dprintk("Send key: 0x%X - " | ||
193 | "Input layer keycode: %d\n", key->code, | ||
194 | key->keycode); | ||
195 | sparse_keymap_report_entry(msi_wmi_input_dev, | ||
196 | key, 1, true); | ||
197 | } | ||
198 | } else | ||
199 | printk(KERN_INFO "Unknown key pressed - %x\n", | ||
200 | eventcode); | ||
201 | } else | ||
202 | printk(KERN_INFO DRV_PFX "Unknown event received\n"); | ||
203 | kfree(response.pointer); | ||
204 | } | ||
205 | |||
206 | static int __init msi_wmi_input_setup(void) | ||
207 | { | ||
208 | int err; | ||
209 | |||
210 | msi_wmi_input_dev = input_allocate_device(); | ||
211 | if (!msi_wmi_input_dev) | ||
212 | return -ENOMEM; | ||
213 | |||
214 | msi_wmi_input_dev->name = "MSI WMI hotkeys"; | ||
215 | msi_wmi_input_dev->phys = "wmi/input0"; | ||
216 | msi_wmi_input_dev->id.bustype = BUS_HOST; | ||
217 | |||
218 | err = sparse_keymap_setup(msi_wmi_input_dev, msi_wmi_keymap, NULL); | ||
219 | if (err) | ||
220 | goto err_free_dev; | ||
221 | |||
222 | err = input_register_device(msi_wmi_input_dev); | ||
223 | |||
224 | if (err) | ||
225 | goto err_free_keymap; | ||
226 | |||
227 | memset(last_pressed, 0, sizeof(last_pressed)); | ||
228 | |||
229 | return 0; | ||
230 | |||
231 | err_free_keymap: | ||
232 | sparse_keymap_free(msi_wmi_input_dev); | ||
233 | err_free_dev: | ||
234 | input_free_device(msi_wmi_input_dev); | ||
235 | return err; | ||
236 | } | ||
237 | |||
238 | static int __init msi_wmi_init(void) | ||
239 | { | ||
240 | int err; | ||
241 | |||
242 | if (!wmi_has_guid(MSIWMI_EVENT_GUID)) { | ||
243 | printk(KERN_ERR | ||
244 | "This machine doesn't have MSI-hotkeys through WMI\n"); | ||
245 | return -ENODEV; | ||
246 | } | ||
247 | err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, | ||
248 | msi_wmi_notify, NULL); | ||
249 | if (err) | ||
250 | return -EINVAL; | ||
251 | |||
252 | err = msi_wmi_input_setup(); | ||
253 | if (err) | ||
254 | goto err_uninstall_notifier; | ||
255 | |||
256 | if (!acpi_video_backlight_support()) { | ||
257 | backlight = backlight_device_register(DRV_NAME, | ||
258 | NULL, NULL, &msi_backlight_ops); | ||
259 | if (IS_ERR(backlight)) | ||
260 | goto err_free_input; | ||
261 | |||
262 | backlight->props.max_brightness = ARRAY_SIZE(backlight_map) - 1; | ||
263 | err = bl_get(NULL); | ||
264 | if (err < 0) | ||
265 | goto err_free_backlight; | ||
266 | |||
267 | backlight->props.brightness = err; | ||
268 | } | ||
269 | dprintk("Event handler installed\n"); | ||
270 | |||
271 | return 0; | ||
272 | |||
273 | err_free_backlight: | ||
274 | backlight_device_unregister(backlight); | ||
275 | err_free_input: | ||
276 | input_unregister_device(msi_wmi_input_dev); | ||
277 | err_uninstall_notifier: | ||
278 | wmi_remove_notify_handler(MSIWMI_EVENT_GUID); | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | static void __exit msi_wmi_exit(void) | ||
283 | { | ||
284 | if (wmi_has_guid(MSIWMI_EVENT_GUID)) { | ||
285 | wmi_remove_notify_handler(MSIWMI_EVENT_GUID); | ||
286 | sparse_keymap_free(msi_wmi_input_dev); | ||
287 | input_unregister_device(msi_wmi_input_dev); | ||
288 | backlight_device_unregister(backlight); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | module_init(msi_wmi_init); | ||
293 | module_exit(msi_wmi_exit); | ||
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cf61d6a8ef6f..448c8aeb166b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -21,8 +21,8 @@ | |||
21 | * 02110-1301, USA. | 21 | * 02110-1301, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define TPACPI_VERSION "0.23" | 24 | #define TPACPI_VERSION "0.24" |
25 | #define TPACPI_SYSFS_VERSION 0x020500 | 25 | #define TPACPI_SYSFS_VERSION 0x020700 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
@@ -61,6 +61,7 @@ | |||
61 | 61 | ||
62 | #include <linux/nvram.h> | 62 | #include <linux/nvram.h> |
63 | #include <linux/proc_fs.h> | 63 | #include <linux/proc_fs.h> |
64 | #include <linux/seq_file.h> | ||
64 | #include <linux/sysfs.h> | 65 | #include <linux/sysfs.h> |
65 | #include <linux/backlight.h> | 66 | #include <linux/backlight.h> |
66 | #include <linux/fb.h> | 67 | #include <linux/fb.h> |
@@ -76,6 +77,10 @@ | |||
76 | #include <linux/jiffies.h> | 77 | #include <linux/jiffies.h> |
77 | #include <linux/workqueue.h> | 78 | #include <linux/workqueue.h> |
78 | 79 | ||
80 | #include <sound/core.h> | ||
81 | #include <sound/control.h> | ||
82 | #include <sound/initval.h> | ||
83 | |||
79 | #include <acpi/acpi_drivers.h> | 84 | #include <acpi/acpi_drivers.h> |
80 | 85 | ||
81 | #include <linux/pci_ids.h> | 86 | #include <linux/pci_ids.h> |
@@ -231,6 +236,7 @@ enum tpacpi_hkey_event_t { | |||
231 | #define TPACPI_DBG_HKEY 0x0008 | 236 | #define TPACPI_DBG_HKEY 0x0008 |
232 | #define TPACPI_DBG_FAN 0x0010 | 237 | #define TPACPI_DBG_FAN 0x0010 |
233 | #define TPACPI_DBG_BRGHT 0x0020 | 238 | #define TPACPI_DBG_BRGHT 0x0020 |
239 | #define TPACPI_DBG_MIXER 0x0040 | ||
234 | 240 | ||
235 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") | 241 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") |
236 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 242 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
@@ -256,7 +262,7 @@ struct tp_acpi_drv_struct { | |||
256 | struct ibm_struct { | 262 | struct ibm_struct { |
257 | char *name; | 263 | char *name; |
258 | 264 | ||
259 | int (*read) (char *); | 265 | int (*read) (struct seq_file *); |
260 | int (*write) (char *); | 266 | int (*write) (char *); |
261 | void (*exit) (void); | 267 | void (*exit) (void); |
262 | void (*resume) (void); | 268 | void (*resume) (void); |
@@ -298,6 +304,7 @@ static struct { | |||
298 | u32 fan_ctrl_status_undef:1; | 304 | u32 fan_ctrl_status_undef:1; |
299 | u32 second_fan:1; | 305 | u32 second_fan:1; |
300 | u32 beep_needs_two_args:1; | 306 | u32 beep_needs_two_args:1; |
307 | u32 mixer_no_level_control:1; | ||
301 | u32 input_device_registered:1; | 308 | u32 input_device_registered:1; |
302 | u32 platform_drv_registered:1; | 309 | u32 platform_drv_registered:1; |
303 | u32 platform_drv_attrs_registered:1; | 310 | u32 platform_drv_attrs_registered:1; |
@@ -309,6 +316,7 @@ static struct { | |||
309 | 316 | ||
310 | static struct { | 317 | static struct { |
311 | u16 hotkey_mask_ff:1; | 318 | u16 hotkey_mask_ff:1; |
319 | u16 volume_ctrl_forbidden:1; | ||
312 | } tp_warned; | 320 | } tp_warned; |
313 | 321 | ||
314 | struct thinkpad_id_data { | 322 | struct thinkpad_id_data { |
@@ -425,6 +433,12 @@ static void tpacpi_log_usertask(const char * const what) | |||
425 | .ec = TPACPI_MATCH_ANY, \ | 433 | .ec = TPACPI_MATCH_ANY, \ |
426 | .quirks = (__quirk) } | 434 | .quirks = (__quirk) } |
427 | 435 | ||
436 | #define TPACPI_QEC_LNV(__id1, __id2, __quirk) \ | ||
437 | { .vendor = PCI_VENDOR_ID_LENOVO, \ | ||
438 | .bios = TPACPI_MATCH_ANY, \ | ||
439 | .ec = TPID(__id1, __id2), \ | ||
440 | .quirks = (__quirk) } | ||
441 | |||
428 | struct tpacpi_quirk { | 442 | struct tpacpi_quirk { |
429 | unsigned int vendor; | 443 | unsigned int vendor; |
430 | u16 bios; | 444 | u16 bios; |
@@ -776,36 +790,25 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) | |||
776 | **************************************************************************** | 790 | **************************************************************************** |
777 | ****************************************************************************/ | 791 | ****************************************************************************/ |
778 | 792 | ||
779 | static int dispatch_procfs_read(char *page, char **start, off_t off, | 793 | static int dispatch_proc_show(struct seq_file *m, void *v) |
780 | int count, int *eof, void *data) | ||
781 | { | 794 | { |
782 | struct ibm_struct *ibm = data; | 795 | struct ibm_struct *ibm = m->private; |
783 | int len; | ||
784 | 796 | ||
785 | if (!ibm || !ibm->read) | 797 | if (!ibm || !ibm->read) |
786 | return -EINVAL; | 798 | return -EINVAL; |
799 | return ibm->read(m); | ||
800 | } | ||
787 | 801 | ||
788 | len = ibm->read(page); | 802 | static int dispatch_proc_open(struct inode *inode, struct file *file) |
789 | if (len < 0) | 803 | { |
790 | return len; | 804 | return single_open(file, dispatch_proc_show, PDE(inode)->data); |
791 | |||
792 | if (len <= off + count) | ||
793 | *eof = 1; | ||
794 | *start = page + off; | ||
795 | len -= off; | ||
796 | if (len > count) | ||
797 | len = count; | ||
798 | if (len < 0) | ||
799 | len = 0; | ||
800 | |||
801 | return len; | ||
802 | } | 805 | } |
803 | 806 | ||
804 | static int dispatch_procfs_write(struct file *file, | 807 | static ssize_t dispatch_proc_write(struct file *file, |
805 | const char __user *userbuf, | 808 | const char __user *userbuf, |
806 | unsigned long count, void *data) | 809 | size_t count, loff_t *pos) |
807 | { | 810 | { |
808 | struct ibm_struct *ibm = data; | 811 | struct ibm_struct *ibm = PDE(file->f_path.dentry->d_inode)->data; |
809 | char *kernbuf; | 812 | char *kernbuf; |
810 | int ret; | 813 | int ret; |
811 | 814 | ||
@@ -834,6 +837,15 @@ static int dispatch_procfs_write(struct file *file, | |||
834 | return ret; | 837 | return ret; |
835 | } | 838 | } |
836 | 839 | ||
840 | static const struct file_operations dispatch_proc_fops = { | ||
841 | .owner = THIS_MODULE, | ||
842 | .open = dispatch_proc_open, | ||
843 | .read = seq_read, | ||
844 | .llseek = seq_lseek, | ||
845 | .release = single_release, | ||
846 | .write = dispatch_proc_write, | ||
847 | }; | ||
848 | |||
837 | static char *next_cmd(char **cmds) | 849 | static char *next_cmd(char **cmds) |
838 | { | 850 | { |
839 | char *start = *cmds; | 851 | char *start = *cmds; |
@@ -1261,6 +1273,7 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | |||
1261 | struct tpacpi_rfk *atp_rfk; | 1273 | struct tpacpi_rfk *atp_rfk; |
1262 | int res; | 1274 | int res; |
1263 | bool sw_state = false; | 1275 | bool sw_state = false; |
1276 | bool hw_state; | ||
1264 | int sw_status; | 1277 | int sw_status; |
1265 | 1278 | ||
1266 | BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); | 1279 | BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); |
@@ -1295,7 +1308,8 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | |||
1295 | rfkill_init_sw_state(atp_rfk->rfkill, sw_state); | 1308 | rfkill_init_sw_state(atp_rfk->rfkill, sw_state); |
1296 | } | 1309 | } |
1297 | } | 1310 | } |
1298 | rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); | 1311 | hw_state = tpacpi_rfk_check_hwblock_state(); |
1312 | rfkill_set_hw_state(atp_rfk->rfkill, hw_state); | ||
1299 | 1313 | ||
1300 | res = rfkill_register(atp_rfk->rfkill); | 1314 | res = rfkill_register(atp_rfk->rfkill); |
1301 | if (res < 0) { | 1315 | if (res < 0) { |
@@ -1308,6 +1322,9 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | |||
1308 | } | 1322 | } |
1309 | 1323 | ||
1310 | tpacpi_rfkill_switches[id] = atp_rfk; | 1324 | tpacpi_rfkill_switches[id] = atp_rfk; |
1325 | |||
1326 | printk(TPACPI_INFO "rfkill switch %s: radio is %sblocked\n", | ||
1327 | name, (sw_state || hw_state) ? "" : "un"); | ||
1311 | return 0; | 1328 | return 0; |
1312 | } | 1329 | } |
1313 | 1330 | ||
@@ -1380,12 +1397,10 @@ static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, | |||
1380 | } | 1397 | } |
1381 | 1398 | ||
1382 | /* procfs -------------------------------------------------------------- */ | 1399 | /* procfs -------------------------------------------------------------- */ |
1383 | static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) | 1400 | static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *m) |
1384 | { | 1401 | { |
1385 | int len = 0; | ||
1386 | |||
1387 | if (id >= TPACPI_RFK_SW_MAX) | 1402 | if (id >= TPACPI_RFK_SW_MAX) |
1388 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 1403 | seq_printf(m, "status:\t\tnot supported\n"); |
1389 | else { | 1404 | else { |
1390 | int status; | 1405 | int status; |
1391 | 1406 | ||
@@ -1399,13 +1414,13 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) | |||
1399 | return status; | 1414 | return status; |
1400 | } | 1415 | } |
1401 | 1416 | ||
1402 | len += sprintf(p + len, "status:\t\t%s\n", | 1417 | seq_printf(m, "status:\t\t%s\n", |
1403 | (status == TPACPI_RFK_RADIO_ON) ? | 1418 | (status == TPACPI_RFK_RADIO_ON) ? |
1404 | "enabled" : "disabled"); | 1419 | "enabled" : "disabled"); |
1405 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 1420 | seq_printf(m, "commands:\tenable, disable\n"); |
1406 | } | 1421 | } |
1407 | 1422 | ||
1408 | return len; | 1423 | return 0; |
1409 | } | 1424 | } |
1410 | 1425 | ||
1411 | static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) | 1426 | static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) |
@@ -1776,7 +1791,7 @@ static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { | |||
1776 | 1791 | ||
1777 | TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ | 1792 | TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ |
1778 | TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ | 1793 | TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ |
1779 | TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */ | 1794 | TPV_QL1('7', 'E', 'D', '0', '1', '5'), /* R60e, R60i */ |
1780 | 1795 | ||
1781 | /* BIOS FW BIOS VERS EC FW EC VERS */ | 1796 | /* BIOS FW BIOS VERS EC FW EC VERS */ |
1782 | TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ | 1797 | TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ |
@@ -1792,8 +1807,8 @@ static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { | |||
1792 | TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ | 1807 | TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ |
1793 | TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ | 1808 | TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ |
1794 | 1809 | ||
1795 | TPV_QL0('7', 'B', 'D', '7'), /* X60/s */ | 1810 | TPV_QL1('7', 'B', 'D', '7', '4', '0'), /* X60/s */ |
1796 | TPV_QL0('7', 'J', '3', '0'), /* X60t */ | 1811 | TPV_QL1('7', 'J', '3', '0', '1', '3'), /* X60t */ |
1797 | 1812 | ||
1798 | /* (0) - older versions lack DMI EC fw string and functionality */ | 1813 | /* (0) - older versions lack DMI EC fw string and functionality */ |
1799 | /* (1) - older versions known to lack functionality */ | 1814 | /* (1) - older versions known to lack functionality */ |
@@ -1883,14 +1898,11 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) | |||
1883 | return 0; | 1898 | return 0; |
1884 | } | 1899 | } |
1885 | 1900 | ||
1886 | static int thinkpad_acpi_driver_read(char *p) | 1901 | static int thinkpad_acpi_driver_read(struct seq_file *m) |
1887 | { | 1902 | { |
1888 | int len = 0; | 1903 | seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC); |
1889 | 1904 | seq_printf(m, "version:\t%s\n", TPACPI_VERSION); | |
1890 | len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC); | 1905 | return 0; |
1891 | len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION); | ||
1892 | |||
1893 | return len; | ||
1894 | } | 1906 | } |
1895 | 1907 | ||
1896 | static struct ibm_struct thinkpad_acpi_driver_data = { | 1908 | static struct ibm_struct thinkpad_acpi_driver_data = { |
@@ -2186,7 +2198,8 @@ static int hotkey_mask_set(u32 mask) | |||
2186 | fwmask, hotkey_acpi_mask); | 2198 | fwmask, hotkey_acpi_mask); |
2187 | } | 2199 | } |
2188 | 2200 | ||
2189 | hotkey_mask_warn_incomplete_mask(); | 2201 | if (tpacpi_lifecycle != TPACPI_LIFE_EXITING) |
2202 | hotkey_mask_warn_incomplete_mask(); | ||
2190 | 2203 | ||
2191 | return rc; | 2204 | return rc; |
2192 | } | 2205 | } |
@@ -3182,6 +3195,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3182 | int res, i; | 3195 | int res, i; |
3183 | int status; | 3196 | int status; |
3184 | int hkeyv; | 3197 | int hkeyv; |
3198 | bool radiosw_state = false; | ||
3199 | bool tabletsw_state = false; | ||
3185 | 3200 | ||
3186 | unsigned long quirks; | 3201 | unsigned long quirks; |
3187 | 3202 | ||
@@ -3287,6 +3302,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3287 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3302 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
3288 | if (dbg_wlswemul) { | 3303 | if (dbg_wlswemul) { |
3289 | tp_features.hotkey_wlsw = 1; | 3304 | tp_features.hotkey_wlsw = 1; |
3305 | radiosw_state = !!tpacpi_wlsw_emulstate; | ||
3290 | printk(TPACPI_INFO | 3306 | printk(TPACPI_INFO |
3291 | "radio switch emulation enabled\n"); | 3307 | "radio switch emulation enabled\n"); |
3292 | } else | 3308 | } else |
@@ -3294,6 +3310,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3294 | /* Not all thinkpads have a hardware radio switch */ | 3310 | /* Not all thinkpads have a hardware radio switch */ |
3295 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | 3311 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { |
3296 | tp_features.hotkey_wlsw = 1; | 3312 | tp_features.hotkey_wlsw = 1; |
3313 | radiosw_state = !!status; | ||
3297 | printk(TPACPI_INFO | 3314 | printk(TPACPI_INFO |
3298 | "radio switch found; radios are %s\n", | 3315 | "radio switch found; radios are %s\n", |
3299 | enabled(status, 0)); | 3316 | enabled(status, 0)); |
@@ -3305,11 +3322,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3305 | /* For X41t, X60t, X61t Tablets... */ | 3322 | /* For X41t, X60t, X61t Tablets... */ |
3306 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { | 3323 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { |
3307 | tp_features.hotkey_tablet = 1; | 3324 | tp_features.hotkey_tablet = 1; |
3325 | tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK); | ||
3308 | printk(TPACPI_INFO | 3326 | printk(TPACPI_INFO |
3309 | "possible tablet mode switch found; " | 3327 | "possible tablet mode switch found; " |
3310 | "ThinkPad in %s mode\n", | 3328 | "ThinkPad in %s mode\n", |
3311 | (status & TP_HOTKEY_TABLET_MASK)? | 3329 | (tabletsw_state) ? "tablet" : "laptop"); |
3312 | "tablet" : "laptop"); | ||
3313 | res = add_to_attr_set(hotkey_dev_attributes, | 3330 | res = add_to_attr_set(hotkey_dev_attributes, |
3314 | &dev_attr_hotkey_tablet_mode.attr); | 3331 | &dev_attr_hotkey_tablet_mode.attr); |
3315 | } | 3332 | } |
@@ -3344,16 +3361,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3344 | TPACPI_HOTKEY_MAP_SIZE); | 3361 | TPACPI_HOTKEY_MAP_SIZE); |
3345 | } | 3362 | } |
3346 | 3363 | ||
3347 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | 3364 | input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); |
3348 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
3349 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
3350 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | 3365 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; |
3351 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | 3366 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; |
3352 | tpacpi_inputdev->keycode = hotkey_keycode_map; | 3367 | tpacpi_inputdev->keycode = hotkey_keycode_map; |
3353 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | 3368 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { |
3354 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | 3369 | if (hotkey_keycode_map[i] != KEY_RESERVED) { |
3355 | set_bit(hotkey_keycode_map[i], | 3370 | input_set_capability(tpacpi_inputdev, EV_KEY, |
3356 | tpacpi_inputdev->keybit); | 3371 | hotkey_keycode_map[i]); |
3357 | } else { | 3372 | } else { |
3358 | if (i < sizeof(hotkey_reserved_mask)*8) | 3373 | if (i < sizeof(hotkey_reserved_mask)*8) |
3359 | hotkey_reserved_mask |= 1 << i; | 3374 | hotkey_reserved_mask |= 1 << i; |
@@ -3361,12 +3376,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3361 | } | 3376 | } |
3362 | 3377 | ||
3363 | if (tp_features.hotkey_wlsw) { | 3378 | if (tp_features.hotkey_wlsw) { |
3364 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 3379 | input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL); |
3365 | set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); | 3380 | input_report_switch(tpacpi_inputdev, |
3381 | SW_RFKILL_ALL, radiosw_state); | ||
3366 | } | 3382 | } |
3367 | if (tp_features.hotkey_tablet) { | 3383 | if (tp_features.hotkey_tablet) { |
3368 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 3384 | input_set_capability(tpacpi_inputdev, EV_SW, SW_TABLET_MODE); |
3369 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); | 3385 | input_report_switch(tpacpi_inputdev, |
3386 | SW_TABLET_MODE, tabletsw_state); | ||
3370 | } | 3387 | } |
3371 | 3388 | ||
3372 | /* Do not issue duplicate brightness change events to | 3389 | /* Do not issue duplicate brightness change events to |
@@ -3433,8 +3450,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3433 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 3450 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
3434 | 3451 | ||
3435 | hotkey_poll_setup_safe(true); | 3452 | hotkey_poll_setup_safe(true); |
3436 | tpacpi_send_radiosw_update(); | ||
3437 | tpacpi_input_send_tabletsw(); | ||
3438 | 3453 | ||
3439 | return 0; | 3454 | return 0; |
3440 | 3455 | ||
@@ -3542,49 +3557,57 @@ static bool hotkey_notify_usrevent(const u32 hkey, | |||
3542 | } | 3557 | } |
3543 | } | 3558 | } |
3544 | 3559 | ||
3560 | static void thermal_dump_all_sensors(void); | ||
3561 | |||
3545 | static bool hotkey_notify_thermal(const u32 hkey, | 3562 | static bool hotkey_notify_thermal(const u32 hkey, |
3546 | bool *send_acpi_ev, | 3563 | bool *send_acpi_ev, |
3547 | bool *ignore_acpi_ev) | 3564 | bool *ignore_acpi_ev) |
3548 | { | 3565 | { |
3566 | bool known = true; | ||
3567 | |||
3549 | /* 0x6000-0x6FFF: thermal alarms */ | 3568 | /* 0x6000-0x6FFF: thermal alarms */ |
3550 | *send_acpi_ev = true; | 3569 | *send_acpi_ev = true; |
3551 | *ignore_acpi_ev = false; | 3570 | *ignore_acpi_ev = false; |
3552 | 3571 | ||
3553 | switch (hkey) { | 3572 | switch (hkey) { |
3573 | case TP_HKEY_EV_THM_TABLE_CHANGED: | ||
3574 | printk(TPACPI_INFO | ||
3575 | "EC reports that Thermal Table has changed\n"); | ||
3576 | /* recommended action: do nothing, we don't have | ||
3577 | * Lenovo ATM information */ | ||
3578 | return true; | ||
3554 | case TP_HKEY_EV_ALARM_BAT_HOT: | 3579 | case TP_HKEY_EV_ALARM_BAT_HOT: |
3555 | printk(TPACPI_CRIT | 3580 | printk(TPACPI_CRIT |
3556 | "THERMAL ALARM: battery is too hot!\n"); | 3581 | "THERMAL ALARM: battery is too hot!\n"); |
3557 | /* recommended action: warn user through gui */ | 3582 | /* recommended action: warn user through gui */ |
3558 | return true; | 3583 | break; |
3559 | case TP_HKEY_EV_ALARM_BAT_XHOT: | 3584 | case TP_HKEY_EV_ALARM_BAT_XHOT: |
3560 | printk(TPACPI_ALERT | 3585 | printk(TPACPI_ALERT |
3561 | "THERMAL EMERGENCY: battery is extremely hot!\n"); | 3586 | "THERMAL EMERGENCY: battery is extremely hot!\n"); |
3562 | /* recommended action: immediate sleep/hibernate */ | 3587 | /* recommended action: immediate sleep/hibernate */ |
3563 | return true; | 3588 | break; |
3564 | case TP_HKEY_EV_ALARM_SENSOR_HOT: | 3589 | case TP_HKEY_EV_ALARM_SENSOR_HOT: |
3565 | printk(TPACPI_CRIT | 3590 | printk(TPACPI_CRIT |
3566 | "THERMAL ALARM: " | 3591 | "THERMAL ALARM: " |
3567 | "a sensor reports something is too hot!\n"); | 3592 | "a sensor reports something is too hot!\n"); |
3568 | /* recommended action: warn user through gui, that */ | 3593 | /* recommended action: warn user through gui, that */ |
3569 | /* some internal component is too hot */ | 3594 | /* some internal component is too hot */ |
3570 | return true; | 3595 | break; |
3571 | case TP_HKEY_EV_ALARM_SENSOR_XHOT: | 3596 | case TP_HKEY_EV_ALARM_SENSOR_XHOT: |
3572 | printk(TPACPI_ALERT | 3597 | printk(TPACPI_ALERT |
3573 | "THERMAL EMERGENCY: " | 3598 | "THERMAL EMERGENCY: " |
3574 | "a sensor reports something is extremely hot!\n"); | 3599 | "a sensor reports something is extremely hot!\n"); |
3575 | /* recommended action: immediate sleep/hibernate */ | 3600 | /* recommended action: immediate sleep/hibernate */ |
3576 | return true; | 3601 | break; |
3577 | case TP_HKEY_EV_THM_TABLE_CHANGED: | ||
3578 | printk(TPACPI_INFO | ||
3579 | "EC reports that Thermal Table has changed\n"); | ||
3580 | /* recommended action: do nothing, we don't have | ||
3581 | * Lenovo ATM information */ | ||
3582 | return true; | ||
3583 | default: | 3602 | default: |
3584 | printk(TPACPI_ALERT | 3603 | printk(TPACPI_ALERT |
3585 | "THERMAL ALERT: unknown thermal alarm received\n"); | 3604 | "THERMAL ALERT: unknown thermal alarm received\n"); |
3586 | return false; | 3605 | known = false; |
3587 | } | 3606 | } |
3607 | |||
3608 | thermal_dump_all_sensors(); | ||
3609 | |||
3610 | return known; | ||
3588 | } | 3611 | } |
3589 | 3612 | ||
3590 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 3613 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
@@ -3727,14 +3750,13 @@ static void hotkey_resume(void) | |||
3727 | } | 3750 | } |
3728 | 3751 | ||
3729 | /* procfs -------------------------------------------------------------- */ | 3752 | /* procfs -------------------------------------------------------------- */ |
3730 | static int hotkey_read(char *p) | 3753 | static int hotkey_read(struct seq_file *m) |
3731 | { | 3754 | { |
3732 | int res, status; | 3755 | int res, status; |
3733 | int len = 0; | ||
3734 | 3756 | ||
3735 | if (!tp_features.hotkey) { | 3757 | if (!tp_features.hotkey) { |
3736 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3758 | seq_printf(m, "status:\t\tnot supported\n"); |
3737 | return len; | 3759 | return 0; |
3738 | } | 3760 | } |
3739 | 3761 | ||
3740 | if (mutex_lock_killable(&hotkey_mutex)) | 3762 | if (mutex_lock_killable(&hotkey_mutex)) |
@@ -3746,17 +3768,16 @@ static int hotkey_read(char *p) | |||
3746 | if (res) | 3768 | if (res) |
3747 | return res; | 3769 | return res; |
3748 | 3770 | ||
3749 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 3771 | seq_printf(m, "status:\t\t%s\n", enabled(status, 0)); |
3750 | if (hotkey_all_mask) { | 3772 | if (hotkey_all_mask) { |
3751 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask); | 3773 | seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask); |
3752 | len += sprintf(p + len, | 3774 | seq_printf(m, "commands:\tenable, disable, reset, <mask>\n"); |
3753 | "commands:\tenable, disable, reset, <mask>\n"); | ||
3754 | } else { | 3775 | } else { |
3755 | len += sprintf(p + len, "mask:\t\tnot supported\n"); | 3776 | seq_printf(m, "mask:\t\tnot supported\n"); |
3756 | len += sprintf(p + len, "commands:\tenable, disable, reset\n"); | 3777 | seq_printf(m, "commands:\tenable, disable, reset\n"); |
3757 | } | 3778 | } |
3758 | 3779 | ||
3759 | return len; | 3780 | return 0; |
3760 | } | 3781 | } |
3761 | 3782 | ||
3762 | static void hotkey_enabledisable_warn(bool enable) | 3783 | static void hotkey_enabledisable_warn(bool enable) |
@@ -3863,15 +3884,6 @@ enum { | |||
3863 | 3884 | ||
3864 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" | 3885 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" |
3865 | 3886 | ||
3866 | static void bluetooth_suspend(pm_message_t state) | ||
3867 | { | ||
3868 | /* Try to make sure radio will resume powered off */ | ||
3869 | if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd", | ||
3870 | TP_ACPI_BLTH_PWR_OFF_ON_RESUME)) | ||
3871 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
3872 | "bluetooth power down on resume request failed\n"); | ||
3873 | } | ||
3874 | |||
3875 | static int bluetooth_get_status(void) | 3887 | static int bluetooth_get_status(void) |
3876 | { | 3888 | { |
3877 | int status; | 3889 | int status; |
@@ -3905,10 +3917,9 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state) | |||
3905 | #endif | 3917 | #endif |
3906 | 3918 | ||
3907 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ | 3919 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ |
3920 | status = TP_ACPI_BLUETOOTH_RESUMECTRL; | ||
3908 | if (state == TPACPI_RFK_RADIO_ON) | 3921 | if (state == TPACPI_RFK_RADIO_ON) |
3909 | status = TP_ACPI_BLUETOOTH_RADIOSSW; | 3922 | status |= TP_ACPI_BLUETOOTH_RADIOSSW; |
3910 | else | ||
3911 | status = 0; | ||
3912 | 3923 | ||
3913 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 3924 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
3914 | return -EIO; | 3925 | return -EIO; |
@@ -4032,9 +4043,9 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
4032 | } | 4043 | } |
4033 | 4044 | ||
4034 | /* procfs -------------------------------------------------------------- */ | 4045 | /* procfs -------------------------------------------------------------- */ |
4035 | static int bluetooth_read(char *p) | 4046 | static int bluetooth_read(struct seq_file *m) |
4036 | { | 4047 | { |
4037 | return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); | 4048 | return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, m); |
4038 | } | 4049 | } |
4039 | 4050 | ||
4040 | static int bluetooth_write(char *buf) | 4051 | static int bluetooth_write(char *buf) |
@@ -4047,7 +4058,6 @@ static struct ibm_struct bluetooth_driver_data = { | |||
4047 | .read = bluetooth_read, | 4058 | .read = bluetooth_read, |
4048 | .write = bluetooth_write, | 4059 | .write = bluetooth_write, |
4049 | .exit = bluetooth_exit, | 4060 | .exit = bluetooth_exit, |
4050 | .suspend = bluetooth_suspend, | ||
4051 | .shutdown = bluetooth_shutdown, | 4061 | .shutdown = bluetooth_shutdown, |
4052 | }; | 4062 | }; |
4053 | 4063 | ||
@@ -4065,15 +4075,6 @@ enum { | |||
4065 | 4075 | ||
4066 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" | 4076 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" |
4067 | 4077 | ||
4068 | static void wan_suspend(pm_message_t state) | ||
4069 | { | ||
4070 | /* Try to make sure radio will resume powered off */ | ||
4071 | if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd", | ||
4072 | TP_ACPI_WGSV_PWR_OFF_ON_RESUME)) | ||
4073 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
4074 | "WWAN power down on resume request failed\n"); | ||
4075 | } | ||
4076 | |||
4077 | static int wan_get_status(void) | 4078 | static int wan_get_status(void) |
4078 | { | 4079 | { |
4079 | int status; | 4080 | int status; |
@@ -4106,11 +4107,10 @@ static int wan_set_status(enum tpacpi_rfkill_state state) | |||
4106 | } | 4107 | } |
4107 | #endif | 4108 | #endif |
4108 | 4109 | ||
4109 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ | 4110 | /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */ |
4111 | status = TP_ACPI_WANCARD_RESUMECTRL; | ||
4110 | if (state == TPACPI_RFK_RADIO_ON) | 4112 | if (state == TPACPI_RFK_RADIO_ON) |
4111 | status = TP_ACPI_WANCARD_RADIOSSW; | 4113 | status |= TP_ACPI_WANCARD_RADIOSSW; |
4112 | else | ||
4113 | status = 0; | ||
4114 | 4114 | ||
4115 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 4115 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
4116 | return -EIO; | 4116 | return -EIO; |
@@ -4233,9 +4233,9 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
4233 | } | 4233 | } |
4234 | 4234 | ||
4235 | /* procfs -------------------------------------------------------------- */ | 4235 | /* procfs -------------------------------------------------------------- */ |
4236 | static int wan_read(char *p) | 4236 | static int wan_read(struct seq_file *m) |
4237 | { | 4237 | { |
4238 | return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); | 4238 | return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, m); |
4239 | } | 4239 | } |
4240 | 4240 | ||
4241 | static int wan_write(char *buf) | 4241 | static int wan_write(char *buf) |
@@ -4248,7 +4248,6 @@ static struct ibm_struct wan_driver_data = { | |||
4248 | .read = wan_read, | 4248 | .read = wan_read, |
4249 | .write = wan_write, | 4249 | .write = wan_write, |
4250 | .exit = wan_exit, | 4250 | .exit = wan_exit, |
4251 | .suspend = wan_suspend, | ||
4252 | .shutdown = wan_shutdown, | 4251 | .shutdown = wan_shutdown, |
4253 | }; | 4252 | }; |
4254 | 4253 | ||
@@ -4611,14 +4610,13 @@ static int video_expand_toggle(void) | |||
4611 | /* not reached */ | 4610 | /* not reached */ |
4612 | } | 4611 | } |
4613 | 4612 | ||
4614 | static int video_read(char *p) | 4613 | static int video_read(struct seq_file *m) |
4615 | { | 4614 | { |
4616 | int status, autosw; | 4615 | int status, autosw; |
4617 | int len = 0; | ||
4618 | 4616 | ||
4619 | if (video_supported == TPACPI_VIDEO_NONE) { | 4617 | if (video_supported == TPACPI_VIDEO_NONE) { |
4620 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4618 | seq_printf(m, "status:\t\tnot supported\n"); |
4621 | return len; | 4619 | return 0; |
4622 | } | 4620 | } |
4623 | 4621 | ||
4624 | status = video_outputsw_get(); | 4622 | status = video_outputsw_get(); |
@@ -4629,20 +4627,20 @@ static int video_read(char *p) | |||
4629 | if (autosw < 0) | 4627 | if (autosw < 0) |
4630 | return autosw; | 4628 | return autosw; |
4631 | 4629 | ||
4632 | len += sprintf(p + len, "status:\t\tsupported\n"); | 4630 | seq_printf(m, "status:\t\tsupported\n"); |
4633 | len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); | 4631 | seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0)); |
4634 | len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); | 4632 | seq_printf(m, "crt:\t\t%s\n", enabled(status, 1)); |
4635 | if (video_supported == TPACPI_VIDEO_NEW) | 4633 | if (video_supported == TPACPI_VIDEO_NEW) |
4636 | len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); | 4634 | seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3)); |
4637 | len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); | 4635 | seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0)); |
4638 | len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); | 4636 | seq_printf(m, "commands:\tlcd_enable, lcd_disable\n"); |
4639 | len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); | 4637 | seq_printf(m, "commands:\tcrt_enable, crt_disable\n"); |
4640 | if (video_supported == TPACPI_VIDEO_NEW) | 4638 | if (video_supported == TPACPI_VIDEO_NEW) |
4641 | len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); | 4639 | seq_printf(m, "commands:\tdvi_enable, dvi_disable\n"); |
4642 | len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); | 4640 | seq_printf(m, "commands:\tauto_enable, auto_disable\n"); |
4643 | len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); | 4641 | seq_printf(m, "commands:\tvideo_switch, expand_toggle\n"); |
4644 | 4642 | ||
4645 | return len; | 4643 | return 0; |
4646 | } | 4644 | } |
4647 | 4645 | ||
4648 | static int video_write(char *buf) | 4646 | static int video_write(char *buf) |
@@ -4834,25 +4832,24 @@ static void light_exit(void) | |||
4834 | flush_workqueue(tpacpi_wq); | 4832 | flush_workqueue(tpacpi_wq); |
4835 | } | 4833 | } |
4836 | 4834 | ||
4837 | static int light_read(char *p) | 4835 | static int light_read(struct seq_file *m) |
4838 | { | 4836 | { |
4839 | int len = 0; | ||
4840 | int status; | 4837 | int status; |
4841 | 4838 | ||
4842 | if (!tp_features.light) { | 4839 | if (!tp_features.light) { |
4843 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4840 | seq_printf(m, "status:\t\tnot supported\n"); |
4844 | } else if (!tp_features.light_status) { | 4841 | } else if (!tp_features.light_status) { |
4845 | len += sprintf(p + len, "status:\t\tunknown\n"); | 4842 | seq_printf(m, "status:\t\tunknown\n"); |
4846 | len += sprintf(p + len, "commands:\ton, off\n"); | 4843 | seq_printf(m, "commands:\ton, off\n"); |
4847 | } else { | 4844 | } else { |
4848 | status = light_get_status(); | 4845 | status = light_get_status(); |
4849 | if (status < 0) | 4846 | if (status < 0) |
4850 | return status; | 4847 | return status; |
4851 | len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); | 4848 | seq_printf(m, "status:\t\t%s\n", onoff(status, 0)); |
4852 | len += sprintf(p + len, "commands:\ton, off\n"); | 4849 | seq_printf(m, "commands:\ton, off\n"); |
4853 | } | 4850 | } |
4854 | 4851 | ||
4855 | return len; | 4852 | return 0; |
4856 | } | 4853 | } |
4857 | 4854 | ||
4858 | static int light_write(char *buf) | 4855 | static int light_write(char *buf) |
@@ -4930,20 +4927,18 @@ static void cmos_exit(void) | |||
4930 | device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); | 4927 | device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); |
4931 | } | 4928 | } |
4932 | 4929 | ||
4933 | static int cmos_read(char *p) | 4930 | static int cmos_read(struct seq_file *m) |
4934 | { | 4931 | { |
4935 | int len = 0; | ||
4936 | |||
4937 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 4932 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
4938 | R30, R31, T20-22, X20-21 */ | 4933 | R30, R31, T20-22, X20-21 */ |
4939 | if (!cmos_handle) | 4934 | if (!cmos_handle) |
4940 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4935 | seq_printf(m, "status:\t\tnot supported\n"); |
4941 | else { | 4936 | else { |
4942 | len += sprintf(p + len, "status:\t\tsupported\n"); | 4937 | seq_printf(m, "status:\t\tsupported\n"); |
4943 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); | 4938 | seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n"); |
4944 | } | 4939 | } |
4945 | 4940 | ||
4946 | return len; | 4941 | return 0; |
4947 | } | 4942 | } |
4948 | 4943 | ||
4949 | static int cmos_write(char *buf) | 4944 | static int cmos_write(char *buf) |
@@ -5318,15 +5313,13 @@ static int __init led_init(struct ibm_init_struct *iibm) | |||
5318 | ((s) == TPACPI_LED_OFF ? "off" : \ | 5313 | ((s) == TPACPI_LED_OFF ? "off" : \ |
5319 | ((s) == TPACPI_LED_ON ? "on" : "blinking")) | 5314 | ((s) == TPACPI_LED_ON ? "on" : "blinking")) |
5320 | 5315 | ||
5321 | static int led_read(char *p) | 5316 | static int led_read(struct seq_file *m) |
5322 | { | 5317 | { |
5323 | int len = 0; | ||
5324 | |||
5325 | if (!led_supported) { | 5318 | if (!led_supported) { |
5326 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 5319 | seq_printf(m, "status:\t\tnot supported\n"); |
5327 | return len; | 5320 | return 0; |
5328 | } | 5321 | } |
5329 | len += sprintf(p + len, "status:\t\tsupported\n"); | 5322 | seq_printf(m, "status:\t\tsupported\n"); |
5330 | 5323 | ||
5331 | if (led_supported == TPACPI_LED_570) { | 5324 | if (led_supported == TPACPI_LED_570) { |
5332 | /* 570 */ | 5325 | /* 570 */ |
@@ -5335,15 +5328,15 @@ static int led_read(char *p) | |||
5335 | status = led_get_status(i); | 5328 | status = led_get_status(i); |
5336 | if (status < 0) | 5329 | if (status < 0) |
5337 | return -EIO; | 5330 | return -EIO; |
5338 | len += sprintf(p + len, "%d:\t\t%s\n", | 5331 | seq_printf(m, "%d:\t\t%s\n", |
5339 | i, str_led_status(status)); | 5332 | i, str_led_status(status)); |
5340 | } | 5333 | } |
5341 | } | 5334 | } |
5342 | 5335 | ||
5343 | len += sprintf(p + len, "commands:\t" | 5336 | seq_printf(m, "commands:\t" |
5344 | "<led> on, <led> off, <led> blink (<led> is 0-15)\n"); | 5337 | "<led> on, <led> off, <led> blink (<led> is 0-15)\n"); |
5345 | 5338 | ||
5346 | return len; | 5339 | return 0; |
5347 | } | 5340 | } |
5348 | 5341 | ||
5349 | static int led_write(char *buf) | 5342 | static int led_write(char *buf) |
@@ -5416,18 +5409,16 @@ static int __init beep_init(struct ibm_init_struct *iibm) | |||
5416 | return (beep_handle)? 0 : 1; | 5409 | return (beep_handle)? 0 : 1; |
5417 | } | 5410 | } |
5418 | 5411 | ||
5419 | static int beep_read(char *p) | 5412 | static int beep_read(struct seq_file *m) |
5420 | { | 5413 | { |
5421 | int len = 0; | ||
5422 | |||
5423 | if (!beep_handle) | 5414 | if (!beep_handle) |
5424 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 5415 | seq_printf(m, "status:\t\tnot supported\n"); |
5425 | else { | 5416 | else { |
5426 | len += sprintf(p + len, "status:\t\tsupported\n"); | 5417 | seq_printf(m, "status:\t\tsupported\n"); |
5427 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); | 5418 | seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n"); |
5428 | } | 5419 | } |
5429 | 5420 | ||
5430 | return len; | 5421 | return 0; |
5431 | } | 5422 | } |
5432 | 5423 | ||
5433 | static int beep_write(char *buf) | 5424 | static int beep_write(char *buf) |
@@ -5480,8 +5471,11 @@ enum { /* TPACPI_THERMAL_TPEC_* */ | |||
5480 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ | 5471 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ |
5481 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ | 5472 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ |
5482 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ | 5473 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ |
5474 | |||
5475 | TPACPI_THERMAL_SENSOR_NA = -128000, /* Sensor not available */ | ||
5483 | }; | 5476 | }; |
5484 | 5477 | ||
5478 | |||
5485 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ | 5479 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ |
5486 | struct ibm_thermal_sensors_struct { | 5480 | struct ibm_thermal_sensors_struct { |
5487 | s32 temp[TPACPI_MAX_THERMAL_SENSORS]; | 5481 | s32 temp[TPACPI_MAX_THERMAL_SENSORS]; |
@@ -5571,6 +5565,28 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) | |||
5571 | return n; | 5565 | return n; |
5572 | } | 5566 | } |
5573 | 5567 | ||
5568 | static void thermal_dump_all_sensors(void) | ||
5569 | { | ||
5570 | int n, i; | ||
5571 | struct ibm_thermal_sensors_struct t; | ||
5572 | |||
5573 | n = thermal_get_sensors(&t); | ||
5574 | if (n <= 0) | ||
5575 | return; | ||
5576 | |||
5577 | printk(TPACPI_NOTICE | ||
5578 | "temperatures (Celsius):"); | ||
5579 | |||
5580 | for (i = 0; i < n; i++) { | ||
5581 | if (t.temp[i] != TPACPI_THERMAL_SENSOR_NA) | ||
5582 | printk(KERN_CONT " %d", (int)(t.temp[i] / 1000)); | ||
5583 | else | ||
5584 | printk(KERN_CONT " N/A"); | ||
5585 | } | ||
5586 | |||
5587 | printk(KERN_CONT "\n"); | ||
5588 | } | ||
5589 | |||
5574 | /* sysfs temp##_input -------------------------------------------------- */ | 5590 | /* sysfs temp##_input -------------------------------------------------- */ |
5575 | 5591 | ||
5576 | static ssize_t thermal_temp_input_show(struct device *dev, | 5592 | static ssize_t thermal_temp_input_show(struct device *dev, |
@@ -5586,7 +5602,7 @@ static ssize_t thermal_temp_input_show(struct device *dev, | |||
5586 | res = thermal_get_sensor(idx, &value); | 5602 | res = thermal_get_sensor(idx, &value); |
5587 | if (res) | 5603 | if (res) |
5588 | return res; | 5604 | return res; |
5589 | if (value == TP_EC_THERMAL_TMP_NA * 1000) | 5605 | if (value == TPACPI_THERMAL_SENSOR_NA) |
5590 | return -ENXIO; | 5606 | return -ENXIO; |
5591 | 5607 | ||
5592 | return snprintf(buf, PAGE_SIZE, "%d\n", value); | 5608 | return snprintf(buf, PAGE_SIZE, "%d\n", value); |
@@ -5763,9 +5779,8 @@ static void thermal_exit(void) | |||
5763 | } | 5779 | } |
5764 | } | 5780 | } |
5765 | 5781 | ||
5766 | static int thermal_read(char *p) | 5782 | static int thermal_read(struct seq_file *m) |
5767 | { | 5783 | { |
5768 | int len = 0; | ||
5769 | int n, i; | 5784 | int n, i; |
5770 | struct ibm_thermal_sensors_struct t; | 5785 | struct ibm_thermal_sensors_struct t; |
5771 | 5786 | ||
@@ -5773,16 +5788,16 @@ static int thermal_read(char *p) | |||
5773 | if (unlikely(n < 0)) | 5788 | if (unlikely(n < 0)) |
5774 | return n; | 5789 | return n; |
5775 | 5790 | ||
5776 | len += sprintf(p + len, "temperatures:\t"); | 5791 | seq_printf(m, "temperatures:\t"); |
5777 | 5792 | ||
5778 | if (n > 0) { | 5793 | if (n > 0) { |
5779 | for (i = 0; i < (n - 1); i++) | 5794 | for (i = 0; i < (n - 1); i++) |
5780 | len += sprintf(p + len, "%d ", t.temp[i] / 1000); | 5795 | seq_printf(m, "%d ", t.temp[i] / 1000); |
5781 | len += sprintf(p + len, "%d\n", t.temp[i] / 1000); | 5796 | seq_printf(m, "%d\n", t.temp[i] / 1000); |
5782 | } else | 5797 | } else |
5783 | len += sprintf(p + len, "not supported\n"); | 5798 | seq_printf(m, "not supported\n"); |
5784 | 5799 | ||
5785 | return len; | 5800 | return 0; |
5786 | } | 5801 | } |
5787 | 5802 | ||
5788 | static struct ibm_struct thermal_driver_data = { | 5803 | static struct ibm_struct thermal_driver_data = { |
@@ -5797,39 +5812,38 @@ static struct ibm_struct thermal_driver_data = { | |||
5797 | 5812 | ||
5798 | static u8 ecdump_regs[256]; | 5813 | static u8 ecdump_regs[256]; |
5799 | 5814 | ||
5800 | static int ecdump_read(char *p) | 5815 | static int ecdump_read(struct seq_file *m) |
5801 | { | 5816 | { |
5802 | int len = 0; | ||
5803 | int i, j; | 5817 | int i, j; |
5804 | u8 v; | 5818 | u8 v; |
5805 | 5819 | ||
5806 | len += sprintf(p + len, "EC " | 5820 | seq_printf(m, "EC " |
5807 | " +00 +01 +02 +03 +04 +05 +06 +07" | 5821 | " +00 +01 +02 +03 +04 +05 +06 +07" |
5808 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); | 5822 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); |
5809 | for (i = 0; i < 256; i += 16) { | 5823 | for (i = 0; i < 256; i += 16) { |
5810 | len += sprintf(p + len, "EC 0x%02x:", i); | 5824 | seq_printf(m, "EC 0x%02x:", i); |
5811 | for (j = 0; j < 16; j++) { | 5825 | for (j = 0; j < 16; j++) { |
5812 | if (!acpi_ec_read(i + j, &v)) | 5826 | if (!acpi_ec_read(i + j, &v)) |
5813 | break; | 5827 | break; |
5814 | if (v != ecdump_regs[i + j]) | 5828 | if (v != ecdump_regs[i + j]) |
5815 | len += sprintf(p + len, " *%02x", v); | 5829 | seq_printf(m, " *%02x", v); |
5816 | else | 5830 | else |
5817 | len += sprintf(p + len, " %02x", v); | 5831 | seq_printf(m, " %02x", v); |
5818 | ecdump_regs[i + j] = v; | 5832 | ecdump_regs[i + j] = v; |
5819 | } | 5833 | } |
5820 | len += sprintf(p + len, "\n"); | 5834 | seq_putc(m, '\n'); |
5821 | if (j != 16) | 5835 | if (j != 16) |
5822 | break; | 5836 | break; |
5823 | } | 5837 | } |
5824 | 5838 | ||
5825 | /* These are way too dangerous to advertise openly... */ | 5839 | /* These are way too dangerous to advertise openly... */ |
5826 | #if 0 | 5840 | #if 0 |
5827 | len += sprintf(p + len, "commands:\t0x<offset> 0x<value>" | 5841 | seq_printf(m, "commands:\t0x<offset> 0x<value>" |
5828 | " (<offset> is 00-ff, <value> is 00-ff)\n"); | 5842 | " (<offset> is 00-ff, <value> is 00-ff)\n"); |
5829 | len += sprintf(p + len, "commands:\t0x<offset> <value> " | 5843 | seq_printf(m, "commands:\t0x<offset> <value> " |
5830 | " (<offset> is 00-ff, <value> is 0-255)\n"); | 5844 | " (<offset> is 00-ff, <value> is 0-255)\n"); |
5831 | #endif | 5845 | #endif |
5832 | return len; | 5846 | return 0; |
5833 | } | 5847 | } |
5834 | 5848 | ||
5835 | static int ecdump_write(char *buf) | 5849 | static int ecdump_write(char *buf) |
@@ -6092,6 +6106,12 @@ static int brightness_get(struct backlight_device *bd) | |||
6092 | return status & TP_EC_BACKLIGHT_LVLMSK; | 6106 | return status & TP_EC_BACKLIGHT_LVLMSK; |
6093 | } | 6107 | } |
6094 | 6108 | ||
6109 | static void tpacpi_brightness_notify_change(void) | ||
6110 | { | ||
6111 | backlight_force_update(ibm_backlight_device, | ||
6112 | BACKLIGHT_UPDATE_HOTKEY); | ||
6113 | } | ||
6114 | |||
6095 | static struct backlight_ops ibm_backlight_data = { | 6115 | static struct backlight_ops ibm_backlight_data = { |
6096 | .get_brightness = brightness_get, | 6116 | .get_brightness = brightness_get, |
6097 | .update_status = brightness_update_status, | 6117 | .update_status = brightness_update_status, |
@@ -6120,8 +6140,8 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { | |||
6120 | 6140 | ||
6121 | /* Models with Intel Extreme Graphics 2 */ | 6141 | /* Models with Intel Extreme Graphics 2 */ |
6122 | TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), | 6142 | TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), |
6123 | TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | 6143 | TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
6124 | TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | 6144 | TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
6125 | 6145 | ||
6126 | /* Models with Intel GMA900 */ | 6146 | /* Models with Intel GMA900 */ |
6127 | TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ | 6147 | TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ |
@@ -6246,6 +6266,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
6246 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; | 6266 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; |
6247 | backlight_update_status(ibm_backlight_device); | 6267 | backlight_update_status(ibm_backlight_device); |
6248 | 6268 | ||
6269 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, | ||
6270 | "brightness: registering brightness hotkeys " | ||
6271 | "as change notification\n"); | ||
6272 | tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | ||
6273 | | TP_ACPI_HKEY_BRGHTUP_MASK | ||
6274 | | TP_ACPI_HKEY_BRGHTDWN_MASK);; | ||
6249 | return 0; | 6275 | return 0; |
6250 | } | 6276 | } |
6251 | 6277 | ||
@@ -6270,23 +6296,22 @@ static void brightness_exit(void) | |||
6270 | tpacpi_brightness_checkpoint_nvram(); | 6296 | tpacpi_brightness_checkpoint_nvram(); |
6271 | } | 6297 | } |
6272 | 6298 | ||
6273 | static int brightness_read(char *p) | 6299 | static int brightness_read(struct seq_file *m) |
6274 | { | 6300 | { |
6275 | int len = 0; | ||
6276 | int level; | 6301 | int level; |
6277 | 6302 | ||
6278 | level = brightness_get(NULL); | 6303 | level = brightness_get(NULL); |
6279 | if (level < 0) { | 6304 | if (level < 0) { |
6280 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 6305 | seq_printf(m, "level:\t\tunreadable\n"); |
6281 | } else { | 6306 | } else { |
6282 | len += sprintf(p + len, "level:\t\t%d\n", level); | 6307 | seq_printf(m, "level:\t\t%d\n", level); |
6283 | len += sprintf(p + len, "commands:\tup, down\n"); | 6308 | seq_printf(m, "commands:\tup, down\n"); |
6284 | len += sprintf(p + len, "commands:\tlevel <level>" | 6309 | seq_printf(m, "commands:\tlevel <level>" |
6285 | " (<level> is 0-%d)\n", | 6310 | " (<level> is 0-%d)\n", |
6286 | (tp_features.bright_16levels) ? 15 : 7); | 6311 | (tp_features.bright_16levels) ? 15 : 7); |
6287 | } | 6312 | } |
6288 | 6313 | ||
6289 | return len; | 6314 | return 0; |
6290 | } | 6315 | } |
6291 | 6316 | ||
6292 | static int brightness_write(char *buf) | 6317 | static int brightness_write(char *buf) |
@@ -6322,6 +6347,9 @@ static int brightness_write(char *buf) | |||
6322 | * Doing it this way makes the syscall restartable in case of EINTR | 6347 | * Doing it this way makes the syscall restartable in case of EINTR |
6323 | */ | 6348 | */ |
6324 | rc = brightness_set(level); | 6349 | rc = brightness_set(level); |
6350 | if (!rc && ibm_backlight_device) | ||
6351 | backlight_force_update(ibm_backlight_device, | ||
6352 | BACKLIGHT_UPDATE_SYSFS); | ||
6325 | return (rc == -EINTR)? -ERESTARTSYS : rc; | 6353 | return (rc == -EINTR)? -ERESTARTSYS : rc; |
6326 | } | 6354 | } |
6327 | 6355 | ||
@@ -6338,99 +6366,654 @@ static struct ibm_struct brightness_driver_data = { | |||
6338 | * Volume subdriver | 6366 | * Volume subdriver |
6339 | */ | 6367 | */ |
6340 | 6368 | ||
6341 | static int volume_offset = 0x30; | 6369 | /* |
6370 | * IBM ThinkPads have a simple volume controller with MUTE gating. | ||
6371 | * Very early Lenovo ThinkPads follow the IBM ThinkPad spec. | ||
6372 | * | ||
6373 | * Since the *61 series (and probably also the later *60 series), Lenovo | ||
6374 | * ThinkPads only implement the MUTE gate. | ||
6375 | * | ||
6376 | * EC register 0x30 | ||
6377 | * Bit 6: MUTE (1 mutes sound) | ||
6378 | * Bit 3-0: Volume | ||
6379 | * Other bits should be zero as far as we know. | ||
6380 | * | ||
6381 | * This is also stored in CMOS NVRAM, byte 0x60, bit 6 (MUTE), and | ||
6382 | * bits 3-0 (volume). Other bits in NVRAM may have other functions, | ||
6383 | * such as bit 7 which is used to detect repeated presses of MUTE, | ||
6384 | * and we leave them unchanged. | ||
6385 | */ | ||
6386 | |||
6387 | #define TPACPI_ALSA_DRVNAME "ThinkPad EC" | ||
6388 | #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" | ||
6389 | #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME | ||
6390 | |||
6391 | static int alsa_index = SNDRV_DEFAULT_IDX1; | ||
6392 | static char *alsa_id = "ThinkPadEC"; | ||
6393 | static int alsa_enable = SNDRV_DEFAULT_ENABLE1; | ||
6394 | |||
6395 | struct tpacpi_alsa_data { | ||
6396 | struct snd_card *card; | ||
6397 | struct snd_ctl_elem_id *ctl_mute_id; | ||
6398 | struct snd_ctl_elem_id *ctl_vol_id; | ||
6399 | }; | ||
6400 | |||
6401 | static struct snd_card *alsa_card; | ||
6402 | |||
6403 | enum { | ||
6404 | TP_EC_AUDIO = 0x30, | ||
6405 | |||
6406 | /* TP_EC_AUDIO bits */ | ||
6407 | TP_EC_AUDIO_MUTESW = 6, | ||
6408 | |||
6409 | /* TP_EC_AUDIO bitmasks */ | ||
6410 | TP_EC_AUDIO_LVL_MSK = 0x0F, | ||
6411 | TP_EC_AUDIO_MUTESW_MSK = (1 << TP_EC_AUDIO_MUTESW), | ||
6412 | |||
6413 | /* Maximum volume */ | ||
6414 | TP_EC_VOLUME_MAX = 14, | ||
6415 | }; | ||
6416 | |||
6417 | enum tpacpi_volume_access_mode { | ||
6418 | TPACPI_VOL_MODE_AUTO = 0, /* Not implemented yet */ | ||
6419 | TPACPI_VOL_MODE_EC, /* Pure EC control */ | ||
6420 | TPACPI_VOL_MODE_UCMS_STEP, /* UCMS step-based control: N/A */ | ||
6421 | TPACPI_VOL_MODE_ECNVRAM, /* EC control w/ NVRAM store */ | ||
6422 | TPACPI_VOL_MODE_MAX | ||
6423 | }; | ||
6424 | |||
6425 | enum tpacpi_volume_capabilities { | ||
6426 | TPACPI_VOL_CAP_AUTO = 0, /* Use white/blacklist */ | ||
6427 | TPACPI_VOL_CAP_VOLMUTE, /* Output vol and mute */ | ||
6428 | TPACPI_VOL_CAP_MUTEONLY, /* Output mute only */ | ||
6429 | TPACPI_VOL_CAP_MAX | ||
6430 | }; | ||
6431 | |||
6432 | static enum tpacpi_volume_access_mode volume_mode = | ||
6433 | TPACPI_VOL_MODE_MAX; | ||
6434 | |||
6435 | static enum tpacpi_volume_capabilities volume_capabilities; | ||
6436 | static int volume_control_allowed; | ||
6342 | 6437 | ||
6343 | static int volume_read(char *p) | 6438 | /* |
6439 | * Used to syncronize writers to TP_EC_AUDIO and | ||
6440 | * TP_NVRAM_ADDR_MIXER, as we need to do read-modify-write | ||
6441 | */ | ||
6442 | static struct mutex volume_mutex; | ||
6443 | |||
6444 | static void tpacpi_volume_checkpoint_nvram(void) | ||
6344 | { | 6445 | { |
6345 | int len = 0; | 6446 | u8 lec = 0; |
6346 | u8 level; | 6447 | u8 b_nvram; |
6448 | u8 ec_mask; | ||
6449 | |||
6450 | if (volume_mode != TPACPI_VOL_MODE_ECNVRAM) | ||
6451 | return; | ||
6452 | if (!volume_control_allowed) | ||
6453 | return; | ||
6454 | |||
6455 | vdbg_printk(TPACPI_DBG_MIXER, | ||
6456 | "trying to checkpoint mixer state to NVRAM...\n"); | ||
6347 | 6457 | ||
6348 | if (!acpi_ec_read(volume_offset, &level)) { | 6458 | if (tp_features.mixer_no_level_control) |
6349 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 6459 | ec_mask = TP_EC_AUDIO_MUTESW_MSK; |
6460 | else | ||
6461 | ec_mask = TP_EC_AUDIO_MUTESW_MSK | TP_EC_AUDIO_LVL_MSK; | ||
6462 | |||
6463 | if (mutex_lock_killable(&volume_mutex) < 0) | ||
6464 | return; | ||
6465 | |||
6466 | if (unlikely(!acpi_ec_read(TP_EC_AUDIO, &lec))) | ||
6467 | goto unlock; | ||
6468 | lec &= ec_mask; | ||
6469 | b_nvram = nvram_read_byte(TP_NVRAM_ADDR_MIXER); | ||
6470 | |||
6471 | if (lec != (b_nvram & ec_mask)) { | ||
6472 | /* NVRAM needs update */ | ||
6473 | b_nvram &= ~ec_mask; | ||
6474 | b_nvram |= lec; | ||
6475 | nvram_write_byte(b_nvram, TP_NVRAM_ADDR_MIXER); | ||
6476 | dbg_printk(TPACPI_DBG_MIXER, | ||
6477 | "updated NVRAM mixer status to 0x%02x (0x%02x)\n", | ||
6478 | (unsigned int) lec, (unsigned int) b_nvram); | ||
6350 | } else { | 6479 | } else { |
6351 | len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); | 6480 | vdbg_printk(TPACPI_DBG_MIXER, |
6352 | len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); | 6481 | "NVRAM mixer status already is 0x%02x (0x%02x)\n", |
6353 | len += sprintf(p + len, "commands:\tup, down, mute\n"); | 6482 | (unsigned int) lec, (unsigned int) b_nvram); |
6354 | len += sprintf(p + len, "commands:\tlevel <level>" | ||
6355 | " (<level> is 0-15)\n"); | ||
6356 | } | 6483 | } |
6357 | 6484 | ||
6358 | return len; | 6485 | unlock: |
6486 | mutex_unlock(&volume_mutex); | ||
6359 | } | 6487 | } |
6360 | 6488 | ||
6361 | static int volume_write(char *buf) | 6489 | static int volume_get_status_ec(u8 *status) |
6362 | { | 6490 | { |
6363 | int cmos_cmd, inc, i; | 6491 | u8 s; |
6364 | u8 level, mute; | ||
6365 | int new_level, new_mute; | ||
6366 | char *cmd; | ||
6367 | 6492 | ||
6368 | while ((cmd = next_cmd(&buf))) { | 6493 | if (!acpi_ec_read(TP_EC_AUDIO, &s)) |
6369 | if (!acpi_ec_read(volume_offset, &level)) | 6494 | return -EIO; |
6370 | return -EIO; | ||
6371 | new_mute = mute = level & 0x40; | ||
6372 | new_level = level = level & 0xf; | ||
6373 | 6495 | ||
6374 | if (strlencmp(cmd, "up") == 0) { | 6496 | *status = s; |
6375 | if (mute) | ||
6376 | new_mute = 0; | ||
6377 | else | ||
6378 | new_level = level == 15 ? 15 : level + 1; | ||
6379 | } else if (strlencmp(cmd, "down") == 0) { | ||
6380 | if (mute) | ||
6381 | new_mute = 0; | ||
6382 | else | ||
6383 | new_level = level == 0 ? 0 : level - 1; | ||
6384 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | ||
6385 | new_level >= 0 && new_level <= 15) { | ||
6386 | /* new_level set */ | ||
6387 | } else if (strlencmp(cmd, "mute") == 0) { | ||
6388 | new_mute = 0x40; | ||
6389 | } else | ||
6390 | return -EINVAL; | ||
6391 | 6497 | ||
6392 | if (new_level != level) { | 6498 | dbg_printk(TPACPI_DBG_MIXER, "status 0x%02x\n", s); |
6393 | /* mute doesn't change */ | ||
6394 | 6499 | ||
6395 | cmos_cmd = (new_level > level) ? | 6500 | return 0; |
6396 | TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; | 6501 | } |
6397 | inc = new_level > level ? 1 : -1; | ||
6398 | 6502 | ||
6399 | if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || | 6503 | static int volume_get_status(u8 *status) |
6400 | !acpi_ec_write(volume_offset, level))) | 6504 | { |
6401 | return -EIO; | 6505 | return volume_get_status_ec(status); |
6506 | } | ||
6402 | 6507 | ||
6403 | for (i = level; i != new_level; i += inc) | 6508 | static int volume_set_status_ec(const u8 status) |
6404 | if (issue_thinkpad_cmos_command(cmos_cmd) || | 6509 | { |
6405 | !acpi_ec_write(volume_offset, i + inc)) | 6510 | if (!acpi_ec_write(TP_EC_AUDIO, status)) |
6406 | return -EIO; | 6511 | return -EIO; |
6407 | 6512 | ||
6408 | if (mute && | 6513 | dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status); |
6409 | (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || | 6514 | |
6410 | !acpi_ec_write(volume_offset, new_level + mute))) { | 6515 | return 0; |
6411 | return -EIO; | 6516 | } |
6412 | } | 6517 | |
6518 | static int volume_set_status(const u8 status) | ||
6519 | { | ||
6520 | return volume_set_status_ec(status); | ||
6521 | } | ||
6522 | |||
6523 | static int volume_set_mute_ec(const bool mute) | ||
6524 | { | ||
6525 | int rc; | ||
6526 | u8 s, n; | ||
6527 | |||
6528 | if (mutex_lock_killable(&volume_mutex) < 0) | ||
6529 | return -EINTR; | ||
6530 | |||
6531 | rc = volume_get_status_ec(&s); | ||
6532 | if (rc) | ||
6533 | goto unlock; | ||
6534 | |||
6535 | n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : | ||
6536 | s & ~TP_EC_AUDIO_MUTESW_MSK; | ||
6537 | |||
6538 | if (n != s) | ||
6539 | rc = volume_set_status_ec(n); | ||
6540 | |||
6541 | unlock: | ||
6542 | mutex_unlock(&volume_mutex); | ||
6543 | return rc; | ||
6544 | } | ||
6545 | |||
6546 | static int volume_set_mute(const bool mute) | ||
6547 | { | ||
6548 | dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", | ||
6549 | (mute) ? "" : "un"); | ||
6550 | return volume_set_mute_ec(mute); | ||
6551 | } | ||
6552 | |||
6553 | static int volume_set_volume_ec(const u8 vol) | ||
6554 | { | ||
6555 | int rc; | ||
6556 | u8 s, n; | ||
6557 | |||
6558 | if (vol > TP_EC_VOLUME_MAX) | ||
6559 | return -EINVAL; | ||
6560 | |||
6561 | if (mutex_lock_killable(&volume_mutex) < 0) | ||
6562 | return -EINTR; | ||
6563 | |||
6564 | rc = volume_get_status_ec(&s); | ||
6565 | if (rc) | ||
6566 | goto unlock; | ||
6567 | |||
6568 | n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; | ||
6569 | |||
6570 | if (n != s) | ||
6571 | rc = volume_set_status_ec(n); | ||
6572 | |||
6573 | unlock: | ||
6574 | mutex_unlock(&volume_mutex); | ||
6575 | return rc; | ||
6576 | } | ||
6577 | |||
6578 | static int volume_set_volume(const u8 vol) | ||
6579 | { | ||
6580 | dbg_printk(TPACPI_DBG_MIXER, | ||
6581 | "trying to set volume level to %hu\n", vol); | ||
6582 | return volume_set_volume_ec(vol); | ||
6583 | } | ||
6584 | |||
6585 | static void volume_alsa_notify_change(void) | ||
6586 | { | ||
6587 | struct tpacpi_alsa_data *d; | ||
6588 | |||
6589 | if (alsa_card && alsa_card->private_data) { | ||
6590 | d = alsa_card->private_data; | ||
6591 | if (d->ctl_mute_id) | ||
6592 | snd_ctl_notify(alsa_card, | ||
6593 | SNDRV_CTL_EVENT_MASK_VALUE, | ||
6594 | d->ctl_mute_id); | ||
6595 | if (d->ctl_vol_id) | ||
6596 | snd_ctl_notify(alsa_card, | ||
6597 | SNDRV_CTL_EVENT_MASK_VALUE, | ||
6598 | d->ctl_vol_id); | ||
6599 | } | ||
6600 | } | ||
6601 | |||
6602 | static int volume_alsa_vol_info(struct snd_kcontrol *kcontrol, | ||
6603 | struct snd_ctl_elem_info *uinfo) | ||
6604 | { | ||
6605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
6606 | uinfo->count = 1; | ||
6607 | uinfo->value.integer.min = 0; | ||
6608 | uinfo->value.integer.max = TP_EC_VOLUME_MAX; | ||
6609 | return 0; | ||
6610 | } | ||
6611 | |||
6612 | static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, | ||
6613 | struct snd_ctl_elem_value *ucontrol) | ||
6614 | { | ||
6615 | u8 s; | ||
6616 | int rc; | ||
6617 | |||
6618 | rc = volume_get_status(&s); | ||
6619 | if (rc < 0) | ||
6620 | return rc; | ||
6621 | |||
6622 | ucontrol->value.integer.value[0] = s & TP_EC_AUDIO_LVL_MSK; | ||
6623 | return 0; | ||
6624 | } | ||
6625 | |||
6626 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, | ||
6627 | struct snd_ctl_elem_value *ucontrol) | ||
6628 | { | ||
6629 | return volume_set_volume(ucontrol->value.integer.value[0]); | ||
6630 | } | ||
6631 | |||
6632 | #define volume_alsa_mute_info snd_ctl_boolean_mono_info | ||
6633 | |||
6634 | static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, | ||
6635 | struct snd_ctl_elem_value *ucontrol) | ||
6636 | { | ||
6637 | u8 s; | ||
6638 | int rc; | ||
6639 | |||
6640 | rc = volume_get_status(&s); | ||
6641 | if (rc < 0) | ||
6642 | return rc; | ||
6643 | |||
6644 | ucontrol->value.integer.value[0] = | ||
6645 | (s & TP_EC_AUDIO_MUTESW_MSK) ? 0 : 1; | ||
6646 | return 0; | ||
6647 | } | ||
6648 | |||
6649 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, | ||
6650 | struct snd_ctl_elem_value *ucontrol) | ||
6651 | { | ||
6652 | return volume_set_mute(!ucontrol->value.integer.value[0]); | ||
6653 | } | ||
6654 | |||
6655 | static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { | ||
6656 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6657 | .name = "Console Playback Volume", | ||
6658 | .index = 0, | ||
6659 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
6660 | .info = volume_alsa_vol_info, | ||
6661 | .get = volume_alsa_vol_get, | ||
6662 | }; | ||
6663 | |||
6664 | static struct snd_kcontrol_new volume_alsa_control_mute __devinitdata = { | ||
6665 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6666 | .name = "Console Playback Switch", | ||
6667 | .index = 0, | ||
6668 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
6669 | .info = volume_alsa_mute_info, | ||
6670 | .get = volume_alsa_mute_get, | ||
6671 | }; | ||
6672 | |||
6673 | static void volume_suspend(pm_message_t state) | ||
6674 | { | ||
6675 | tpacpi_volume_checkpoint_nvram(); | ||
6676 | } | ||
6677 | |||
6678 | static void volume_resume(void) | ||
6679 | { | ||
6680 | volume_alsa_notify_change(); | ||
6681 | } | ||
6682 | |||
6683 | static void volume_shutdown(void) | ||
6684 | { | ||
6685 | tpacpi_volume_checkpoint_nvram(); | ||
6686 | } | ||
6687 | |||
6688 | static void volume_exit(void) | ||
6689 | { | ||
6690 | if (alsa_card) { | ||
6691 | snd_card_free(alsa_card); | ||
6692 | alsa_card = NULL; | ||
6693 | } | ||
6694 | |||
6695 | tpacpi_volume_checkpoint_nvram(); | ||
6696 | } | ||
6697 | |||
6698 | static int __init volume_create_alsa_mixer(void) | ||
6699 | { | ||
6700 | struct snd_card *card; | ||
6701 | struct tpacpi_alsa_data *data; | ||
6702 | struct snd_kcontrol *ctl_vol; | ||
6703 | struct snd_kcontrol *ctl_mute; | ||
6704 | int rc; | ||
6705 | |||
6706 | rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE, | ||
6707 | sizeof(struct tpacpi_alsa_data), &card); | ||
6708 | if (rc < 0) | ||
6709 | return rc; | ||
6710 | if (!card) | ||
6711 | return -ENOMEM; | ||
6712 | |||
6713 | BUG_ON(!card->private_data); | ||
6714 | data = card->private_data; | ||
6715 | data->card = card; | ||
6716 | |||
6717 | strlcpy(card->driver, TPACPI_ALSA_DRVNAME, | ||
6718 | sizeof(card->driver)); | ||
6719 | strlcpy(card->shortname, TPACPI_ALSA_SHRTNAME, | ||
6720 | sizeof(card->shortname)); | ||
6721 | snprintf(card->mixername, sizeof(card->mixername), "ThinkPad EC %s", | ||
6722 | (thinkpad_id.ec_version_str) ? | ||
6723 | thinkpad_id.ec_version_str : "(unknown)"); | ||
6724 | snprintf(card->longname, sizeof(card->longname), | ||
6725 | "%s at EC reg 0x%02x, fw %s", card->shortname, TP_EC_AUDIO, | ||
6726 | (thinkpad_id.ec_version_str) ? | ||
6727 | thinkpad_id.ec_version_str : "unknown"); | ||
6728 | |||
6729 | if (volume_control_allowed) { | ||
6730 | volume_alsa_control_vol.put = volume_alsa_vol_put; | ||
6731 | volume_alsa_control_vol.access = | ||
6732 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
6733 | |||
6734 | volume_alsa_control_mute.put = volume_alsa_mute_put; | ||
6735 | volume_alsa_control_mute.access = | ||
6736 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
6737 | } | ||
6738 | |||
6739 | if (!tp_features.mixer_no_level_control) { | ||
6740 | ctl_vol = snd_ctl_new1(&volume_alsa_control_vol, NULL); | ||
6741 | rc = snd_ctl_add(card, ctl_vol); | ||
6742 | if (rc < 0) { | ||
6743 | printk(TPACPI_ERR | ||
6744 | "Failed to create ALSA volume control\n"); | ||
6745 | goto err_out; | ||
6413 | } | 6746 | } |
6747 | data->ctl_vol_id = &ctl_vol->id; | ||
6748 | } | ||
6414 | 6749 | ||
6415 | if (new_mute != mute) { | 6750 | ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL); |
6416 | /* level doesn't change */ | 6751 | rc = snd_ctl_add(card, ctl_mute); |
6752 | if (rc < 0) { | ||
6753 | printk(TPACPI_ERR "Failed to create ALSA mute control\n"); | ||
6754 | goto err_out; | ||
6755 | } | ||
6756 | data->ctl_mute_id = &ctl_mute->id; | ||
6417 | 6757 | ||
6418 | cmos_cmd = (new_mute) ? | 6758 | snd_card_set_dev(card, &tpacpi_pdev->dev); |
6419 | TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; | 6759 | rc = snd_card_register(card); |
6420 | 6760 | ||
6421 | if (issue_thinkpad_cmos_command(cmos_cmd) || | 6761 | err_out: |
6422 | !acpi_ec_write(volume_offset, level + new_mute)) | 6762 | if (rc < 0) { |
6423 | return -EIO; | 6763 | snd_card_free(card); |
6764 | card = NULL; | ||
6765 | } | ||
6766 | |||
6767 | alsa_card = card; | ||
6768 | return rc; | ||
6769 | } | ||
6770 | |||
6771 | #define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */ | ||
6772 | #define TPACPI_VOL_Q_LEVEL 0x0002 /* Volume control available */ | ||
6773 | |||
6774 | static const struct tpacpi_quirk volume_quirk_table[] __initconst = { | ||
6775 | /* Whitelist volume level on all IBM by default */ | ||
6776 | { .vendor = PCI_VENDOR_ID_IBM, | ||
6777 | .bios = TPACPI_MATCH_ANY, | ||
6778 | .ec = TPACPI_MATCH_ANY, | ||
6779 | .quirks = TPACPI_VOL_Q_LEVEL }, | ||
6780 | |||
6781 | /* Lenovo models with volume control (needs confirmation) */ | ||
6782 | TPACPI_QEC_LNV('7', 'C', TPACPI_VOL_Q_LEVEL), /* R60/i */ | ||
6783 | TPACPI_QEC_LNV('7', 'E', TPACPI_VOL_Q_LEVEL), /* R60e/i */ | ||
6784 | TPACPI_QEC_LNV('7', '9', TPACPI_VOL_Q_LEVEL), /* T60/p */ | ||
6785 | TPACPI_QEC_LNV('7', 'B', TPACPI_VOL_Q_LEVEL), /* X60/s */ | ||
6786 | TPACPI_QEC_LNV('7', 'J', TPACPI_VOL_Q_LEVEL), /* X60t */ | ||
6787 | TPACPI_QEC_LNV('7', '7', TPACPI_VOL_Q_LEVEL), /* Z60 */ | ||
6788 | TPACPI_QEC_LNV('7', 'F', TPACPI_VOL_Q_LEVEL), /* Z61 */ | ||
6789 | |||
6790 | /* Whitelist mute-only on all Lenovo by default */ | ||
6791 | { .vendor = PCI_VENDOR_ID_LENOVO, | ||
6792 | .bios = TPACPI_MATCH_ANY, | ||
6793 | .ec = TPACPI_MATCH_ANY, | ||
6794 | .quirks = TPACPI_VOL_Q_MUTEONLY } | ||
6795 | }; | ||
6796 | |||
6797 | static int __init volume_init(struct ibm_init_struct *iibm) | ||
6798 | { | ||
6799 | unsigned long quirks; | ||
6800 | int rc; | ||
6801 | |||
6802 | vdbg_printk(TPACPI_DBG_INIT, "initializing volume subdriver\n"); | ||
6803 | |||
6804 | mutex_init(&volume_mutex); | ||
6805 | |||
6806 | /* | ||
6807 | * Check for module parameter bogosity, note that we | ||
6808 | * init volume_mode to TPACPI_VOL_MODE_MAX in order to be | ||
6809 | * able to detect "unspecified" | ||
6810 | */ | ||
6811 | if (volume_mode > TPACPI_VOL_MODE_MAX) | ||
6812 | return -EINVAL; | ||
6813 | |||
6814 | if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) { | ||
6815 | printk(TPACPI_ERR | ||
6816 | "UCMS step volume mode not implemented, " | ||
6817 | "please contact %s\n", TPACPI_MAIL); | ||
6818 | return 1; | ||
6819 | } | ||
6820 | |||
6821 | if (volume_capabilities >= TPACPI_VOL_CAP_MAX) | ||
6822 | return -EINVAL; | ||
6823 | |||
6824 | /* | ||
6825 | * The ALSA mixer is our primary interface. | ||
6826 | * When disabled, don't install the subdriver at all | ||
6827 | */ | ||
6828 | if (!alsa_enable) { | ||
6829 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
6830 | "ALSA mixer disabled by parameter, " | ||
6831 | "not loading volume subdriver...\n"); | ||
6832 | return 1; | ||
6833 | } | ||
6834 | |||
6835 | quirks = tpacpi_check_quirks(volume_quirk_table, | ||
6836 | ARRAY_SIZE(volume_quirk_table)); | ||
6837 | |||
6838 | switch (volume_capabilities) { | ||
6839 | case TPACPI_VOL_CAP_AUTO: | ||
6840 | if (quirks & TPACPI_VOL_Q_MUTEONLY) | ||
6841 | tp_features.mixer_no_level_control = 1; | ||
6842 | else if (quirks & TPACPI_VOL_Q_LEVEL) | ||
6843 | tp_features.mixer_no_level_control = 0; | ||
6844 | else | ||
6845 | return 1; /* no mixer */ | ||
6846 | break; | ||
6847 | case TPACPI_VOL_CAP_VOLMUTE: | ||
6848 | tp_features.mixer_no_level_control = 0; | ||
6849 | break; | ||
6850 | case TPACPI_VOL_CAP_MUTEONLY: | ||
6851 | tp_features.mixer_no_level_control = 1; | ||
6852 | break; | ||
6853 | default: | ||
6854 | return 1; | ||
6855 | } | ||
6856 | |||
6857 | if (volume_capabilities != TPACPI_VOL_CAP_AUTO) | ||
6858 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
6859 | "using user-supplied volume_capabilities=%d\n", | ||
6860 | volume_capabilities); | ||
6861 | |||
6862 | if (volume_mode == TPACPI_VOL_MODE_AUTO || | ||
6863 | volume_mode == TPACPI_VOL_MODE_MAX) { | ||
6864 | volume_mode = TPACPI_VOL_MODE_ECNVRAM; | ||
6865 | |||
6866 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
6867 | "driver auto-selected volume_mode=%d\n", | ||
6868 | volume_mode); | ||
6869 | } else { | ||
6870 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
6871 | "using user-supplied volume_mode=%d\n", | ||
6872 | volume_mode); | ||
6873 | } | ||
6874 | |||
6875 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
6876 | "mute is supported, volume control is %s\n", | ||
6877 | str_supported(!tp_features.mixer_no_level_control)); | ||
6878 | |||
6879 | rc = volume_create_alsa_mixer(); | ||
6880 | if (rc) { | ||
6881 | printk(TPACPI_ERR | ||
6882 | "Could not create the ALSA mixer interface\n"); | ||
6883 | return rc; | ||
6884 | } | ||
6885 | |||
6886 | printk(TPACPI_INFO | ||
6887 | "Console audio control enabled, mode: %s\n", | ||
6888 | (volume_control_allowed) ? | ||
6889 | "override (read/write)" : | ||
6890 | "monitor (read only)"); | ||
6891 | |||
6892 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
6893 | "registering volume hotkeys as change notification\n"); | ||
6894 | tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | ||
6895 | | TP_ACPI_HKEY_VOLUP_MASK | ||
6896 | | TP_ACPI_HKEY_VOLDWN_MASK | ||
6897 | | TP_ACPI_HKEY_MUTE_MASK); | ||
6898 | |||
6899 | return 0; | ||
6900 | } | ||
6901 | |||
6902 | static int volume_read(struct seq_file *m) | ||
6903 | { | ||
6904 | u8 status; | ||
6905 | |||
6906 | if (volume_get_status(&status) < 0) { | ||
6907 | seq_printf(m, "level:\t\tunreadable\n"); | ||
6908 | } else { | ||
6909 | if (tp_features.mixer_no_level_control) | ||
6910 | seq_printf(m, "level:\t\tunsupported\n"); | ||
6911 | else | ||
6912 | seq_printf(m, "level:\t\t%d\n", | ||
6913 | status & TP_EC_AUDIO_LVL_MSK); | ||
6914 | |||
6915 | seq_printf(m, "mute:\t\t%s\n", | ||
6916 | onoff(status, TP_EC_AUDIO_MUTESW)); | ||
6917 | |||
6918 | if (volume_control_allowed) { | ||
6919 | seq_printf(m, "commands:\tunmute, mute\n"); | ||
6920 | if (!tp_features.mixer_no_level_control) { | ||
6921 | seq_printf(m, | ||
6922 | "commands:\tup, down\n"); | ||
6923 | seq_printf(m, | ||
6924 | "commands:\tlevel <level>" | ||
6925 | " (<level> is 0-%d)\n", | ||
6926 | TP_EC_VOLUME_MAX); | ||
6927 | } | ||
6424 | } | 6928 | } |
6425 | } | 6929 | } |
6426 | 6930 | ||
6427 | return 0; | 6931 | return 0; |
6428 | } | 6932 | } |
6429 | 6933 | ||
6934 | static int volume_write(char *buf) | ||
6935 | { | ||
6936 | u8 s; | ||
6937 | u8 new_level, new_mute; | ||
6938 | int l; | ||
6939 | char *cmd; | ||
6940 | int rc; | ||
6941 | |||
6942 | /* | ||
6943 | * We do allow volume control at driver startup, so that the | ||
6944 | * user can set initial state through the volume=... parameter hack. | ||
6945 | */ | ||
6946 | if (!volume_control_allowed && tpacpi_lifecycle != TPACPI_LIFE_INIT) { | ||
6947 | if (unlikely(!tp_warned.volume_ctrl_forbidden)) { | ||
6948 | tp_warned.volume_ctrl_forbidden = 1; | ||
6949 | printk(TPACPI_NOTICE | ||
6950 | "Console audio control in monitor mode, " | ||
6951 | "changes are not allowed.\n"); | ||
6952 | printk(TPACPI_NOTICE | ||
6953 | "Use the volume_control=1 module parameter " | ||
6954 | "to enable volume control\n"); | ||
6955 | } | ||
6956 | return -EPERM; | ||
6957 | } | ||
6958 | |||
6959 | rc = volume_get_status(&s); | ||
6960 | if (rc < 0) | ||
6961 | return rc; | ||
6962 | |||
6963 | new_level = s & TP_EC_AUDIO_LVL_MSK; | ||
6964 | new_mute = s & TP_EC_AUDIO_MUTESW_MSK; | ||
6965 | |||
6966 | while ((cmd = next_cmd(&buf))) { | ||
6967 | if (!tp_features.mixer_no_level_control) { | ||
6968 | if (strlencmp(cmd, "up") == 0) { | ||
6969 | if (new_mute) | ||
6970 | new_mute = 0; | ||
6971 | else if (new_level < TP_EC_VOLUME_MAX) | ||
6972 | new_level++; | ||
6973 | continue; | ||
6974 | } else if (strlencmp(cmd, "down") == 0) { | ||
6975 | if (new_mute) | ||
6976 | new_mute = 0; | ||
6977 | else if (new_level > 0) | ||
6978 | new_level--; | ||
6979 | continue; | ||
6980 | } else if (sscanf(cmd, "level %u", &l) == 1 && | ||
6981 | l >= 0 && l <= TP_EC_VOLUME_MAX) { | ||
6982 | new_level = l; | ||
6983 | continue; | ||
6984 | } | ||
6985 | } | ||
6986 | if (strlencmp(cmd, "mute") == 0) | ||
6987 | new_mute = TP_EC_AUDIO_MUTESW_MSK; | ||
6988 | else if (strlencmp(cmd, "unmute") == 0) | ||
6989 | new_mute = 0; | ||
6990 | else | ||
6991 | return -EINVAL; | ||
6992 | } | ||
6993 | |||
6994 | if (tp_features.mixer_no_level_control) { | ||
6995 | tpacpi_disclose_usertask("procfs volume", "%smute\n", | ||
6996 | new_mute ? "" : "un"); | ||
6997 | rc = volume_set_mute(!!new_mute); | ||
6998 | } else { | ||
6999 | tpacpi_disclose_usertask("procfs volume", | ||
7000 | "%smute and set level to %d\n", | ||
7001 | new_mute ? "" : "un", new_level); | ||
7002 | rc = volume_set_status(new_mute | new_level); | ||
7003 | } | ||
7004 | volume_alsa_notify_change(); | ||
7005 | |||
7006 | return (rc == -EINTR) ? -ERESTARTSYS : rc; | ||
7007 | } | ||
7008 | |||
6430 | static struct ibm_struct volume_driver_data = { | 7009 | static struct ibm_struct volume_driver_data = { |
6431 | .name = "volume", | 7010 | .name = "volume", |
6432 | .read = volume_read, | 7011 | .read = volume_read, |
6433 | .write = volume_write, | 7012 | .write = volume_write, |
7013 | .exit = volume_exit, | ||
7014 | .suspend = volume_suspend, | ||
7015 | .resume = volume_resume, | ||
7016 | .shutdown = volume_shutdown, | ||
6434 | }; | 7017 | }; |
6435 | 7018 | ||
6436 | /************************************************************************* | 7019 | /************************************************************************* |
@@ -7507,9 +8090,8 @@ static void fan_resume(void) | |||
7507 | } | 8090 | } |
7508 | } | 8091 | } |
7509 | 8092 | ||
7510 | static int fan_read(char *p) | 8093 | static int fan_read(struct seq_file *m) |
7511 | { | 8094 | { |
7512 | int len = 0; | ||
7513 | int rc; | 8095 | int rc; |
7514 | u8 status; | 8096 | u8 status; |
7515 | unsigned int speed = 0; | 8097 | unsigned int speed = 0; |
@@ -7521,7 +8103,7 @@ static int fan_read(char *p) | |||
7521 | if (rc < 0) | 8103 | if (rc < 0) |
7522 | return rc; | 8104 | return rc; |
7523 | 8105 | ||
7524 | len += sprintf(p + len, "status:\t\t%s\n" | 8106 | seq_printf(m, "status:\t\t%s\n" |
7525 | "level:\t\t%d\n", | 8107 | "level:\t\t%d\n", |
7526 | (status != 0) ? "enabled" : "disabled", status); | 8108 | (status != 0) ? "enabled" : "disabled", status); |
7527 | break; | 8109 | break; |
@@ -7532,54 +8114,54 @@ static int fan_read(char *p) | |||
7532 | if (rc < 0) | 8114 | if (rc < 0) |
7533 | return rc; | 8115 | return rc; |
7534 | 8116 | ||
7535 | len += sprintf(p + len, "status:\t\t%s\n", | 8117 | seq_printf(m, "status:\t\t%s\n", |
7536 | (status != 0) ? "enabled" : "disabled"); | 8118 | (status != 0) ? "enabled" : "disabled"); |
7537 | 8119 | ||
7538 | rc = fan_get_speed(&speed); | 8120 | rc = fan_get_speed(&speed); |
7539 | if (rc < 0) | 8121 | if (rc < 0) |
7540 | return rc; | 8122 | return rc; |
7541 | 8123 | ||
7542 | len += sprintf(p + len, "speed:\t\t%d\n", speed); | 8124 | seq_printf(m, "speed:\t\t%d\n", speed); |
7543 | 8125 | ||
7544 | if (status & TP_EC_FAN_FULLSPEED) | 8126 | if (status & TP_EC_FAN_FULLSPEED) |
7545 | /* Disengaged mode takes precedence */ | 8127 | /* Disengaged mode takes precedence */ |
7546 | len += sprintf(p + len, "level:\t\tdisengaged\n"); | 8128 | seq_printf(m, "level:\t\tdisengaged\n"); |
7547 | else if (status & TP_EC_FAN_AUTO) | 8129 | else if (status & TP_EC_FAN_AUTO) |
7548 | len += sprintf(p + len, "level:\t\tauto\n"); | 8130 | seq_printf(m, "level:\t\tauto\n"); |
7549 | else | 8131 | else |
7550 | len += sprintf(p + len, "level:\t\t%d\n", status); | 8132 | seq_printf(m, "level:\t\t%d\n", status); |
7551 | break; | 8133 | break; |
7552 | 8134 | ||
7553 | case TPACPI_FAN_NONE: | 8135 | case TPACPI_FAN_NONE: |
7554 | default: | 8136 | default: |
7555 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 8137 | seq_printf(m, "status:\t\tnot supported\n"); |
7556 | } | 8138 | } |
7557 | 8139 | ||
7558 | if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { | 8140 | if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { |
7559 | len += sprintf(p + len, "commands:\tlevel <level>"); | 8141 | seq_printf(m, "commands:\tlevel <level>"); |
7560 | 8142 | ||
7561 | switch (fan_control_access_mode) { | 8143 | switch (fan_control_access_mode) { |
7562 | case TPACPI_FAN_WR_ACPI_SFAN: | 8144 | case TPACPI_FAN_WR_ACPI_SFAN: |
7563 | len += sprintf(p + len, " (<level> is 0-7)\n"); | 8145 | seq_printf(m, " (<level> is 0-7)\n"); |
7564 | break; | 8146 | break; |
7565 | 8147 | ||
7566 | default: | 8148 | default: |
7567 | len += sprintf(p + len, " (<level> is 0-7, " | 8149 | seq_printf(m, " (<level> is 0-7, " |
7568 | "auto, disengaged, full-speed)\n"); | 8150 | "auto, disengaged, full-speed)\n"); |
7569 | break; | 8151 | break; |
7570 | } | 8152 | } |
7571 | } | 8153 | } |
7572 | 8154 | ||
7573 | if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) | 8155 | if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) |
7574 | len += sprintf(p + len, "commands:\tenable, disable\n" | 8156 | seq_printf(m, "commands:\tenable, disable\n" |
7575 | "commands:\twatchdog <timeout> (<timeout> " | 8157 | "commands:\twatchdog <timeout> (<timeout> " |
7576 | "is 0 (off), 1-120 (seconds))\n"); | 8158 | "is 0 (off), 1-120 (seconds))\n"); |
7577 | 8159 | ||
7578 | if (fan_control_commands & TPACPI_FAN_CMD_SPEED) | 8160 | if (fan_control_commands & TPACPI_FAN_CMD_SPEED) |
7579 | len += sprintf(p + len, "commands:\tspeed <speed>" | 8161 | seq_printf(m, "commands:\tspeed <speed>" |
7580 | " (<speed> is 0-65535)\n"); | 8162 | " (<speed> is 0-65535)\n"); |
7581 | 8163 | ||
7582 | return len; | 8164 | return 0; |
7583 | } | 8165 | } |
7584 | 8166 | ||
7585 | static int fan_write_cmd_level(const char *cmd, int *rc) | 8167 | static int fan_write_cmd_level(const char *cmd, int *rc) |
@@ -7721,10 +8303,23 @@ static struct ibm_struct fan_driver_data = { | |||
7721 | */ | 8303 | */ |
7722 | static void tpacpi_driver_event(const unsigned int hkey_event) | 8304 | static void tpacpi_driver_event(const unsigned int hkey_event) |
7723 | { | 8305 | { |
8306 | if (ibm_backlight_device) { | ||
8307 | switch (hkey_event) { | ||
8308 | case TP_HKEY_EV_BRGHT_UP: | ||
8309 | case TP_HKEY_EV_BRGHT_DOWN: | ||
8310 | tpacpi_brightness_notify_change(); | ||
8311 | } | ||
8312 | } | ||
8313 | if (alsa_card) { | ||
8314 | switch (hkey_event) { | ||
8315 | case TP_HKEY_EV_VOL_UP: | ||
8316 | case TP_HKEY_EV_VOL_DOWN: | ||
8317 | case TP_HKEY_EV_VOL_MUTE: | ||
8318 | volume_alsa_notify_change(); | ||
8319 | } | ||
8320 | } | ||
7724 | } | 8321 | } |
7725 | 8322 | ||
7726 | |||
7727 | |||
7728 | static void hotkey_driver_event(const unsigned int scancode) | 8323 | static void hotkey_driver_event(const unsigned int scancode) |
7729 | { | 8324 | { |
7730 | tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); | 8325 | tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); |
@@ -7853,19 +8448,19 @@ static int __init ibm_init(struct ibm_init_struct *iibm) | |||
7853 | "%s installed\n", ibm->name); | 8448 | "%s installed\n", ibm->name); |
7854 | 8449 | ||
7855 | if (ibm->read) { | 8450 | if (ibm->read) { |
7856 | entry = create_proc_entry(ibm->name, | 8451 | mode_t mode; |
7857 | S_IFREG | S_IRUGO | S_IWUSR, | 8452 | |
7858 | proc_dir); | 8453 | mode = S_IRUGO; |
8454 | if (ibm->write) | ||
8455 | mode |= S_IWUSR; | ||
8456 | entry = proc_create_data(ibm->name, mode, proc_dir, | ||
8457 | &dispatch_proc_fops, ibm); | ||
7859 | if (!entry) { | 8458 | if (!entry) { |
7860 | printk(TPACPI_ERR "unable to create proc entry %s\n", | 8459 | printk(TPACPI_ERR "unable to create proc entry %s\n", |
7861 | ibm->name); | 8460 | ibm->name); |
7862 | ret = -ENODEV; | 8461 | ret = -ENODEV; |
7863 | goto err_out; | 8462 | goto err_out; |
7864 | } | 8463 | } |
7865 | entry->data = ibm; | ||
7866 | entry->read_proc = &dispatch_procfs_read; | ||
7867 | if (ibm->write) | ||
7868 | entry->write_proc = &dispatch_procfs_write; | ||
7869 | ibm->flags.proc_created = 1; | 8464 | ibm->flags.proc_created = 1; |
7870 | } | 8465 | } |
7871 | 8466 | ||
@@ -8077,6 +8672,7 @@ static struct ibm_init_struct ibms_init[] __initdata = { | |||
8077 | .data = &brightness_driver_data, | 8672 | .data = &brightness_driver_data, |
8078 | }, | 8673 | }, |
8079 | { | 8674 | { |
8675 | .init = volume_init, | ||
8080 | .data = &volume_driver_data, | 8676 | .data = &volume_driver_data, |
8081 | }, | 8677 | }, |
8082 | { | 8678 | { |
@@ -8112,36 +8708,59 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) | |||
8112 | return -EINVAL; | 8708 | return -EINVAL; |
8113 | } | 8709 | } |
8114 | 8710 | ||
8115 | module_param(experimental, int, 0); | 8711 | module_param(experimental, int, 0444); |
8116 | MODULE_PARM_DESC(experimental, | 8712 | MODULE_PARM_DESC(experimental, |
8117 | "Enables experimental features when non-zero"); | 8713 | "Enables experimental features when non-zero"); |
8118 | 8714 | ||
8119 | module_param_named(debug, dbg_level, uint, 0); | 8715 | module_param_named(debug, dbg_level, uint, 0); |
8120 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); | 8716 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); |
8121 | 8717 | ||
8122 | module_param(force_load, bool, 0); | 8718 | module_param(force_load, bool, 0444); |
8123 | MODULE_PARM_DESC(force_load, | 8719 | MODULE_PARM_DESC(force_load, |
8124 | "Attempts to load the driver even on a " | 8720 | "Attempts to load the driver even on a " |
8125 | "mis-identified ThinkPad when true"); | 8721 | "mis-identified ThinkPad when true"); |
8126 | 8722 | ||
8127 | module_param_named(fan_control, fan_control_allowed, bool, 0); | 8723 | module_param_named(fan_control, fan_control_allowed, bool, 0444); |
8128 | MODULE_PARM_DESC(fan_control, | 8724 | MODULE_PARM_DESC(fan_control, |
8129 | "Enables setting fan parameters features when true"); | 8725 | "Enables setting fan parameters features when true"); |
8130 | 8726 | ||
8131 | module_param_named(brightness_mode, brightness_mode, uint, 0); | 8727 | module_param_named(brightness_mode, brightness_mode, uint, 0444); |
8132 | MODULE_PARM_DESC(brightness_mode, | 8728 | MODULE_PARM_DESC(brightness_mode, |
8133 | "Selects brightness control strategy: " | 8729 | "Selects brightness control strategy: " |
8134 | "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); | 8730 | "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); |
8135 | 8731 | ||
8136 | module_param(brightness_enable, uint, 0); | 8732 | module_param(brightness_enable, uint, 0444); |
8137 | MODULE_PARM_DESC(brightness_enable, | 8733 | MODULE_PARM_DESC(brightness_enable, |
8138 | "Enables backlight control when 1, disables when 0"); | 8734 | "Enables backlight control when 1, disables when 0"); |
8139 | 8735 | ||
8140 | module_param(hotkey_report_mode, uint, 0); | 8736 | module_param(hotkey_report_mode, uint, 0444); |
8141 | MODULE_PARM_DESC(hotkey_report_mode, | 8737 | MODULE_PARM_DESC(hotkey_report_mode, |
8142 | "used for backwards compatibility with userspace, " | 8738 | "used for backwards compatibility with userspace, " |
8143 | "see documentation"); | 8739 | "see documentation"); |
8144 | 8740 | ||
8741 | module_param_named(volume_mode, volume_mode, uint, 0444); | ||
8742 | MODULE_PARM_DESC(volume_mode, | ||
8743 | "Selects volume control strategy: " | ||
8744 | "0=auto, 1=EC, 2=N/A, 3=EC+NVRAM"); | ||
8745 | |||
8746 | module_param_named(volume_capabilities, volume_capabilities, uint, 0444); | ||
8747 | MODULE_PARM_DESC(volume_capabilities, | ||
8748 | "Selects the mixer capabilites: " | ||
8749 | "0=auto, 1=volume and mute, 2=mute only"); | ||
8750 | |||
8751 | module_param_named(volume_control, volume_control_allowed, bool, 0444); | ||
8752 | MODULE_PARM_DESC(volume_control, | ||
8753 | "Enables software override for the console audio " | ||
8754 | "control when true"); | ||
8755 | |||
8756 | /* ALSA module API parameters */ | ||
8757 | module_param_named(index, alsa_index, int, 0444); | ||
8758 | MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer"); | ||
8759 | module_param_named(id, alsa_id, charp, 0444); | ||
8760 | MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer"); | ||
8761 | module_param_named(enable, alsa_enable, bool, 0444); | ||
8762 | MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer"); | ||
8763 | |||
8145 | #define TPACPI_PARAM(feature) \ | 8764 | #define TPACPI_PARAM(feature) \ |
8146 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ | 8765 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ |
8147 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ | 8766 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ |
@@ -8160,25 +8779,25 @@ TPACPI_PARAM(volume); | |||
8160 | TPACPI_PARAM(fan); | 8779 | TPACPI_PARAM(fan); |
8161 | 8780 | ||
8162 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 8781 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
8163 | module_param(dbg_wlswemul, uint, 0); | 8782 | module_param(dbg_wlswemul, uint, 0444); |
8164 | MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation"); | 8783 | MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation"); |
8165 | module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0); | 8784 | module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0); |
8166 | MODULE_PARM_DESC(wlsw_state, | 8785 | MODULE_PARM_DESC(wlsw_state, |
8167 | "Initial state of the emulated WLSW switch"); | 8786 | "Initial state of the emulated WLSW switch"); |
8168 | 8787 | ||
8169 | module_param(dbg_bluetoothemul, uint, 0); | 8788 | module_param(dbg_bluetoothemul, uint, 0444); |
8170 | MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation"); | 8789 | MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation"); |
8171 | module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0); | 8790 | module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0); |
8172 | MODULE_PARM_DESC(bluetooth_state, | 8791 | MODULE_PARM_DESC(bluetooth_state, |
8173 | "Initial state of the emulated bluetooth switch"); | 8792 | "Initial state of the emulated bluetooth switch"); |
8174 | 8793 | ||
8175 | module_param(dbg_wwanemul, uint, 0); | 8794 | module_param(dbg_wwanemul, uint, 0444); |
8176 | MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation"); | 8795 | MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation"); |
8177 | module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); | 8796 | module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); |
8178 | MODULE_PARM_DESC(wwan_state, | 8797 | MODULE_PARM_DESC(wwan_state, |
8179 | "Initial state of the emulated WWAN switch"); | 8798 | "Initial state of the emulated WWAN switch"); |
8180 | 8799 | ||
8181 | module_param(dbg_uwbemul, uint, 0); | 8800 | module_param(dbg_uwbemul, uint, 0444); |
8182 | MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation"); | 8801 | MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation"); |
8183 | module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0); | 8802 | module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0); |
8184 | MODULE_PARM_DESC(uwb_state, | 8803 | MODULE_PARM_DESC(uwb_state, |
@@ -8371,6 +8990,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
8371 | PCI_VENDOR_ID_IBM; | 8990 | PCI_VENDOR_ID_IBM; |
8372 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; | 8991 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; |
8373 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; | 8992 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; |
8993 | tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; | ||
8374 | } | 8994 | } |
8375 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 8995 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
8376 | ret = ibm_init(&ibms_init[i]); | 8996 | ret = ibm_init(&ibms_init[i]); |
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c new file mode 100644 index 000000000000..a350418e87ea --- /dev/null +++ b/drivers/platform/x86/toshiba_bluetooth.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Toshiba Bluetooth Enable Driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com> | ||
5 | * | ||
6 | * Thanks to Matthew Garrett for background info on ACPI innards which | ||
7 | * normal people aren't meant to understand :-) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Note the Toshiba Bluetooth RFKill switch seems to be a strange | ||
14 | * fish. It only provides a BT event when the switch is flipped to | ||
15 | * the 'on' position. When flipping it to 'off', the USB device is | ||
16 | * simply pulled away underneath us, without any BT event being | ||
17 | * delivered. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <acpi/acpi_bus.h> | ||
25 | #include <acpi/acpi_drivers.h> | ||
26 | |||
27 | MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>"); | ||
28 | MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | |||
32 | static int toshiba_bt_rfkill_add(struct acpi_device *device); | ||
33 | static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type); | ||
34 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); | ||
35 | static int toshiba_bt_resume(struct acpi_device *device); | ||
36 | |||
37 | static const struct acpi_device_id bt_device_ids[] = { | ||
38 | { "TOS6205", 0}, | ||
39 | { "", 0}, | ||
40 | }; | ||
41 | MODULE_DEVICE_TABLE(acpi, bt_device_ids); | ||
42 | |||
43 | static struct acpi_driver toshiba_bt_rfkill_driver = { | ||
44 | .name = "Toshiba BT", | ||
45 | .class = "Toshiba", | ||
46 | .ids = bt_device_ids, | ||
47 | .ops = { | ||
48 | .add = toshiba_bt_rfkill_add, | ||
49 | .remove = toshiba_bt_rfkill_remove, | ||
50 | .notify = toshiba_bt_rfkill_notify, | ||
51 | .resume = toshiba_bt_resume, | ||
52 | }, | ||
53 | .owner = THIS_MODULE, | ||
54 | }; | ||
55 | |||
56 | |||
57 | static int toshiba_bluetooth_enable(acpi_handle handle) | ||
58 | { | ||
59 | acpi_status res1, res2; | ||
60 | acpi_integer result; | ||
61 | |||
62 | /* | ||
63 | * Query ACPI to verify RFKill switch is set to 'on'. | ||
64 | * If not, we return silently, no need to report it as | ||
65 | * an error. | ||
66 | */ | ||
67 | res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result); | ||
68 | if (ACPI_FAILURE(res1)) | ||
69 | return res1; | ||
70 | if (!(result & 0x01)) | ||
71 | return 0; | ||
72 | |||
73 | printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n"); | ||
74 | res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL); | ||
75 | res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL); | ||
76 | if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2)) | ||
77 | return 0; | ||
78 | |||
79 | printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable " | ||
80 | "Toshiba Bluetooth\n"); | ||
81 | |||
82 | return -ENODEV; | ||
83 | } | ||
84 | |||
85 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) | ||
86 | { | ||
87 | toshiba_bluetooth_enable(device->handle); | ||
88 | } | ||
89 | |||
90 | static int toshiba_bt_resume(struct acpi_device *device) | ||
91 | { | ||
92 | return toshiba_bluetooth_enable(device->handle); | ||
93 | } | ||
94 | |||
95 | static int toshiba_bt_rfkill_add(struct acpi_device *device) | ||
96 | { | ||
97 | acpi_status status; | ||
98 | acpi_integer bt_present; | ||
99 | int result = -ENODEV; | ||
100 | |||
101 | /* | ||
102 | * Some Toshiba laptops may have a fake TOS6205 device in | ||
103 | * their ACPI BIOS, so query the _STA method to see if there | ||
104 | * is really anything there, before trying to enable it. | ||
105 | */ | ||
106 | status = acpi_evaluate_integer(device->handle, "_STA", NULL, | ||
107 | &bt_present); | ||
108 | |||
109 | if (!ACPI_FAILURE(status) && bt_present) { | ||
110 | printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - " | ||
111 | "installing RFKill handler\n"); | ||
112 | result = toshiba_bluetooth_enable(device->handle); | ||
113 | } | ||
114 | |||
115 | return result; | ||
116 | } | ||
117 | |||
118 | static int __init toshiba_bt_rfkill_init(void) | ||
119 | { | ||
120 | int result; | ||
121 | |||
122 | result = acpi_bus_register_driver(&toshiba_bt_rfkill_driver); | ||
123 | if (result < 0) { | ||
124 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
125 | "Error registering driver\n")); | ||
126 | return result; | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type) | ||
133 | { | ||
134 | /* clean up */ | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static void __exit toshiba_bt_rfkill_exit(void) | ||
139 | { | ||
140 | acpi_bus_unregister_driver(&toshiba_bt_rfkill_driver); | ||
141 | } | ||
142 | |||
143 | module_init(toshiba_bt_rfkill_init); | ||
144 | module_exit(toshiba_bt_rfkill_exit); | ||
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 177f8d767df4..e425a868cd3a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/device.h> | ||
33 | #include <linux/list.h> | 34 | #include <linux/list.h> |
34 | #include <linux/acpi.h> | 35 | #include <linux/acpi.h> |
35 | #include <acpi/acpi_bus.h> | 36 | #include <acpi/acpi_bus.h> |
@@ -65,6 +66,7 @@ struct wmi_block { | |||
65 | acpi_handle handle; | 66 | acpi_handle handle; |
66 | wmi_notify_handler handler; | 67 | wmi_notify_handler handler; |
67 | void *handler_data; | 68 | void *handler_data; |
69 | struct device *dev; | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | static struct wmi_block wmi_blocks; | 72 | static struct wmi_block wmi_blocks; |
@@ -195,6 +197,34 @@ static bool wmi_parse_guid(const u8 *src, u8 *dest) | |||
195 | return true; | 197 | return true; |
196 | } | 198 | } |
197 | 199 | ||
200 | /* | ||
201 | * Convert a raw GUID to the ACII string representation | ||
202 | */ | ||
203 | static int wmi_gtoa(const char *in, char *out) | ||
204 | { | ||
205 | int i; | ||
206 | |||
207 | for (i = 3; i >= 0; i--) | ||
208 | out += sprintf(out, "%02X", in[i] & 0xFF); | ||
209 | |||
210 | out += sprintf(out, "-"); | ||
211 | out += sprintf(out, "%02X", in[5] & 0xFF); | ||
212 | out += sprintf(out, "%02X", in[4] & 0xFF); | ||
213 | out += sprintf(out, "-"); | ||
214 | out += sprintf(out, "%02X", in[7] & 0xFF); | ||
215 | out += sprintf(out, "%02X", in[6] & 0xFF); | ||
216 | out += sprintf(out, "-"); | ||
217 | out += sprintf(out, "%02X", in[8] & 0xFF); | ||
218 | out += sprintf(out, "%02X", in[9] & 0xFF); | ||
219 | out += sprintf(out, "-"); | ||
220 | |||
221 | for (i = 10; i <= 15; i++) | ||
222 | out += sprintf(out, "%02X", in[i] & 0xFF); | ||
223 | |||
224 | out = '\0'; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
198 | static bool find_guid(const char *guid_string, struct wmi_block **out) | 228 | static bool find_guid(const char *guid_string, struct wmi_block **out) |
199 | { | 229 | { |
200 | char tmp[16], guid_input[16]; | 230 | char tmp[16], guid_input[16]; |
@@ -555,6 +585,138 @@ bool wmi_has_guid(const char *guid_string) | |||
555 | EXPORT_SYMBOL_GPL(wmi_has_guid); | 585 | EXPORT_SYMBOL_GPL(wmi_has_guid); |
556 | 586 | ||
557 | /* | 587 | /* |
588 | * sysfs interface | ||
589 | */ | ||
590 | static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, | ||
591 | char *buf) | ||
592 | { | ||
593 | char guid_string[37]; | ||
594 | struct wmi_block *wblock; | ||
595 | |||
596 | wblock = dev_get_drvdata(dev); | ||
597 | if (!wblock) | ||
598 | return -ENOMEM; | ||
599 | |||
600 | wmi_gtoa(wblock->gblock.guid, guid_string); | ||
601 | |||
602 | return sprintf(buf, "wmi:%s\n", guid_string); | ||
603 | } | ||
604 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); | ||
605 | |||
606 | static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
607 | { | ||
608 | char guid_string[37]; | ||
609 | |||
610 | struct wmi_block *wblock; | ||
611 | |||
612 | if (add_uevent_var(env, "MODALIAS=")) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | wblock = dev_get_drvdata(dev); | ||
616 | if (!wblock) | ||
617 | return -ENOMEM; | ||
618 | |||
619 | wmi_gtoa(wblock->gblock.guid, guid_string); | ||
620 | |||
621 | strcpy(&env->buf[env->buflen - 1], "wmi:"); | ||
622 | memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36); | ||
623 | env->buflen += 40; | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static void wmi_dev_free(struct device *dev) | ||
629 | { | ||
630 | kfree(dev); | ||
631 | } | ||
632 | |||
633 | static struct class wmi_class = { | ||
634 | .name = "wmi", | ||
635 | .dev_release = wmi_dev_free, | ||
636 | .dev_uevent = wmi_dev_uevent, | ||
637 | }; | ||
638 | |||
639 | static int wmi_create_devs(void) | ||
640 | { | ||
641 | int result; | ||
642 | char guid_string[37]; | ||
643 | struct guid_block *gblock; | ||
644 | struct wmi_block *wblock; | ||
645 | struct list_head *p; | ||
646 | struct device *guid_dev; | ||
647 | |||
648 | /* Create devices for all the GUIDs */ | ||
649 | list_for_each(p, &wmi_blocks.list) { | ||
650 | wblock = list_entry(p, struct wmi_block, list); | ||
651 | |||
652 | guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
653 | if (!guid_dev) | ||
654 | return -ENOMEM; | ||
655 | |||
656 | wblock->dev = guid_dev; | ||
657 | |||
658 | guid_dev->class = &wmi_class; | ||
659 | dev_set_drvdata(guid_dev, wblock); | ||
660 | |||
661 | gblock = &wblock->gblock; | ||
662 | |||
663 | wmi_gtoa(gblock->guid, guid_string); | ||
664 | dev_set_name(guid_dev, guid_string); | ||
665 | |||
666 | result = device_register(guid_dev); | ||
667 | if (result) | ||
668 | return result; | ||
669 | |||
670 | result = device_create_file(guid_dev, &dev_attr_modalias); | ||
671 | if (result) | ||
672 | return result; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static void wmi_remove_devs(void) | ||
679 | { | ||
680 | struct guid_block *gblock; | ||
681 | struct wmi_block *wblock; | ||
682 | struct list_head *p; | ||
683 | struct device *guid_dev; | ||
684 | |||
685 | /* Delete devices for all the GUIDs */ | ||
686 | list_for_each(p, &wmi_blocks.list) { | ||
687 | wblock = list_entry(p, struct wmi_block, list); | ||
688 | |||
689 | guid_dev = wblock->dev; | ||
690 | gblock = &wblock->gblock; | ||
691 | |||
692 | device_remove_file(guid_dev, &dev_attr_modalias); | ||
693 | |||
694 | device_unregister(guid_dev); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | static void wmi_class_exit(void) | ||
699 | { | ||
700 | wmi_remove_devs(); | ||
701 | class_unregister(&wmi_class); | ||
702 | } | ||
703 | |||
704 | static int wmi_class_init(void) | ||
705 | { | ||
706 | int ret; | ||
707 | |||
708 | ret = class_register(&wmi_class); | ||
709 | if (ret) | ||
710 | return ret; | ||
711 | |||
712 | ret = wmi_create_devs(); | ||
713 | if (ret) | ||
714 | wmi_class_exit(); | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | |||
719 | /* | ||
558 | * Parse the _WDG method for the GUID data blocks | 720 | * Parse the _WDG method for the GUID data blocks |
559 | */ | 721 | */ |
560 | static __init acpi_status parse_wdg(acpi_handle handle) | 722 | static __init acpi_status parse_wdg(acpi_handle handle) |
@@ -709,10 +871,17 @@ static int __init acpi_wmi_init(void) | |||
709 | 871 | ||
710 | if (result < 0) { | 872 | if (result < 0) { |
711 | printk(KERN_INFO PREFIX "Error loading mapper\n"); | 873 | printk(KERN_INFO PREFIX "Error loading mapper\n"); |
712 | } else { | 874 | return -ENODEV; |
713 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | 875 | } |
876 | |||
877 | result = wmi_class_init(); | ||
878 | if (result) { | ||
879 | acpi_bus_unregister_driver(&acpi_wmi_driver); | ||
880 | return result; | ||
714 | } | 881 | } |
715 | 882 | ||
883 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | ||
884 | |||
716 | return result; | 885 | return result; |
717 | } | 886 | } |
718 | 887 | ||
@@ -721,6 +890,8 @@ static void __exit acpi_wmi_exit(void) | |||
721 | struct list_head *p, *tmp; | 890 | struct list_head *p, *tmp; |
722 | struct wmi_block *wblock; | 891 | struct wmi_block *wblock; |
723 | 892 | ||
893 | wmi_class_exit(); | ||
894 | |||
724 | acpi_bus_unregister_driver(&acpi_wmi_driver); | 895 | acpi_bus_unregister_driver(&acpi_wmi_driver); |
725 | 896 | ||
726 | list_for_each_safe(p, tmp, &wmi_blocks.list) { | 897 | list_for_each_safe(p, tmp, &wmi_blocks.list) { |
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 83b8b5ac49c9..5314bf630bc4 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c | |||
@@ -80,7 +80,8 @@ static int pnpacpi_get_resources(struct pnp_dev *dev) | |||
80 | 80 | ||
81 | static int pnpacpi_set_resources(struct pnp_dev *dev) | 81 | static int pnpacpi_set_resources(struct pnp_dev *dev) |
82 | { | 82 | { |
83 | acpi_handle handle = dev->data; | 83 | struct acpi_device *acpi_dev = dev->data; |
84 | acpi_handle handle = acpi_dev->handle; | ||
84 | struct acpi_buffer buffer; | 85 | struct acpi_buffer buffer; |
85 | int ret; | 86 | int ret; |
86 | 87 | ||
@@ -103,7 +104,8 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) | |||
103 | 104 | ||
104 | static int pnpacpi_disable_resources(struct pnp_dev *dev) | 105 | static int pnpacpi_disable_resources(struct pnp_dev *dev) |
105 | { | 106 | { |
106 | acpi_handle handle = dev->data; | 107 | struct acpi_device *acpi_dev = dev->data; |
108 | acpi_handle handle = acpi_dev->handle; | ||
107 | int ret; | 109 | int ret; |
108 | 110 | ||
109 | dev_dbg(&dev->dev, "disable resources\n"); | 111 | dev_dbg(&dev->dev, "disable resources\n"); |
@@ -121,6 +123,8 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) | |||
121 | #ifdef CONFIG_ACPI_SLEEP | 123 | #ifdef CONFIG_ACPI_SLEEP |
122 | static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) | 124 | static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) |
123 | { | 125 | { |
126 | struct acpi_device *acpi_dev = dev->data; | ||
127 | acpi_handle handle = acpi_dev->handle; | ||
124 | int power_state; | 128 | int power_state; |
125 | 129 | ||
126 | power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); | 130 | power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); |
@@ -128,16 +132,19 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) | |||
128 | power_state = (state.event == PM_EVENT_ON) ? | 132 | power_state = (state.event == PM_EVENT_ON) ? |
129 | ACPI_STATE_D0 : ACPI_STATE_D3; | 133 | ACPI_STATE_D0 : ACPI_STATE_D3; |
130 | 134 | ||
131 | return acpi_bus_set_power((acpi_handle) dev->data, power_state); | 135 | return acpi_bus_set_power(handle, power_state); |
132 | } | 136 | } |
133 | 137 | ||
134 | static int pnpacpi_resume(struct pnp_dev *dev) | 138 | static int pnpacpi_resume(struct pnp_dev *dev) |
135 | { | 139 | { |
136 | return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0); | 140 | struct acpi_device *acpi_dev = dev->data; |
141 | acpi_handle handle = acpi_dev->handle; | ||
142 | |||
143 | return acpi_bus_set_power(handle, ACPI_STATE_D0); | ||
137 | } | 144 | } |
138 | #endif | 145 | #endif |
139 | 146 | ||
140 | static struct pnp_protocol pnpacpi_protocol = { | 147 | struct pnp_protocol pnpacpi_protocol = { |
141 | .name = "Plug and Play ACPI", | 148 | .name = "Plug and Play ACPI", |
142 | .get = pnpacpi_get_resources, | 149 | .get = pnpacpi_get_resources, |
143 | .set = pnpacpi_set_resources, | 150 | .set = pnpacpi_set_resources, |
@@ -147,6 +154,7 @@ static struct pnp_protocol pnpacpi_protocol = { | |||
147 | .resume = pnpacpi_resume, | 154 | .resume = pnpacpi_resume, |
148 | #endif | 155 | #endif |
149 | }; | 156 | }; |
157 | EXPORT_SYMBOL(pnpacpi_protocol); | ||
150 | 158 | ||
151 | static int __init pnpacpi_add_device(struct acpi_device *device) | 159 | static int __init pnpacpi_add_device(struct acpi_device *device) |
152 | { | 160 | { |
@@ -168,7 +176,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) | |||
168 | if (!dev) | 176 | if (!dev) |
169 | return -ENOMEM; | 177 | return -ENOMEM; |
170 | 178 | ||
171 | dev->data = device->handle; | 179 | dev->data = device; |
172 | /* .enabled means the device can decode the resources */ | 180 | /* .enabled means the device can decode the resources */ |
173 | dev->active = device->status.enabled; | 181 | dev->active = device->status.enabled; |
174 | status = acpi_get_handle(device->handle, "_SRS", &temp); | 182 | status = acpi_get_handle(device->handle, "_SRS", &temp); |
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ef3a2cd3a7a0..5702b2c8691f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -465,7 +465,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
465 | 465 | ||
466 | int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) | 466 | int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) |
467 | { | 467 | { |
468 | acpi_handle handle = dev->data; | 468 | struct acpi_device *acpi_dev = dev->data; |
469 | acpi_handle handle = acpi_dev->handle; | ||
469 | acpi_status status; | 470 | acpi_status status; |
470 | 471 | ||
471 | pnp_dbg(&dev->dev, "parse allocated resources\n"); | 472 | pnp_dbg(&dev->dev, "parse allocated resources\n"); |
@@ -773,7 +774,8 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
773 | 774 | ||
774 | int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) | 775 | int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) |
775 | { | 776 | { |
776 | acpi_handle handle = dev->data; | 777 | struct acpi_device *acpi_dev = dev->data; |
778 | acpi_handle handle = acpi_dev->handle; | ||
777 | acpi_status status; | 779 | acpi_status status; |
778 | struct acpipnp_parse_option_s parse_data; | 780 | struct acpipnp_parse_option_s parse_data; |
779 | 781 | ||
@@ -845,7 +847,8 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) | |||
845 | int pnpacpi_build_resource_template(struct pnp_dev *dev, | 847 | int pnpacpi_build_resource_template(struct pnp_dev *dev, |
846 | struct acpi_buffer *buffer) | 848 | struct acpi_buffer *buffer) |
847 | { | 849 | { |
848 | acpi_handle handle = dev->data; | 850 | struct acpi_device *acpi_dev = dev->data; |
851 | acpi_handle handle = acpi_dev->handle; | ||
849 | struct acpi_resource *resource; | 852 | struct acpi_resource *resource; |
850 | int res_cnt = 0; | 853 | int res_cnt = 0; |
851 | acpi_status status; | 854 | acpi_status status; |
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 6f8d8f971212..5066de5cfc0c 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c | |||
@@ -225,6 +225,12 @@ passive_store(struct device *dev, struct device_attribute *attr, | |||
225 | if (!sscanf(buf, "%d\n", &state)) | 225 | if (!sscanf(buf, "%d\n", &state)) |
226 | return -EINVAL; | 226 | return -EINVAL; |
227 | 227 | ||
228 | /* sanity check: values below 1000 millicelcius don't make sense | ||
229 | * and can cause the system to go into a thermal heart attack | ||
230 | */ | ||
231 | if (state && state < 1000) | ||
232 | return -EINVAL; | ||
233 | |||
228 | if (state && !tz->forced_passive) { | 234 | if (state && !tz->forced_passive) { |
229 | mutex_lock(&thermal_list_lock); | 235 | mutex_lock(&thermal_list_lock); |
230 | list_for_each_entry(cdev, &thermal_cdev_list, node) { | 236 | list_for_each_entry(cdev, &thermal_cdev_list, node) { |
@@ -235,6 +241,8 @@ passive_store(struct device *dev, struct device_attribute *attr, | |||
235 | cdev); | 241 | cdev); |
236 | } | 242 | } |
237 | mutex_unlock(&thermal_list_lock); | 243 | mutex_unlock(&thermal_list_lock); |
244 | if (!tz->passive_delay) | ||
245 | tz->passive_delay = 1000; | ||
238 | } else if (!state && tz->forced_passive) { | 246 | } else if (!state && tz->forced_passive) { |
239 | mutex_lock(&thermal_list_lock); | 247 | mutex_lock(&thermal_list_lock); |
240 | list_for_each_entry(cdev, &thermal_cdev_list, node) { | 248 | list_for_each_entry(cdev, &thermal_cdev_list, node) { |
@@ -245,17 +253,12 @@ passive_store(struct device *dev, struct device_attribute *attr, | |||
245 | cdev); | 253 | cdev); |
246 | } | 254 | } |
247 | mutex_unlock(&thermal_list_lock); | 255 | mutex_unlock(&thermal_list_lock); |
256 | tz->passive_delay = 0; | ||
248 | } | 257 | } |
249 | 258 | ||
250 | tz->tc1 = 1; | 259 | tz->tc1 = 1; |
251 | tz->tc2 = 1; | 260 | tz->tc2 = 1; |
252 | 261 | ||
253 | if (!tz->passive_delay) | ||
254 | tz->passive_delay = 1000; | ||
255 | |||
256 | if (!tz->polling_delay) | ||
257 | tz->polling_delay = 10000; | ||
258 | |||
259 | tz->forced_passive = state; | 262 | tz->forced_passive = state; |
260 | 263 | ||
261 | thermal_zone_device_update(tz); | 264 | thermal_zone_device_update(tz); |
@@ -374,7 +377,7 @@ thermal_cooling_device_cur_state_store(struct device *dev, | |||
374 | if (!sscanf(buf, "%ld\n", &state)) | 377 | if (!sscanf(buf, "%ld\n", &state)) |
375 | return -EINVAL; | 378 | return -EINVAL; |
376 | 379 | ||
377 | if (state < 0) | 380 | if ((long)state < 0) |
378 | return -EINVAL; | 381 | return -EINVAL; |
379 | 382 | ||
380 | result = cdev->ops->set_cur_state(cdev, state); | 383 | result = cdev->ops->set_cur_state(cdev, state); |
@@ -1016,6 +1019,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) | |||
1016 | thermal_zone_device_set_polling(tz, tz->passive_delay); | 1019 | thermal_zone_device_set_polling(tz, tz->passive_delay); |
1017 | else if (tz->polling_delay) | 1020 | else if (tz->polling_delay) |
1018 | thermal_zone_device_set_polling(tz, tz->polling_delay); | 1021 | thermal_zone_device_set_polling(tz, tz->polling_delay); |
1022 | else | ||
1023 | thermal_zone_device_set_polling(tz, 0); | ||
1019 | mutex_unlock(&tz->lock); | 1024 | mutex_unlock(&tz->lock); |
1020 | } | 1025 | } |
1021 | EXPORT_SYMBOL(thermal_zone_device_update); | 1026 | EXPORT_SYMBOL(thermal_zone_device_update); |