1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Linux driver for Bitland notebooks.
4 *
5 * Copyright (C) 2026 2 Mingyou Chen <qby140326@gmail.com>
6 */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10 #include <linux/acpi.h>
11 #include <linux/array_size.h>
12 #include <linux/bits.h>
13 #include <linux/container_of.h>
14 #include <linux/dev_printk.h>
15 #include <linux/device.h>
16 #include <linux/device/devres.h>
17 #include <linux/err.h>
18 #include <linux/hwmon.h>
19 #include <linux/init.h>
20 #include <linux/input-event-codes.h>
21 #include <linux/input.h>
22 #include <linux/input/sparse-keymap.h>
23 #include <linux/kernel.h>
24 #include <linux/leds.h>
25 #include <linux/module.h>
26 #include <linux/notifier.h>
27 #include <linux/platform_profile.h>
28 #include <linux/pm.h>
29 #include <linux/power_supply.h>
30 #include <linux/stddef.h>
31 #include <linux/string.h>
32 #include <linux/sysfs.h>
33 #include <linux/unaligned.h>
34 #include <linux/units.h>
35 #include <linux/wmi.h>
36
37 #define DRV_NAME "bitland-mifs-wmi"
38 #define BITLAND_MIFS_GUID "B60BFB48-3E5B-49E4-A0E9-8CFFE1B3434B"
39 #define BITLAND_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF"
40
41 enum bitland_mifs_operation {
42 WMI_METHOD_GET = 250,
43 WMI_METHOD_SET = 251,
44 };
45
46 enum bitland_mifs_function {
47 WMI_FN_SYSTEM_PER_MODE = 8,
48 WMI_FN_GPU_MODE = 9,
49 WMI_FN_KBD_TYPE = 10,
50 WMI_FN_FN_LOCK = 11,
51 WMI_FN_TP_LOCK = 12,
52 WMI_FN_FAN_SPEEDS = 13,
53 WMI_FN_RGB_KB_MODE = 16,
54 WMI_FN_RGB_KB_COLOR = 17,
55 WMI_FN_RGB_KB_BRIGHTNESS = 18,
56 WMI_FN_SYSTEM_AC_TYPE = 19,
57 WMI_FN_MAX_FAN_SWITCH = 20,
58 WMI_FN_MAX_FAN_SPEED = 21,
59 WMI_FN_CPU_THERMOMETER = 22,
60 WMI_FN_CPU_POWER = 23,
61 };
62
63 enum bitland_system_ac_mode {
64 WMI_SYSTEM_AC_TYPEC = 1,
65 /* Unknown type, this is unused in the original driver */
66 WMI_SYSTEM_AC_CIRCULARHOLE = 2,
67 };
68
69 enum bitland_mifs_power_profile {
70 WMI_PP_BALANCED = 0,
71 WMI_PP_PERFORMANCE = 1,
72 WMI_PP_QUIET = 2,
73 WMI_PP_FULL_SPEED = 3,
74 };
75
76 enum bitland_mifs_event_id {
77 WMI_EVENT_RESERVED_1 = 1,
78 WMI_EVENT_RESERVED_2 = 2,
79 WMI_EVENT_RESERVED_3 = 3,
80 WMI_EVENT_AIRPLANE_MODE = 4,
81 WMI_EVENT_KBD_BRIGHTNESS = 5,
82 WMI_EVENT_TOUCHPAD_STATE = 6,
83 WMI_EVENT_FNLOCK_STATE = 7,
84 WMI_EVENT_KBD_MODE = 8,
85 WMI_EVENT_CAPSLOCK_STATE = 9,
86 WMI_EVENT_CALCULATOR_START = 11,
87 WMI_EVENT_BROWSER_START = 12,
88 WMI_EVENT_NUMLOCK_STATE = 13,
89 WMI_EVENT_SCROLLLOCK_STATE = 14,
90 WMI_EVENT_PERFORMANCE_PLAN = 15,
91 WMI_EVENT_FN_J = 16,
92 WMI_EVENT_FN_F = 17,
93 WMI_EVENT_FN_0 = 18,
94 WMI_EVENT_FN_1 = 19,
95 WMI_EVENT_FN_2 = 20,
96 WMI_EVENT_FN_3 = 21,
97 WMI_EVENT_FN_4 = 22,
98 WMI_EVENT_FN_5 = 24,
99 WMI_EVENT_REFRESH_RATE = 25,
100 WMI_EVENT_CPU_FAN_SPEED = 26,
101 WMI_EVENT_GPU_FAN_SPEED = 32,
102 WMI_EVENT_WIN_KEY_LOCK = 33,
103 WMI_EVENT_RESERVED_23 = 34,
104 WMI_EVENT_OPEN_APP = 35,
105 };
106
107 enum bitland_mifs_event_type {
108 WMI_EVENT_TYPE_HOTKEY = 1,
109 };
110
111 enum bitland_wmi_device_type {
112 BITLAND_WMI_CONTROL = 0,
113 BITLAND_WMI_EVENT = 1,
114 };
115
116 struct bitland_mifs_input {
117 u8 reserved1;
118 u8 operation;
119 u8 reserved2;
120 u8 function;
121 u8 payload[28];
122 } __packed;
123
124 struct bitland_mifs_output {
125 u8 reserved1;
126 u8 operation;
127 u8 reserved2;
128 u8 function;
129 u8 data[28];
130 } __packed;
131
132 struct bitland_mifs_event {
133 u8 event_type;
134 u8 event_id;
135 u8 value_low; /* For most events, this is the value */
136 u8 value_high; /* For fan speed events, combined with value_low */
137 u8 reserved[4];
138 } __packed;
139
140 static BLOCKING_NOTIFIER_HEAD(bitland_notifier_list);
141
142 enum bitland_notifier_actions {
143 BITLAND_NOTIFY_KBD_BRIGHTNESS,
144 BITLAND_NOTIFY_PLATFORM_PROFILE,
145 BITLAND_NOTIFY_HWMON,
146 };
147
148 struct bitland_fan_notify_data {
149 int channel; /* 0 = CPU, 1 = GPU */
150 u16 speed;
151 };
152
153 struct bitland_mifs_wmi_data {
154 struct wmi_device *wdev;
155 struct mutex lock; /* Protects WMI calls */
156 struct led_classdev kbd_led;
157 struct notifier_block notifier;
158 struct input_dev *input_dev;
159 struct device *hwmon_dev;
160 struct device *pp_dev;
161 enum platform_profile_option saved_profile;
162 };
163
bitland_mifs_wmi_call(struct bitland_mifs_wmi_data * data,const struct bitland_mifs_input * input,struct bitland_mifs_output * output)164 static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
165 const struct bitland_mifs_input *input,
166 struct bitland_mifs_output *output)
167 {
168 struct wmi_buffer in_buf = { .length = sizeof(*input), .data = (void *)input };
169 struct wmi_buffer out_buf = { 0 };
170 int ret;
171
172 guard(mutex)(&data->lock);
173
174 if (!output)
175 return wmidev_invoke_procedure(data->wdev, 0, 1, &in_buf);
176
177 ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf, sizeof(*output));
178 if (ret)
179 return ret;
180
181 memcpy(output, out_buf.data, sizeof(*output));
182 kfree(out_buf.data);
183
184 return 0;
185 }
186
laptop_profile_get(struct device * dev,enum platform_profile_option * profile)187 static int laptop_profile_get(struct device *dev,
188 enum platform_profile_option *profile)
189 {
190 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
191 struct bitland_mifs_input input = {
192 .reserved1 = 0,
193 .operation = WMI_METHOD_GET,
194 .reserved2 = 0,
195 .function = WMI_FN_SYSTEM_PER_MODE,
196 };
197 struct bitland_mifs_output result;
198 int ret;
199
200 ret = bitland_mifs_wmi_call(data, &input, &result);
201 if (ret)
202 return ret;
203
204 switch (result.data[0]) {
205 case WMI_PP_BALANCED:
206 *profile = PLATFORM_PROFILE_BALANCED;
207 break;
208 case WMI_PP_PERFORMANCE:
209 *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
210 break;
211 case WMI_PP_QUIET:
212 *profile = PLATFORM_PROFILE_LOW_POWER;
213 break;
214 case WMI_PP_FULL_SPEED:
215 *profile = PLATFORM_PROFILE_PERFORMANCE;
216 break;
217 default:
218 return -EINVAL;
219 }
220 return 0;
221 }
222
bitland_check_performance_capability(struct bitland_mifs_wmi_data * data)223 static int bitland_check_performance_capability(struct bitland_mifs_wmi_data *data)
224 {
225 struct bitland_mifs_input input = {
226 .operation = WMI_METHOD_GET,
227 .function = WMI_FN_SYSTEM_AC_TYPE,
228 };
229 struct bitland_mifs_output output;
230 int ret;
231
232 /* Full-speed/performance mode requires DC power (not USB-C) */
233 if (!power_supply_is_system_supplied())
234 return -EOPNOTSUPP;
235
236 ret = bitland_mifs_wmi_call(data, &input, &output);
237 if (ret)
238 return ret;
239
240 if (output.data[0] != WMI_SYSTEM_AC_CIRCULARHOLE)
241 return -EOPNOTSUPP;
242
243 return 0;
244 }
245
laptop_profile_set(struct device * dev,enum platform_profile_option profile)246 static int laptop_profile_set(struct device *dev,
247 enum platform_profile_option profile)
248 {
249 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
250 struct bitland_mifs_input input = {
251 .reserved1 = 0,
252 .operation = WMI_METHOD_SET,
253 .reserved2 = 0,
254 .function = WMI_FN_SYSTEM_PER_MODE,
255 };
256 int ret;
257 u8 val;
258
259 switch (profile) {
260 case PLATFORM_PROFILE_LOW_POWER:
261 val = WMI_PP_QUIET;
262 break;
263 case PLATFORM_PROFILE_BALANCED:
264 val = WMI_PP_BALANCED;
265 break;
266 case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
267 ret = bitland_check_performance_capability(data);
268 if (ret)
269 return ret;
270 val = WMI_PP_PERFORMANCE;
271 break;
272 case PLATFORM_PROFILE_PERFORMANCE:
273 ret = bitland_check_performance_capability(data);
274 if (ret)
275 return ret;
276 val = WMI_PP_FULL_SPEED;
277 break;
278 default:
279 return -EOPNOTSUPP;
280 }
281
282 input.payload[0] = val;
283
284 return bitland_mifs_wmi_call(data, &input, NULL);
285 }
286
platform_profile_probe(void * drvdata,unsigned long * choices)287 static int platform_profile_probe(void *drvdata, unsigned long *choices)
288 {
289 set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
290 set_bit(PLATFORM_PROFILE_BALANCED, choices);
291 set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
292 set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
293
294 return 0;
295 }
296
bitland_mifs_wmi_suspend(struct device * dev)297 static int bitland_mifs_wmi_suspend(struct device *dev)
298 {
299 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
300 enum platform_profile_option profile;
301 int ret;
302
303 /* Skip event device */
304 if (!data->pp_dev)
305 return 0;
306
307 ret = laptop_profile_get(data->pp_dev, &profile);
308 if (ret == 0)
309 data->saved_profile = profile;
310
311 return ret;
312 }
313
bitland_mifs_wmi_resume(struct device * dev)314 static int bitland_mifs_wmi_resume(struct device *dev)
315 {
316 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
317
318 /* Skip event device */
319 if (!data->pp_dev)
320 return 0;
321
322 dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile);
323 return laptop_profile_set(dev, data->saved_profile);
324 }
325
326 static DEFINE_SIMPLE_DEV_PM_OPS(bitland_mifs_wmi_pm_ops,
327 bitland_mifs_wmi_suspend,
328 bitland_mifs_wmi_resume);
329
330 static const struct platform_profile_ops laptop_profile_ops = {
331 .probe = platform_profile_probe,
332 .profile_get = laptop_profile_get,
333 .profile_set = laptop_profile_set,
334 };
335
336 static const char *const fan_labels[] = {
337 "CPU", /* 0 */
338 "GPU", /* 1 */
339 "SYS", /* 2 */
340 };
341
laptop_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)342 static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
343 u32 attr, int channel, long *val)
344 {
345 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
346 struct bitland_mifs_input input = {
347 .reserved1 = 0,
348 .operation = WMI_METHOD_GET,
349 .reserved2 = 0,
350 };
351 struct bitland_mifs_output res;
352 int ret;
353
354 switch (type) {
355 case hwmon_temp:
356 input.function = WMI_FN_CPU_THERMOMETER;
357 ret = bitland_mifs_wmi_call(data, &input, &res);
358 if (!ret)
359 *val = res.data[0] * MILLIDEGREE_PER_DEGREE;
360 return ret;
361 case hwmon_fan:
362 input.function = WMI_FN_FAN_SPEEDS;
363 ret = bitland_mifs_wmi_call(data, &input, &res);
364 if (ret)
365 return ret;
366
367 switch (channel) {
368 case 0: /* CPU */
369 *val = get_unaligned_le16(&res.data[0]);
370 return 0;
371 case 1: /* GPU */
372 *val = get_unaligned_le16(&res.data[2]);
373 return 0;
374 case 2: /* SYS */
375 *val = get_unaligned_le16(&res.data[6]);
376 return 0;
377 default:
378 return -EINVAL;
379 }
380 default:
381 return -EINVAL;
382 }
383 }
384
laptop_hwmon_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)385 static int laptop_hwmon_read_string(struct device *dev,
386 enum hwmon_sensor_types type, u32 attr,
387 int channel, const char **str)
388 {
389 if (type == hwmon_fan && attr == hwmon_fan_label) {
390 if (channel >= 0 && channel < ARRAY_SIZE(fan_labels)) {
391 *str = fan_labels[channel];
392 return 0;
393 }
394 }
395 return -EINVAL;
396 }
397
398 static const struct hwmon_channel_info *laptop_hwmon_info[] = {
399 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
400 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL,
401 HWMON_F_INPUT | HWMON_F_LABEL,
402 HWMON_F_INPUT | HWMON_F_LABEL),
403 NULL
404 };
405
406 static const struct hwmon_ops laptop_hwmon_ops = {
407 .visible = 0444,
408 .read = laptop_hwmon_read,
409 .read_string = laptop_hwmon_read_string,
410 };
411
412 static const struct hwmon_chip_info laptop_chip_info = {
413 .ops = &laptop_hwmon_ops,
414 .info = laptop_hwmon_info,
415 };
416
laptop_kbd_led_set(struct led_classdev * led_cdev,enum led_brightness value)417 static int laptop_kbd_led_set(struct led_classdev *led_cdev,
418 enum led_brightness value)
419 {
420 struct bitland_mifs_wmi_data *data =
421 container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led);
422 struct bitland_mifs_input input = {
423 .reserved1 = 0,
424 .operation = WMI_METHOD_SET,
425 .reserved2 = 0,
426 .function = WMI_FN_RGB_KB_BRIGHTNESS,
427 };
428
429 input.payload[0] = (u8)value;
430
431 return bitland_mifs_wmi_call(data, &input, NULL);
432 }
433
laptop_kbd_led_get(struct led_classdev * led_cdev)434 static enum led_brightness laptop_kbd_led_get(struct led_classdev *led_cdev)
435 {
436 struct bitland_mifs_wmi_data *data =
437 container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led);
438 struct bitland_mifs_input input = {
439 .reserved1 = 0,
440 .operation = WMI_METHOD_GET,
441 .reserved2 = 0,
442 .function = WMI_FN_RGB_KB_BRIGHTNESS,
443 };
444 struct bitland_mifs_output res;
445 int ret;
446
447 ret = bitland_mifs_wmi_call(data, &input, &res);
448 if (ret)
449 return ret;
450
451 return res.data[0];
452 }
453
454 static const char *const gpu_mode_strings[] = {
455 "hybrid",
456 "discrete",
457 "uma",
458 };
459
460 /* GPU Mode: 0:Hybrid, 1:Discrete, 2:UMA */
gpu_mode_show(struct device * dev,struct device_attribute * attr,char * buf)461 static ssize_t gpu_mode_show(struct device *dev, struct device_attribute *attr,
462 char *buf)
463 {
464 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
465 struct bitland_mifs_input input = {
466 .reserved1 = 0,
467 .operation = WMI_METHOD_GET,
468 .reserved2 = 0,
469 .function = WMI_FN_GPU_MODE,
470 };
471 struct bitland_mifs_output res;
472 u8 mode_val;
473 int ret;
474
475 ret = bitland_mifs_wmi_call(data, &input, &res);
476 if (ret)
477 return ret;
478
479 mode_val = res.data[0];
480 if (mode_val >= ARRAY_SIZE(gpu_mode_strings))
481 return -EPROTO;
482
483 return sysfs_emit(buf, "%s\n", gpu_mode_strings[mode_val]);
484 }
485
gpu_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)486 static ssize_t gpu_mode_store(struct device *dev, struct device_attribute *attr,
487 const char *buf, size_t count)
488 {
489 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
490 struct bitland_mifs_input input = {
491 .reserved1 = 0,
492 .operation = WMI_METHOD_SET,
493 .reserved2 = 0,
494 .function = WMI_FN_GPU_MODE,
495 };
496 int val;
497 int ret;
498
499 val = sysfs_match_string(gpu_mode_strings, buf);
500 if (val < 0)
501 return -EINVAL;
502
503 input.payload[0] = (u8)val;
504
505 ret = bitland_mifs_wmi_call(data, &input, NULL);
506 if (ret)
507 return ret;
508
509 return count;
510 }
511
512 static const char *const kb_mode_strings[] = {
513 "off", /* 0 */
514 "cyclic", /* 1 */
515 "fixed", /* 2 */
516 "custom", /* 3 */
517 };
518
kb_mode_show(struct device * dev,struct device_attribute * attr,char * buf)519 static ssize_t kb_mode_show(struct device *dev, struct device_attribute *attr,
520 char *buf)
521 {
522 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
523 struct bitland_mifs_input input = {
524 .reserved1 = 0,
525 .operation = WMI_METHOD_GET,
526 .reserved2 = 0,
527 .function = WMI_FN_RGB_KB_MODE,
528 };
529 struct bitland_mifs_output res;
530 u8 mode_val;
531 int ret;
532
533 ret = bitland_mifs_wmi_call(data, &input, &res);
534 if (ret)
535 return ret;
536
537 mode_val = res.data[0];
538 if (mode_val >= ARRAY_SIZE(kb_mode_strings))
539 return -EPROTO;
540
541 return sysfs_emit(buf, "%s\n", kb_mode_strings[mode_val]);
542 }
543
kb_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)544 static ssize_t kb_mode_store(struct device *dev, struct device_attribute *attr,
545 const char *buf, size_t count)
546 {
547 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
548 struct bitland_mifs_input input = {
549 .reserved1 = 0,
550 .operation = WMI_METHOD_SET,
551 .reserved2 = 0,
552 .function = WMI_FN_RGB_KB_MODE,
553 };
554 // the wmi value (0, 1, 2 or 3)
555 int val;
556 int ret;
557
558 val = sysfs_match_string(kb_mode_strings, buf);
559 if (val < 0)
560 return -EINVAL;
561
562 input.payload[0] = (u8)val;
563
564 ret = bitland_mifs_wmi_call(data, &input, NULL);
565 if (ret)
566 return ret;
567
568 return count;
569 }
570
571 /* Fan Boost: 0:Normal, 1:Max Speed */
fan_boost_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)572 static ssize_t fan_boost_store(struct device *dev,
573 struct device_attribute *attr, const char *buf,
574 size_t count)
575 {
576 struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
577 struct bitland_mifs_input input = {
578 .reserved1 = 0,
579 .operation = WMI_METHOD_SET,
580 .reserved2 = 0,
581 .function = WMI_FN_MAX_FAN_SWITCH,
582 };
583 bool val;
584 int ret;
585
586 if (kstrtobool(buf, &val))
587 return -EINVAL;
588
589 input.payload[0] = 0; /* CPU/GPU Fan */
590 input.payload[1] = val;
591
592 ret = bitland_mifs_wmi_call(data, &input, NULL);
593 if (ret)
594 return ret;
595
596 return count;
597 }
598
599 static const DEVICE_ATTR_RW(gpu_mode);
600 static const DEVICE_ATTR_RW(kb_mode);
601 static const DEVICE_ATTR_WO(fan_boost);
602
603 static const struct attribute *const laptop_attrs[] = {
604 &dev_attr_gpu_mode.attr,
605 &dev_attr_kb_mode.attr,
606 &dev_attr_fan_boost.attr,
607 NULL,
608 };
609 ATTRIBUTE_GROUPS(laptop);
610
611 static const struct key_entry bitland_mifs_wmi_keymap[] = {
612 { KE_KEY, WMI_EVENT_OPEN_APP, { KEY_PROG1 } },
613 { KE_KEY, WMI_EVENT_CALCULATOR_START, { KEY_CALC } },
614 { KE_KEY, WMI_EVENT_BROWSER_START, { KEY_WWW } },
615 { KE_IGNORE, WMI_EVENT_FN_J, { KEY_RESERVED } },
616 { KE_IGNORE, WMI_EVENT_FN_F, { KEY_RESERVED } },
617 { KE_IGNORE, WMI_EVENT_FN_0, { KEY_RESERVED } },
618 { KE_IGNORE, WMI_EVENT_FN_1, { KEY_RESERVED } },
619 { KE_IGNORE, WMI_EVENT_FN_2, { KEY_RESERVED } },
620 { KE_IGNORE, WMI_EVENT_FN_3, { KEY_RESERVED } },
621 { KE_IGNORE, WMI_EVENT_FN_4, { KEY_RESERVED } },
622 { KE_IGNORE, WMI_EVENT_FN_5, { KEY_RESERVED } },
623 { KE_END, 0 }
624 };
625
bitland_notifier_unregister(void * data)626 static void bitland_notifier_unregister(void *data)
627 {
628 struct notifier_block *nb = data;
629
630 blocking_notifier_chain_unregister(&bitland_notifier_list, nb);
631 }
632
bitland_notifier_callback(struct notifier_block * nb,unsigned long action,void * data)633 static int bitland_notifier_callback(struct notifier_block *nb,
634 unsigned long action, void *data)
635 {
636 struct bitland_mifs_wmi_data *data_ctx =
637 container_of(nb, struct bitland_mifs_wmi_data, notifier);
638 struct bitland_fan_notify_data *fan_info;
639 u8 *brightness;
640
641 switch (action) {
642 case BITLAND_NOTIFY_KBD_BRIGHTNESS:
643 brightness = data;
644 led_classdev_notify_brightness_hw_changed(&data_ctx->kbd_led,
645 *brightness);
646 break;
647 case BITLAND_NOTIFY_PLATFORM_PROFILE:
648 platform_profile_notify(data_ctx->pp_dev);
649 break;
650 case BITLAND_NOTIFY_HWMON:
651 fan_info = data;
652
653 hwmon_notify_event(data_ctx->hwmon_dev, hwmon_fan,
654 hwmon_fan_input, fan_info->channel);
655 break;
656 }
657
658 return NOTIFY_OK;
659 }
660
bitland_mifs_wmi_probe(struct wmi_device * wdev,const void * context)661 static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
662 {
663 struct bitland_mifs_wmi_data *drv_data;
664 enum bitland_wmi_device_type dev_type =
665 (enum bitland_wmi_device_type)(unsigned long)context;
666 struct led_init_data init_data = {
667 .devicename = DRV_NAME,
668 .default_label = ":" LED_FUNCTION_KBD_BACKLIGHT,
669 .devname_mandatory = true,
670 };
671 int ret;
672
673 drv_data = devm_kzalloc(&wdev->dev, sizeof(*drv_data), GFP_KERNEL);
674 if (!drv_data)
675 return -ENOMEM;
676
677 drv_data->wdev = wdev;
678
679 ret = devm_mutex_init(&wdev->dev, &drv_data->lock);
680 if (ret)
681 return ret;
682
683 dev_set_drvdata(&wdev->dev, drv_data);
684
685 if (dev_type == BITLAND_WMI_EVENT) {
686 /* Register input device for hotkeys */
687 drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
688 if (!drv_data->input_dev)
689 return -ENOMEM;
690
691 drv_data->input_dev->name = "Bitland MIFS WMI hotkeys";
692 drv_data->input_dev->phys = "wmi/input0";
693 drv_data->input_dev->id.bustype = BUS_HOST;
694 drv_data->input_dev->dev.parent = &wdev->dev;
695
696 ret = sparse_keymap_setup(drv_data->input_dev,
697 bitland_mifs_wmi_keymap, NULL);
698 if (ret)
699 return ret;
700
701 return input_register_device(drv_data->input_dev);
702 }
703
704 /* Register platform profile */
705 drv_data->pp_dev = devm_platform_profile_register(&wdev->dev, DRV_NAME, drv_data,
706 &laptop_profile_ops);
707 if (IS_ERR(drv_data->pp_dev))
708 return PTR_ERR(drv_data->pp_dev);
709
710 /* Register hwmon */
711 drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
712 "bitland_mifs",
713 drv_data,
714 &laptop_chip_info,
715 NULL);
716 if (IS_ERR(drv_data->hwmon_dev))
717 return PTR_ERR(drv_data->hwmon_dev);
718
719 /* Register keyboard LED */
720 drv_data->kbd_led.max_brightness = 3;
721 drv_data->kbd_led.brightness_set_blocking = laptop_kbd_led_set;
722 drv_data->kbd_led.brightness_get = laptop_kbd_led_get;
723 drv_data->kbd_led.brightness = laptop_kbd_led_get(&drv_data->kbd_led);
724 drv_data->kbd_led.flags = LED_CORE_SUSPENDRESUME |
725 LED_BRIGHT_HW_CHANGED |
726 LED_REJECT_NAME_CONFLICT;
727 ret = devm_led_classdev_register_ext(&wdev->dev, &drv_data->kbd_led, &init_data);
728 if (ret)
729 return ret;
730
731 drv_data->notifier.notifier_call = bitland_notifier_callback;
732 ret = blocking_notifier_chain_register(&bitland_notifier_list, &drv_data->notifier);
733 if (ret)
734 return ret;
735
736 return devm_add_action_or_reset(&wdev->dev,
737 bitland_notifier_unregister,
738 &drv_data->notifier);
739 }
740
bitland_mifs_wmi_notify(struct wmi_device * wdev,const struct wmi_buffer * buffer)741 static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
742 const struct wmi_buffer *buffer)
743 {
744 struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
745 const struct bitland_mifs_event *event = buffer->data;
746 struct bitland_fan_notify_data fan_data;
747 u8 brightness;
748
749 /* Validate event type */
750 if (event->event_type != WMI_EVENT_TYPE_HOTKEY)
751 return;
752
753 dev_dbg(&wdev->dev,
754 "WMI event: id=0x%02x value_low=0x%02x value_high=0x%02x\n",
755 event->event_id, event->value_low, event->value_high);
756
757 switch (event->event_id) {
758 case WMI_EVENT_KBD_BRIGHTNESS:
759 brightness = event->value_low;
760 blocking_notifier_call_chain(&bitland_notifier_list,
761 BITLAND_NOTIFY_KBD_BRIGHTNESS,
762 &brightness);
763 break;
764
765 case WMI_EVENT_PERFORMANCE_PLAN:
766 blocking_notifier_call_chain(&bitland_notifier_list,
767 BITLAND_NOTIFY_PLATFORM_PROFILE,
768 NULL);
769 break;
770
771 case WMI_EVENT_OPEN_APP:
772 case WMI_EVENT_CALCULATOR_START:
773 case WMI_EVENT_BROWSER_START: {
774 guard(mutex)(&data->lock);
775 if (!sparse_keymap_report_event(data->input_dev,
776 event->event_id, 1, true))
777 dev_warn(&wdev->dev, "Unknown key pressed: 0x%02x\n",
778 event->event_id);
779 break;
780 }
781
782 /*
783 * The device has 3 fans (CPU, GPU, SYS),
784 * but there are only the CPU and GPU fan has events
785 */
786 case WMI_EVENT_CPU_FAN_SPEED:
787 case WMI_EVENT_GPU_FAN_SPEED:
788 if (event->event_id == WMI_EVENT_CPU_FAN_SPEED)
789 fan_data.channel = 0;
790 else
791 fan_data.channel = 1;
792
793 /* Fan speed is 16-bit value (value_low is LSB, value_high is MSB) */
794 fan_data.speed = (event->value_high << 8) | event->value_low;
795 blocking_notifier_call_chain(&bitland_notifier_list,
796 BITLAND_NOTIFY_HWMON,
797 &fan_data);
798 break;
799
800 case WMI_EVENT_AIRPLANE_MODE:
801 case WMI_EVENT_TOUCHPAD_STATE:
802 case WMI_EVENT_FNLOCK_STATE:
803 case WMI_EVENT_KBD_MODE:
804 case WMI_EVENT_CAPSLOCK_STATE:
805 case WMI_EVENT_NUMLOCK_STATE:
806 case WMI_EVENT_SCROLLLOCK_STATE:
807 case WMI_EVENT_REFRESH_RATE:
808 case WMI_EVENT_WIN_KEY_LOCK:
809 /* These events are informational or handled by firmware */
810 dev_dbg(&wdev->dev, "State change event: id=%d value=%d\n",
811 event->event_id, event->value_low);
812 break;
813
814 default:
815 dev_dbg(&wdev->dev, "Unknown event: id=0x%02x value=0x%02x\n",
816 event->event_id, event->value_low);
817 break;
818 }
819 }
820
821 static const struct wmi_device_id bitland_mifs_wmi_id_table[] = {
822 { BITLAND_MIFS_GUID, (void *)BITLAND_WMI_CONTROL },
823 { BITLAND_EVENT_GUID, (void *)BITLAND_WMI_EVENT },
824 {}
825 };
826 MODULE_DEVICE_TABLE(wmi, bitland_mifs_wmi_id_table);
827
828 static struct wmi_driver bitland_mifs_wmi_driver = {
829 .no_singleton = true,
830 .driver = {
831 .name = DRV_NAME,
832 .dev_groups = laptop_groups,
833 .pm = pm_sleep_ptr(&bitland_mifs_wmi_pm_ops),
834 },
835 .id_table = bitland_mifs_wmi_id_table,
836 .min_event_size = sizeof(struct bitland_mifs_event),
837 .probe = bitland_mifs_wmi_probe,
838 .notify_new = bitland_mifs_wmi_notify,
839 };
840
841 module_wmi_driver(bitland_mifs_wmi_driver);
842
843 MODULE_AUTHOR("Mingyou Chen <qby140326@gmail.com>");
844 MODULE_DESCRIPTION("Bitland MIFS (MiInterface) WMI driver");
845 MODULE_LICENSE("GPL");
846