1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Input Power Event -> APM Bridge |
4 | * |
5 | * Copyright (c) 2007 Richard Purdie |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/input.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/init.h> |
14 | #include <linux/tty.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/pm.h> |
17 | #include <linux/apm-emulation.h> |
18 | |
19 | static void system_power_event(unsigned int keycode) |
20 | { |
21 | switch (keycode) { |
22 | case KEY_SUSPEND: |
23 | apm_queue_event(APM_USER_SUSPEND); |
24 | pr_info("Requesting system suspend...\n" ); |
25 | break; |
26 | default: |
27 | break; |
28 | } |
29 | } |
30 | |
31 | static void apmpower_event(struct input_handle *handle, unsigned int type, |
32 | unsigned int code, int value) |
33 | { |
34 | /* only react on key down events */ |
35 | if (value != 1) |
36 | return; |
37 | |
38 | switch (type) { |
39 | case EV_PWR: |
40 | system_power_event(keycode: code); |
41 | break; |
42 | |
43 | default: |
44 | break; |
45 | } |
46 | } |
47 | |
48 | static int apmpower_connect(struct input_handler *handler, |
49 | struct input_dev *dev, |
50 | const struct input_device_id *id) |
51 | { |
52 | struct input_handle *handle; |
53 | int error; |
54 | |
55 | handle = kzalloc(size: sizeof(struct input_handle), GFP_KERNEL); |
56 | if (!handle) |
57 | return -ENOMEM; |
58 | |
59 | handle->dev = dev; |
60 | handle->handler = handler; |
61 | handle->name = "apm-power" ; |
62 | |
63 | error = input_register_handle(handle); |
64 | if (error) { |
65 | pr_err("Failed to register input power handler, error %d\n" , |
66 | error); |
67 | kfree(objp: handle); |
68 | return error; |
69 | } |
70 | |
71 | error = input_open_device(handle); |
72 | if (error) { |
73 | pr_err("Failed to open input power device, error %d\n" , error); |
74 | input_unregister_handle(handle); |
75 | kfree(objp: handle); |
76 | return error; |
77 | } |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | static void apmpower_disconnect(struct input_handle *handle) |
83 | { |
84 | input_close_device(handle); |
85 | input_unregister_handle(handle); |
86 | kfree(objp: handle); |
87 | } |
88 | |
89 | static const struct input_device_id apmpower_ids[] = { |
90 | { |
91 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
92 | .evbit = { BIT_MASK(EV_PWR) }, |
93 | }, |
94 | { }, |
95 | }; |
96 | |
97 | MODULE_DEVICE_TABLE(input, apmpower_ids); |
98 | |
99 | static struct input_handler apmpower_handler = { |
100 | .event = apmpower_event, |
101 | .connect = apmpower_connect, |
102 | .disconnect = apmpower_disconnect, |
103 | .name = "apm-power" , |
104 | .id_table = apmpower_ids, |
105 | }; |
106 | |
107 | static int __init apmpower_init(void) |
108 | { |
109 | return input_register_handler(&apmpower_handler); |
110 | } |
111 | |
112 | static void __exit apmpower_exit(void) |
113 | { |
114 | input_unregister_handler(&apmpower_handler); |
115 | } |
116 | |
117 | module_init(apmpower_init); |
118 | module_exit(apmpower_exit); |
119 | |
120 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>" ); |
121 | MODULE_DESCRIPTION("Input Power Event -> APM Bridge" ); |
122 | MODULE_LICENSE("GPL" ); |
123 | |