[PATCH 1/2] platform/x86: bitland-mifs-wmi: Add sysfs controls for device status

Rsplwe <[email protected]>
Newsgroups org.kernel.vger.platform-driver-x86,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add sysfs interfaces for controlling device status: Ambient Light, Fn Key Lock, TouchPad Lock.

Add missing ambient light command/event definitions and updated documentation.

Signed-off-by: Rsplwe <[email protected]>
---
 .../wmi/devices/bitland-mifs-wmi.rst          |   4 +
 drivers/platform/x86/bitland-mifs-wmi.c       | 166 +++++++++++++++++-
 2 files changed, 168 insertions(+), 2 deletions(-)

diff --git a/Documentation/wmi/devices/bitland-mifs-wmi.rst b/Documentation/wmi/devices/bitland-mifs-wmi.rst
index 9e86ecc2993c..57c5e6e18132 100644
--- a/Documentation/wmi/devices/bitland-mifs-wmi.rst
+++ b/Documentation/wmi/devices/bitland-mifs-wmi.rst
@@ -109,6 +109,8 @@ The following Command IDs are used in the third byte of the buffer:
 |          |                       | Bytes 6-7: GPU Fan RPM (Little Endian)   |
 |          |                       | Bytes 10-11: SYS Fan RPM (Little Endian) |
 +----------+-----------------------+------------------------------------------+
+| 15       | Ambient Light         | 0: Off, 1: On                            |
++----------+-----------------------+------------------------------------------+
 | 16       | RGBKeyboardMode       | 0: Off, 1: Auto Cyclic, 2: Fixed,        |
 |          |                       | 3: Custom                                |
 +----------+-----------------------+------------------------------------------+
@@ -168,6 +170,8 @@ Note: reserved event ids are not listed there
 +----------+------------------------------------------------------------------+
 | 9        | CapsLock state change                                            |
 +----------+------------------------------------------------------------------+
