acer-wmi: Add 3G rfkill sysfs file
Add 3G rfkill sysfs file for provide userland to control 3G device on/off by using WMI method. Signed-off-by: Lee, Chun-Yi <jlee@novell.com> Acked-by: Thomas Renninger <trenn@suse.de> Acked-by: Jiri Benc <jbenc@suse.cz> Acked-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Carlos Corbaho <carlos@strangeworlds.co.uk> Cc: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Matthew Garrett <mjg@redhat.com>
This commit is contained in:
		
							parent
							
								
									3fdca87d10
								
							
						
					
					
						commit
						b3c9092b2f
					
				| @ -85,6 +85,7 @@ MODULE_LICENSE("GPL"); | ||||
| #define AMW0_GUID2		"431F16ED-0C2B-444C-B267-27DEB140CF9C" | ||||
| #define WMID_GUID1		"6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" | ||||
| #define WMID_GUID2		"95764E09-FB56-4e83-B31A-37761F60994A" | ||||
| #define WMID_GUID3		"61EF69EA-865C-4BC3-A502-A0DEBA0CB531" | ||||
| 
 | ||||
| /*
 | ||||
|  * Acer ACPI event GUIDs | ||||
| @ -120,6 +121,24 @@ struct event_return_value { | ||||
| 	u32 reserved; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| /*
 | ||||
|  * GUID3 Get Device Status device flags | ||||
|  */ | ||||
| #define ACER_WMID3_GDS_THREEG		(1<<6)	/* 3G */ | ||||
| 
 | ||||
| struct wmid3_gds_input_param {	/* Get Device Status input parameter */ | ||||
| 	u8 function_num;	/* Function Number */ | ||||
| 	u8 hotkey_number;	/* Hotkey Number */ | ||||
| 	u16 devices;		/* Get Device */ | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct wmid3_gds_return_value {	/* Get Device Status return value*/ | ||||
| 	u8 error_code;		/* Error Code */ | ||||
| 	u8 ec_return_value;	/* EC Return Value */ | ||||
| 	u16 devices;		/* Current Device Status */ | ||||
| 	u32 reserved; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| /*
 | ||||
|  * Interface capability flags | ||||
|  */ | ||||
| @ -174,6 +193,7 @@ struct acer_debug { | ||||
| 
 | ||||
| static struct rfkill *wireless_rfkill; | ||||
| static struct rfkill *bluetooth_rfkill; | ||||
| static struct rfkill *threeg_rfkill; | ||||
| 
 | ||||
| /* Each low-level interface must define at least some of the following */ | ||||
| struct wmi_interface { | ||||
| @ -982,6 +1002,54 @@ static void acer_backlight_exit(void) | ||||
| 	backlight_device_unregister(acer_backlight_device); | ||||
| } | ||||
| 
 | ||||
| static acpi_status wmid3_get_device_status(u32 *value, u16 device) | ||||
| { | ||||
| 	struct wmid3_gds_return_value return_value; | ||||
| 	acpi_status status; | ||||
| 	union acpi_object *obj; | ||||
| 	struct wmid3_gds_input_param params = { | ||||
| 		.function_num = 0x1, | ||||
| 		.hotkey_number = 0x01, | ||||
| 		.devices = device, | ||||
| 	}; | ||||
| 	struct acpi_buffer input = { | ||||
| 		sizeof(struct wmid3_gds_input_param), | ||||
| 		¶ms | ||||
| 	}; | ||||
| 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||||
| 
 | ||||
| 	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); | ||||
| 	if (ACPI_FAILURE(status)) | ||||
| 		return status; | ||||
| 
 | ||||
| 	obj = output.pointer; | ||||
| 
 | ||||
| 	if (!obj) | ||||
| 		return AE_ERROR; | ||||
| 	else if (obj->type != ACPI_TYPE_BUFFER) { | ||||
| 		kfree(obj); | ||||
| 		return AE_ERROR; | ||||
| 	} | ||||
| 	if (obj->buffer.length != 8) { | ||||
| 		printk(ACER_WARNING "Unknown buffer length %d\n", | ||||
| 			obj->buffer.length); | ||||
| 		kfree(obj); | ||||
| 		return AE_ERROR; | ||||
| 	} | ||||
| 
 | ||||
| 	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); | ||||
| 	kfree(obj); | ||||
| 
 | ||||
| 	if (return_value.error_code || return_value.ec_return_value) | ||||
| 		printk(ACER_WARNING "Get Device Status failed: " | ||||
| 			"0x%x - 0x%x\n", return_value.error_code, | ||||
| 			return_value.ec_return_value); | ||||
| 	else | ||||
| 		*value = !!(return_value.devices & device); | ||||
| 
 | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Rfkill devices | ||||
|  */ | ||||
| @ -1002,6 +1070,13 @@ static void acer_rfkill_update(struct work_struct *ignored) | ||||
| 			rfkill_set_sw_state(bluetooth_rfkill, !state); | ||||
| 	} | ||||
| 
 | ||||
| 	if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { | ||||
| 		status = wmid3_get_device_status(&state, | ||||
| 				ACER_WMID3_GDS_THREEG); | ||||
| 		if (ACPI_SUCCESS(status)) | ||||
| 			rfkill_set_sw_state(threeg_rfkill, !state); | ||||
| 	} | ||||
| 
 | ||||
| 	schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | ||||
| } | ||||
| 
 | ||||
| @ -1058,6 +1133,19 @@ static int acer_rfkill_init(struct device *dev) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (has_cap(ACER_CAP_THREEG)) { | ||||
| 		threeg_rfkill = acer_rfkill_register(dev, | ||||
| 			RFKILL_TYPE_WWAN, "acer-threeg", | ||||
| 			ACER_CAP_THREEG); | ||||
| 		if (IS_ERR(threeg_rfkill)) { | ||||
| 			rfkill_unregister(wireless_rfkill); | ||||
| 			rfkill_destroy(wireless_rfkill); | ||||
| 			rfkill_unregister(bluetooth_rfkill); | ||||
| 			rfkill_destroy(bluetooth_rfkill); | ||||
| 			return PTR_ERR(threeg_rfkill); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -1074,6 +1162,11 @@ static void acer_rfkill_exit(void) | ||||
| 		rfkill_unregister(bluetooth_rfkill); | ||||
| 		rfkill_destroy(bluetooth_rfkill); | ||||
| 	} | ||||
| 
 | ||||
| 	if (has_cap(ACER_CAP_THREEG)) { | ||||
| 		rfkill_unregister(threeg_rfkill); | ||||
| 		rfkill_destroy(threeg_rfkill); | ||||
| 	} | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| @ -1084,7 +1177,12 @@ static ssize_t show_bool_threeg(struct device *dev, | ||||
| 	struct device_attribute *attr, char *buf) | ||||
| { | ||||
| 	u32 result; \ | ||||
| 	acpi_status status = get_u32(&result, ACER_CAP_THREEG); | ||||
| 	acpi_status status; | ||||
| 	if (wmi_has_guid(WMID_GUID3)) | ||||
| 		status = wmid3_get_device_status(&result, | ||||
| 				ACER_WMID3_GDS_THREEG); | ||||
| 	else | ||||
| 		status = get_u32(&result, ACER_CAP_THREEG); | ||||
| 	if (ACPI_SUCCESS(status)) | ||||
| 		return sprintf(buf, "%u\n", result); | ||||
| 	return sprintf(buf, "Read error\n"); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user