Skip to content

Commit 1ac9abe

Browse files
aymanbagabasandy-shev
authored andcommitted
platform/x86: huawei-wmi: Move to platform driver
Move from WMI driver to platform driver. This move is necessary since the driver is no longer a hotkeys driver only. Platform driver makes it easier for users to access sysfs attributes under (i.e. /sys/devices/platform/huawei-wmi) compared to wmi driver. Use WMI device UID, AMW0 has a UID of HWMI. WMI0 is the device name and doesn't have a UID so keep it as it is. Signed-off-by: Ayman Bagabas <[email protected]> Signed-off-by: Andy Shevchenko <[email protected]>
1 parent 4f5cafb commit 1ac9abe

File tree

2 files changed

+156
-77
lines changed

2 files changed

+156
-77
lines changed

drivers/platform/x86/Kconfig

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ config INTEL_ATOMISP2_PM
13051305
will be called intel_atomisp2_pm.
13061306

13071307
config HUAWEI_WMI
1308-
tristate "Huawei WMI hotkeys driver"
1308+
tristate "Huawei WMI laptop extras driver"
13091309
depends on ACPI_WMI
13101310
depends on INPUT
13111311
select INPUT_SPARSEKMAP
@@ -1314,9 +1314,8 @@ config HUAWEI_WMI
13141314
select LEDS_TRIGGER_AUDIO
13151315
select NEW_LEDS
13161316
help
1317-
This driver provides support for Huawei WMI hotkeys.
1318-
It enables the missing keys and adds support to the micmute
1319-
LED found on some of these laptops.
1317+
This driver provides support for Huawei WMI hotkeys, battery charge
1318+
control, fn-lock, mic-mute LED, and other extra features.
13201319

13211320
To compile this driver as a module, choose M here: the module
13221321
will be called huawei-wmi.

drivers/platform/x86/huawei-wmi.c

Lines changed: 153 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* Huawei WMI hotkeys
3+
* Huawei WMI laptop extras driver
44
*
55
* Copyright (C) 2018 Ayman Bagabas <[email protected]>
66
*/
@@ -10,23 +10,28 @@
1010
#include <linux/input/sparse-keymap.h>
1111
#include <linux/leds.h>
1212
#include <linux/module.h>
13+
#include <linux/platform_device.h>
1314
#include <linux/wmi.h>
1415

1516
/*
1617
* Huawei WMI GUIDs
1718
*/
18-
#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
19-
#define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
19+
#define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
2020

21+
/* Legacy GUIDs */
2122
#define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
23+
#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
2224

