Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3c9092b authored by Lee, Chun-Yi's avatar Lee, Chun-Yi Committed by Matthew Garrett
Browse files

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: default avatarLee, Chun-Yi <jlee@novell.com>
Acked-by: default avatarThomas Renninger <trenn@suse.de>
Acked-by: default avatarJiri Benc <jbenc@suse.cz>
Acked-by: default avatarDmitry Torokhov <dtor@mail.ru>
Signed-off-by: default avatarCarlos Corbaho <carlos@strangeworlds.co.uk>
Cc: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
parent 3fdca87d
Loading
Loading
Loading
Loading
+99 −1
Original line number Diff line number Diff line
@@ -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),
		&params
	};
	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");