+| 10       | Ambient Light state change                                       |
++----------+------------------------------------------------------------------+
 | 13       | NumLock state change                                             |
 +----------+------------------------------------------------------------------+
 | 14       | ScrollLock state change                                          |
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 3a373184519d..e2652d1a1bf7 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -50,6 +50,7 @@ enum bitland_mifs_function {
 	WMI_FN_FN_LOCK			= 11,
 	WMI_FN_TP_LOCK			= 12,
 	WMI_FN_FAN_SPEEDS		= 13,
+	WMI_FN_AMBIENT_LIGHT		= 15,
 	WMI_FN_RGB_KB_MODE		= 16,
 	WMI_FN_RGB_KB_COLOR		= 17,
 	WMI_FN_RGB_KB_BRIGHTNESS	= 18,
@@ -83,6 +84,7 @@ enum bitland_mifs_event_id {
 	WMI_EVENT_FNLOCK_STATE		= 7,
 	WMI_EVENT_KBD_MODE		= 8,
 	WMI_EVENT_CAPSLOCK_STATE	= 9,
+	WMI_EVENT_AMBIENTLIGHT_STATE	= 10,
 	WMI_EVENT_CALCULATOR_START	= 11,
 	WMI_EVENT_BROWSER_START		= 12,
 	WMI_EVENT_NUMLOCK_STATE		= 13,
@@ -143,6 +145,7 @@ enum bitland_notifier_actions {
 	BITLAND_NOTIFY_KBD_BRIGHTNESS,
 	BITLAND_NOTIFY_PLATFORM_PROFILE,
 	BITLAND_NOTIFY_HWMON,
+	BITLAND_NOTIFY_SYSFS_STATE,
 };
 
 struct bitland_fan_notify_data {
@@ -568,6 +571,139 @@ static ssize_t kb_mode_store(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
+static int bitland_state_get(struct bitland_mifs_wmi_data *data, u8 function)
+{
+	struct bitland_mifs_input input = {
+		.reserved1 = 0,
+		.operation = WMI_METHOD_GET,
+		.reserved2 = 0,
+	};
+	struct bitland_mifs_output res;
+	int ret;
+
+	input.function = function;
+
+	ret = bitland_mifs_wmi_call(data, &input, &res);
+	if (ret)
+		return ret;
+
+	return res.data[0];
+}
+
+/* Switch states: 0:OFF, 1:ON */
+static ssize_t ambient_light_show(struct device *dev, struct device_attribute *attr,
+				  char *buf)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+	int state;
+
+	state = bitland_state_get(data, WMI_FN_AMBIENT_LIGHT);
+	if (state < 0)
+		return state;
+
+	return sysfs_emit(buf, "%d\n", state);
+}
+
+static ssize_t ambient_light_store(struct device *dev, struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+	struct bitland_mifs_input input = {
+		.reserved1 = 0,
+		.operation = WMI_METHOD_SET,
+		.reserved2 = 0,
+		.function = WMI_FN_AMBIENT_LIGHT,
+	};
+	bool val;
+	int ret;
+
+	if (kstrtobool(buf, &val))
+		return -EINVAL;
+
+	input.payload[0] = val;
+
+	ret = bitland_mifs_wmi_call(data, &input, NULL);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+	int state;
+
+	state = bitland_state_get(data, WMI_FN_FN_LOCK);
+	if (state < 0)
+		return state;
+
+	return sysfs_emit(buf, "%d\n", state);
+}
+
+static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+	struct bitland_mifs_input input = {
+		.reserved1 = 0,
+		.operation = WMI_METHOD_SET,
+		.reserved2 = 0,
+		.function = WMI_FN_FN_LOCK,
+	};
+	bool val;
+	int ret;
+
+	if (kstrtobool(buf, &val))
+		return -EINVAL;
+
+	input.payload[0] = val;
+
+	ret = bitland_mifs_wmi_call(data, &input, NULL);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t tp_lock_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+	int state;
+
+	state = bitland_state_get(data, WMI_FN_TP_LOCK);
+	if (state < 0)
+		return state;
+
+	return sysfs_emit(buf, "%d\n", state);
+}
+
+static ssize_t tp_lock_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+	struct bitland_mifs_input input = {
+		.reserved1 = 0,
+		.operation = WMI_METHOD_SET,
+		.reserved2 = 0,
+		.function = WMI_FN_TP_LOCK,
+	};
+	bool val;
+	int ret;
+
+	if (kstrtobool(buf, &val))
+		return -EINVAL;
+
+	input.payload[0] = val;
+
+	ret = bitland_mifs_wmi_call(data, &input, NULL);
+	if (ret)
+		return ret;
+	return count;
+}
+
 /* Fan Boost: 0:Normal, 1:Max Speed */
 static ssize_t fan_boost_store(struct device *dev,
 			       struct device_attribute *attr, const char *buf,
@@ -599,11 +735,17 @@ static ssize_t fan_boost_store(struct device *dev,
 static const DEVICE_ATTR_RW(gpu_mode);
 static const DEVICE_ATTR_RW(kb_mode);
 static const DEVICE_ATTR_WO(fan_boost);
+static const DEVICE_ATTR_RW(ambient_light);
+static const DEVICE_ATTR_RW(fn_lock);
+static const DEVICE_ATTR_RW(tp_lock);
 
 static const struct attribute *const laptop_attrs[] = {
 	&dev_attr_gpu_mode.attr,
 	&dev_attr_kb_mode.attr,
 	&dev_attr_fan_boost.attr,
+	&dev_attr_ambient_light.attr,
+	&dev_attr_fn_lock.attr,
+	&dev_attr_tp_lock.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(laptop);
@@ -653,6 +795,11 @@ static int bitland_notifier_callback(struct notifier_block *nb,
 		hwmon_notify_event(data_ctx->hwmon_dev, hwmon_fan,
 				   hwmon_fan_input, fan_info->channel);
 		break;
+	case BITLAND_NOTIFY_SYSFS_STATE:
+		const char *attr = data;
+
+		sysfs_notify(&data_ctx->wdev->dev.kobj, NULL, attr);
+		break;
 	}
 
 	return NOTIFY_OK;
@@ -798,8 +945,6 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
 		break;
 
 	case WMI_EVENT_AIRPLANE_MODE:
-	case WMI_EVENT_TOUCHPAD_STATE:
-	case WMI_EVENT_FNLOCK_STATE:
 	case WMI_EVENT_KBD_MODE:
 	case WMI_EVENT_CAPSLOCK_STATE:
 	case WMI_EVENT_NUMLOCK_STATE:
@@ -810,6 +955,23 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
 		dev_dbg(&wdev->dev, "State change event: id=%d value=%d\n",
 			event->event_id, event->value_low);
 		break;
+	case WMI_EVENT_AMBIENTLIGHT_STATE:
+		blocking_notifier_call_chain(&bitland_notifier_list,
+					     BITLAND_NOTIFY_SYSFS_STATE,
+					     "ambient_light");
+		break;
+
+	case WMI_EVENT_TOUCHPAD_STATE:
+		blocking_notifier_call_chain(&bitland_notifier_list,
+					     BITLAND_NOTIFY_SYSFS_STATE,
+					     "tp_lock");
+		break;
+
+	case WMI_EVENT_FNLOCK_STATE:
+		blocking_notifier_call_chain(&bitland_notifier_list,
+					     BITLAND_NOTIFY_SYSFS_STATE,
+					     "fn_lock");
+		break;
 
 	default:
 		dev_dbg(&wdev->dev, "Unknown event: id=0x%02x value=0x%02x\n",
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.