23-
struct huawei_wmi_priv {
24-
struct input_dev *idev;
25+
struct huawei_wmi {
26+
struct input_dev *idev[2];
2527
struct led_classdev cdev;
28+
struct platform_device *pdev;
2629
acpi_handle handle;
2730
char *acpi_method;
2831
};
2932

33+
struct huawei_wmi *huawei_wmi;
34+
3035
static const struct key_entry huawei_wmi_keymap[] = {
3136
{ KE_KEY, 0x281, { KEY_BRIGHTNESSDOWN } },
3237
{ KE_KEY, 0x282, { KEY_BRIGHTNESSUP } },
@@ -37,7 +42,7 @@ static const struct key_entry huawei_wmi_keymap[] = {
3742
{ KE_KEY, 0x289, { KEY_WLAN } },
3843
// Huawei |M| key
3944
{ KE_KEY, 0x28a, { KEY_CONFIG } },
40-
// Keyboard backlight
45+
// Keyboard backlit
4146
{ KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
4247
{ KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
4348
{ KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
@@ -47,7 +52,7 @@ static const struct key_entry huawei_wmi_keymap[] = {
4752
static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
4853
enum led_brightness brightness)
4954
{
50-
struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent);
55+
struct huawei_wmi *huawei = dev_get_drvdata(led_cdev->dev->parent);
5156
acpi_status status;
5257
union acpi_object args[3];
5358
struct acpi_object_list arg_list = {
@@ -58,52 +63,53 @@ static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
5863
args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
5964
args[1].integer.value = 0x04;
6065

61-
if (strcmp(priv->acpi_method, "SPIN") == 0) {
66+
if (strcmp(huawei->acpi_method, "SPIN") == 0) {
6267
args[0].integer.value = 0;
6368
args[2].integer.value = brightness ? 1 : 0;
64-
} else if (strcmp(priv->acpi_method, "WPIN") == 0) {
69+
} else if (strcmp(huawei->acpi_method, "WPIN") == 0) {
6570
args[0].integer.value = 1;
6671
args[2].integer.value = brightness ? 0 : 1;
6772
} else {
6873
return -EINVAL;
6974
}
7075

71-
status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL);
76+
status = acpi_evaluate_object(huawei->handle, huawei->acpi_method, &arg_list, NULL);
7277
if (ACPI_FAILURE(status))
7378
return -ENXIO;
7479

7580
return 0;
7681
}
7782

78-
static int huawei_wmi_leds_setup(struct wmi_device *wdev)
83+
static void huawei_wmi_leds_setup(struct device *dev)
7984
{
80-
struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
85+
struct huawei_wmi *huawei = dev_get_drvdata(dev);
8186

82-
priv->handle = ec_get_handle();
83-
if (!priv->handle)
84-
return 0;
87+
huawei->handle = ec_get_handle();
88+
if (!huawei->handle)
89+
return;
8590

86-
if (acpi_has_method(priv->handle, "SPIN"))
87-
priv->acpi_method = "SPIN";
88-
else if (acpi_has_method(priv->handle, "WPIN"))
89-
priv->acpi_method = "WPIN";
91+
if (acpi_has_method(huawei->handle, "SPIN"))
92+
huawei->acpi_method = "SPIN";
93+
else if (acpi_has_method(huawei->handle, "WPIN"))
94+
huawei->acpi_method = "WPIN";
9095
else
91-
return 0;
96+
return;
9297

93-
priv->cdev.name = "platform::micmute";
94-
priv->cdev.max_brightness = 1;
95-
priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
96-
priv->cdev.default_trigger = "audio-micmute";
97-
priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
98-
priv->cdev.dev = &wdev->dev;
99-
priv->cdev.flags = LED_CORE_SUSPENDRESUME;
98+
huawei->cdev.name = "platform::micmute";
99+
huawei->cdev.max_brightness = 1;
100+
huawei->cdev.brightness_set_blocking = &huawei_wmi_micmute_led_set;
101+
huawei->cdev.default_trigger = "audio-micmute";
102+
huawei->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
103+
huawei->cdev.dev = dev;
104+
huawei->cdev.flags = LED_CORE_SUSPENDRESUME;
100105

101-
return devm_led_classdev_register(&wdev->dev, &priv->cdev);
106+
devm_led_classdev_register(dev, &huawei->cdev);
102107
}
103108

104-
static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
109+
/* Input */
110+
111+
static void huawei_wmi_process_key(struct input_dev *idev, int code)
105112
{
106-
struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
107113
const struct key_entry *key;
108114

109115
/*
@@ -127,81 +133,155 @@ static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
127133
kfree(response.pointer);
128134
}
129135

130-
key = sparse_keymap_entry_from_scancode(priv->idev, code);
136+
key = sparse_keymap_entry_from_scancode(idev, code);
131137
if (!key) {
132-
dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code);
138+
dev_info(&idev->dev, "Unknown key pressed, code: 0x%04x\n", code);
133139
return;
134140
}
135141

136-
sparse_keymap_report_entry(priv->idev, key, 1, true);
142+
sparse_keymap_report_entry(idev, key, 1, true);
137143
}
138144

139-
static void huawei_wmi_notify(struct wmi_device *wdev,
140-
union acpi_object *obj)
145+
static void huawei_wmi_input_notify(u32 value, void *context)
141146
{
142-
if (obj->type == ACPI_TYPE_INTEGER)
143-
huawei_wmi_process_key(wdev, obj->integer.value);
147+
struct input_dev *idev = (struct input_dev *)context;
148+
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
149+
union acpi_object *obj;
150+
acpi_status status;
151+
152+
status = wmi_get_event_data(value, &response);
153+
if (ACPI_FAILURE(status)) {
154+
dev_err(&idev->dev, "Unable to get event data\n");
155+
return;
156+
}
157+
158+
obj = (union acpi_object *)response.pointer;
159+
if (obj && obj->type == ACPI_TYPE_INTEGER)
160+
huawei_wmi_process_key(idev, obj->integer.value);
144161
else
145-
dev_info(&wdev->dev, "Bad response type %d\n", obj->type);
162+
dev_err(&idev->dev, "Bad response type\n");
163+
164+
kfree(response.pointer);
146165
}
147166

148-
static int huawei_wmi_input_setup(struct wmi_device *wdev)
167+
static int huawei_wmi_input_setup(struct device *dev,
168+
const char *guid,
169+
struct input_dev **idev)
149170
{
150-
struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
151-
int err;
152-
153-
priv->idev = devm_input_allocate_device(&wdev->dev);
154-
if (!priv->idev)
171+
*idev = devm_input_allocate_device(dev);
172+
if (!*idev)
155173
return -ENOMEM;
156174

157-
priv->idev->name = "Huawei WMI hotkeys";
158-
priv->idev->phys = "wmi/input0";
159-
priv->idev->id.bustype = BUS_HOST;
160-
priv->idev->dev.parent = &wdev->dev;
175+
(*idev)->name = "Huawei WMI hotkeys";
176+
(*idev)->phys = "wmi/input0";
177+
(*idev)->id.bustype = BUS_HOST;
178+
(*idev)->dev.parent = dev;
161179

162-
err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL);
163-
if (err)
164-
return err;
180+
return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) ||
181+
input_register_device(*idev) ||
182+
wmi_install_notify_handler(guid, huawei_wmi_input_notify,
183+
*idev);
184+
}
165185

166-
return input_register_device(priv->idev);
186+
static void huawei_wmi_input_exit(struct device *dev, const char *guid)
187+
{
188+
wmi_remove_notify_handler(guid);
167189
}
168190

169-
static int huawei_wmi_probe(struct wmi_device *wdev, const void *context)
191+
/* Huawei driver */
192+
193+
static const struct wmi_device_id huawei_wmi_events_id_table[] = {
194+
{ .guid_string = WMI0_EVENT_GUID },
195+
{ }
196+
};
197+
198+
static int huawei_wmi_probe(struct platform_device *pdev)
170199
{
171-
struct huawei_wmi_priv *priv;
200+
const struct wmi_device_id *guid = huawei_wmi_events_id_table;
172201
int err;
173202

174-
priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
175-
if (!priv)
176-
return -ENOMEM;
203+
platform_set_drvdata(pdev, huawei_wmi);
204+
huawei_wmi->pdev = pdev;
177205

178-
dev_set_drvdata(&wdev->dev, priv);
206+
while (*guid->guid_string) {
207+
struct input_dev *idev = *huawei_wmi->idev;
179208

180-
err = huawei_wmi_input_setup(wdev);
181-
if (err)
182-
return err;
209+
if (wmi_has_guid(guid->guid_string)) {
210+
err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev);
211+
if (err) {
212+
dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string);
213+
return err;
214+
}
215+
}
183216

184-
return huawei_wmi_leds_setup(wdev);
217+
idev++;
218+
guid++;
219+
}
220+
221+
huawei_wmi_leds_setup(&pdev->dev);
222+
return 0;
185223
}
186224

187-
static const struct wmi_device_id huawei_wmi_id_table[] = {
188-
{ .guid_string = WMI0_EVENT_GUID },
189-
{ .guid_string = AMW0_EVENT_GUID },
190-
{ }
191-
};
225+
static int huawei_wmi_remove(struct platform_device *pdev)
226+
{
227+
const struct wmi_device_id *guid = huawei_wmi_events_id_table;
228+
229+
while (*guid->guid_string) {
230+
if (wmi_has_guid(guid->guid_string))
231+
huawei_wmi_input_exit(&pdev->dev, guid->guid_string);
232+
233+
guid++;
234+
}
192235

193-
static struct wmi_driver huawei_wmi_driver = {
236+
return 0;
237+
}
238+
239+
static struct platform_driver huawei_wmi_driver = {
194240
.driver = {
195241
.name = "huawei-wmi",
196242
},
197-
.id_table = huawei_wmi_id_table,
198243
.probe = huawei_wmi_probe,
199-
.notify = huawei_wmi_notify,
244+
.remove = huawei_wmi_remove,
200245
};
201246

202-
module_wmi_driver(huawei_wmi_driver);
247+
static __init int huawei_wmi_init(void)
248+
{
249+
struct platform_device *pdev;
250+
int err;
251+
252+
huawei_wmi = kzalloc(sizeof(struct huawei_wmi), GFP_KERNEL);
253+
if (!huawei_wmi)
254+
return -ENOMEM;
255+
256+
err = platform_driver_register(&huawei_wmi_driver);
257+
if (err)
258+
goto pdrv_err;
259+
260+
pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0);
261+
if (IS_ERR(pdev)) {
262+
err = PTR_ERR(pdev);
263+
goto pdev_err;
264+
}
265+
266+
return 0;
267+
268+
pdev_err:
269+
platform_driver_unregister(&huawei_wmi_driver);
270+
pdrv_err:
271+
kfree(huawei_wmi);
272+
return err;
273+
}
274+
275+
static __exit void huawei_wmi_exit(void)
276+
{
277+
platform_device_unregister(huawei_wmi->pdev);
278+
platform_driver_unregister(&huawei_wmi_driver);
279+
}
280+
281+
module_init(huawei_wmi_init);
282+
module_exit(huawei_wmi_exit);
203283

204-
MODULE_DEVICE_TABLE(wmi, huawei_wmi_id_table);
284+
MODULE_DEVICE_TABLE(wmi, huawei_wmi_events_id_table);
205285
MODULE_AUTHOR("Ayman Bagabas <[email protected]>");
206-
MODULE_DESCRIPTION("Huawei WMI hotkeys");
286+
MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
207287
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)