Commit | Line | Data |
---|---|---|
2025cf9e | 1 | // SPDX-License-Identifier: GPL-2.0-only |
aed06b9c S |
2 | /* |
3 | * Copyright (c) 2013, Microsoft Corporation. | |
aed06b9c S |
4 | */ |
5 | ||
6 | #include <linux/init.h> | |
7 | #include <linux/module.h> | |
8 | #include <linux/device.h> | |
9 | #include <linux/completion.h> | |
10 | #include <linux/hyperv.h> | |
11 | #include <linux/serio.h> | |
12 | #include <linux/slab.h> | |
13 | ||
14 | /* | |
15 | * Current version 1.0 | |
16 | * | |
17 | */ | |
18 | #define SYNTH_KBD_VERSION_MAJOR 1 | |
19 | #define SYNTH_KBD_VERSION_MINOR 0 | |
20 | #define SYNTH_KBD_VERSION (SYNTH_KBD_VERSION_MINOR | \ | |
21 | (SYNTH_KBD_VERSION_MAJOR << 16)) | |
22 | ||
23 | ||
24 | /* | |
25 | * Message types in the synthetic input protocol | |
26 | */ | |
27 | enum synth_kbd_msg_type { | |
28 | SYNTH_KBD_PROTOCOL_REQUEST = 1, | |
29 | SYNTH_KBD_PROTOCOL_RESPONSE = 2, | |
30 | SYNTH_KBD_EVENT = 3, | |
31 | SYNTH_KBD_LED_INDICATORS = 4, | |
32 | }; | |
33 | ||
34 | /* | |
35 | * Basic message structures. | |
36 | */ | |
37 | struct synth_kbd_msg_hdr { | |
38 | __le32 type; | |
39 | }; | |
40 | ||
41 | struct synth_kbd_msg { | |
42 | struct synth_kbd_msg_hdr header; | |
43 | char data[]; /* Enclosed message */ | |
44 | }; | |
45 | ||
46 | union synth_kbd_version { | |
47 | __le32 version; | |
48 | }; | |
49 | ||
50 | /* | |
51 | * Protocol messages | |
52 | */ | |
53 | struct synth_kbd_protocol_request { | |
54 | struct synth_kbd_msg_hdr header; | |
55 | union synth_kbd_version version_requested; | |
56 | }; | |
57 | ||
58 | #define PROTOCOL_ACCEPTED BIT(0) | |
59 | struct synth_kbd_protocol_response { | |
60 | struct synth_kbd_msg_hdr header; | |
61 | __le32 proto_status; | |
62 | }; | |
63 | ||
64 | #define IS_UNICODE BIT(0) | |
65 | #define IS_BREAK BIT(1) | |
66 | #define IS_E0 BIT(2) | |
67 | #define IS_E1 BIT(3) | |
68 | struct synth_kbd_keystroke { | |
69 | struct synth_kbd_msg_hdr header; | |
70 | __le16 make_code; | |
71 | __le16 reserved0; | |
72 | __le32 info; /* Additional information */ | |
73 | }; | |
74 | ||
75 | ||
76 | #define HK_MAXIMUM_MESSAGE_SIZE 256 | |
77 | ||
88f28e95 MN |
78 | #define KBD_VSC_SEND_RING_BUFFER_SIZE (40 * 1024) |
79 | #define KBD_VSC_RECV_RING_BUFFER_SIZE (40 * 1024) | |
aed06b9c S |
80 | |
81 | #define XTKBD_EMUL0 0xe0 | |
82 | #define XTKBD_EMUL1 0xe1 | |
83 | #define XTKBD_RELEASE 0x80 | |
84 | ||
85 | ||
86 | /* | |
87 | * Represents a keyboard device | |
88 | */ | |
89 | struct hv_kbd_dev { | |
90 | struct hv_device *hv_dev; | |
91 | struct serio *hv_serio; | |
92 | struct synth_kbd_protocol_request protocol_req; | |
93 | struct synth_kbd_protocol_response protocol_resp; | |
94 | /* Synchronize the request/response if needed */ | |
95 | struct completion wait_event; | |
96 | spinlock_t lock; /* protects 'started' field */ | |
97 | bool started; | |
98 | }; | |
99 | ||
100 | static void hv_kbd_on_receive(struct hv_device *hv_dev, | |
101 | struct synth_kbd_msg *msg, u32 msg_length) | |
102 | { | |
103 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); | |
104 | struct synth_kbd_keystroke *ks_msg; | |
105 | unsigned long flags; | |
106 | u32 msg_type = __le32_to_cpu(msg->header.type); | |
107 | u32 info; | |
108 | u16 scan_code; | |
109 | ||
110 | switch (msg_type) { | |
111 | case SYNTH_KBD_PROTOCOL_RESPONSE: | |
112 | /* | |
113 | * Validate the information provided by the host. | |
114 | * If the host is giving us a bogus packet, | |
115 | * drop the packet (hoping the problem | |
116 | * goes away). | |
117 | */ | |
118 | if (msg_length < sizeof(struct synth_kbd_protocol_response)) { | |
119 | dev_err(&hv_dev->device, | |
120 | "Illegal protocol response packet (len: %d)\n", | |
121 | msg_length); | |
122 | break; | |
123 | } | |
124 | ||
125 | memcpy(&kbd_dev->protocol_resp, msg, | |
126 | sizeof(struct synth_kbd_protocol_response)); | |
127 | complete(&kbd_dev->wait_event); | |
128 | break; | |
129 | ||
130 | case SYNTH_KBD_EVENT: | |
131 | /* | |
132 | * Validate the information provided by the host. | |
133 | * If the host is giving us a bogus packet, | |
134 | * drop the packet (hoping the problem | |
135 | * goes away). | |
136 | */ | |
137 | if (msg_length < sizeof(struct synth_kbd_keystroke)) { | |
138 | dev_err(&hv_dev->device, | |
139 | "Illegal keyboard event packet (len: %d)\n", | |
140 | msg_length); | |
141 | break; | |
142 | } | |
143 | ||
144 | ks_msg = (struct synth_kbd_keystroke *)msg; | |
145 | info = __le32_to_cpu(ks_msg->info); | |
146 | ||
147 | /* | |
148 | * Inject the information through the serio interrupt. | |
149 | */ | |
150 | spin_lock_irqsave(&kbd_dev->lock, flags); | |
151 | if (kbd_dev->started) { | |
152 | if (info & IS_E0) | |
153 | serio_interrupt(kbd_dev->hv_serio, | |
154 | XTKBD_EMUL0, 0); | |
c3c4d994 S |
155 | if (info & IS_E1) |
156 | serio_interrupt(kbd_dev->hv_serio, | |
157 | XTKBD_EMUL1, 0); | |
aed06b9c S |
158 | scan_code = __le16_to_cpu(ks_msg->make_code); |
159 | if (info & IS_BREAK) | |
160 | scan_code |= XTKBD_RELEASE; | |
161 | ||
162 | serio_interrupt(kbd_dev->hv_serio, scan_code, 0); | |
163 | } | |
164 | spin_unlock_irqrestore(&kbd_dev->lock, flags); | |
62238f3a DC |
165 | |
166 | /* | |
167 | * Only trigger a wakeup on key down, otherwise | |
168 | * "echo freeze > /sys/power/state" can't really enter the | |
169 | * state because the Enter-UP can trigger a wakeup at once. | |
170 | */ | |
171 | if (!(info & IS_BREAK)) | |
10f91c73 | 172 | pm_wakeup_hard_event(&hv_dev->device); |
62238f3a | 173 | |
aed06b9c S |
174 | break; |
175 | ||
176 | default: | |
177 | dev_err(&hv_dev->device, | |
178 | "unhandled message type %d\n", msg_type); | |
179 | } | |
180 | } | |
181 | ||
182 | static void hv_kbd_handle_received_packet(struct hv_device *hv_dev, | |
183 | struct vmpacket_descriptor *desc, | |
184 | u32 bytes_recvd, | |
185 | u64 req_id) | |
186 | { | |
187 | struct synth_kbd_msg *msg; | |
188 | u32 msg_sz; | |
189 | ||
190 | switch (desc->type) { | |
191 | case VM_PKT_COMP: | |
192 | break; | |
193 | ||
194 | case VM_PKT_DATA_INBAND: | |
195 | /* | |
196 | * We have a packet that has "inband" data. The API used | |
197 | * for retrieving the packet guarantees that the complete | |
198 | * packet is read. So, minimally, we should be able to | |
199 | * parse the payload header safely (assuming that the host | |
200 | * can be trusted. Trusting the host seems to be a | |
201 | * reasonable assumption because in a virtualized | |
202 | * environment there is not whole lot you can do if you | |
203 | * don't trust the host. | |
204 | * | |
205 | * Nonetheless, let us validate if the host can be trusted | |
206 | * (in a trivial way). The interesting aspect of this | |
207 | * validation is how do you recover if we discover that the | |
208 | * host is not to be trusted? Simply dropping the packet, I | |
209 | * don't think is an appropriate recovery. In the interest | |
210 | * of failing fast, it may be better to crash the guest. | |
211 | * For now, I will just drop the packet! | |
212 | */ | |
213 | ||
214 | msg_sz = bytes_recvd - (desc->offset8 << 3); | |
215 | if (msg_sz <= sizeof(struct synth_kbd_msg_hdr)) { | |
216 | /* | |
217 | * Drop the packet and hope | |
218 | * the problem magically goes away. | |
219 | */ | |
220 | dev_err(&hv_dev->device, | |
221 | "Illegal packet (type: %d, tid: %llx, size: %d)\n", | |
222 | desc->type, req_id, msg_sz); | |
223 | break; | |
224 | } | |
225 | ||
226 | msg = (void *)desc + (desc->offset8 << 3); | |
227 | hv_kbd_on_receive(hv_dev, msg, msg_sz); | |
228 | break; | |
229 | ||
230 | default: | |
231 | dev_err(&hv_dev->device, | |
232 | "unhandled packet type %d, tid %llx len %d\n", | |
233 | desc->type, req_id, bytes_recvd); | |
234 | break; | |
235 | } | |
236 | } | |
237 | ||
238 | static void hv_kbd_on_channel_callback(void *context) | |
239 | { | |
d09bc836 | 240 | struct vmpacket_descriptor *desc; |
aed06b9c | 241 | struct hv_device *hv_dev = context; |
aed06b9c S |
242 | u32 bytes_recvd; |
243 | u64 req_id; | |
aed06b9c | 244 | |
d09bc836 DC |
245 | foreach_vmbus_pkt(desc, hv_dev->channel) { |
246 | bytes_recvd = desc->len8 * 8; | |
247 | req_id = desc->trans_id; | |
aed06b9c | 248 | |
d09bc836 DC |
249 | hv_kbd_handle_received_packet(hv_dev, desc, bytes_recvd, |
250 | req_id); | |
aed06b9c S |
251 | } |
252 | } | |
253 | ||
254 | static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev) | |
255 | { | |
256 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); | |
257 | struct synth_kbd_protocol_request *request; | |
258 | struct synth_kbd_protocol_response *response; | |
259 | u32 proto_status; | |
260 | int error; | |
261 | ||
262 | request = &kbd_dev->protocol_req; | |
263 | memset(request, 0, sizeof(struct synth_kbd_protocol_request)); | |
264 | request->header.type = __cpu_to_le32(SYNTH_KBD_PROTOCOL_REQUEST); | |
265 | request->version_requested.version = __cpu_to_le32(SYNTH_KBD_VERSION); | |
266 | ||
267 | error = vmbus_sendpacket(hv_dev->channel, request, | |
268 | sizeof(struct synth_kbd_protocol_request), | |
269 | (unsigned long)request, | |
270 | VM_PKT_DATA_INBAND, | |
271 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
272 | if (error) | |
273 | return error; | |
274 | ||
275 | if (!wait_for_completion_timeout(&kbd_dev->wait_event, 10 * HZ)) | |
276 | return -ETIMEDOUT; | |
277 | ||
278 | response = &kbd_dev->protocol_resp; | |
279 | proto_status = __le32_to_cpu(response->proto_status); | |
280 | if (!(proto_status & PROTOCOL_ACCEPTED)) { | |
281 | dev_err(&hv_dev->device, | |
282 | "synth_kbd protocol request failed (version %d)\n", | |
283 | SYNTH_KBD_VERSION); | |
284 | return -ENODEV; | |
285 | } | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
290 | static int hv_kbd_start(struct serio *serio) | |
291 | { | |
292 | struct hv_kbd_dev *kbd_dev = serio->port_data; | |
293 | unsigned long flags; | |
294 | ||
295 | spin_lock_irqsave(&kbd_dev->lock, flags); | |
296 | kbd_dev->started = true; | |
297 | spin_unlock_irqrestore(&kbd_dev->lock, flags); | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
302 | static void hv_kbd_stop(struct serio *serio) | |
303 | { | |
304 | struct hv_kbd_dev *kbd_dev = serio->port_data; | |
305 | unsigned long flags; | |
306 | ||
307 | spin_lock_irqsave(&kbd_dev->lock, flags); | |
308 | kbd_dev->started = false; | |
309 | spin_unlock_irqrestore(&kbd_dev->lock, flags); | |
310 | } | |
311 | ||
312 | static int hv_kbd_probe(struct hv_device *hv_dev, | |
313 | const struct hv_vmbus_device_id *dev_id) | |
314 | { | |
315 | struct hv_kbd_dev *kbd_dev; | |
316 | struct serio *hv_serio; | |
317 | int error; | |
318 | ||
319 | kbd_dev = kzalloc(sizeof(struct hv_kbd_dev), GFP_KERNEL); | |
320 | hv_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | |
321 | if (!kbd_dev || !hv_serio) { | |
322 | error = -ENOMEM; | |
323 | goto err_free_mem; | |
324 | } | |
325 | ||
326 | kbd_dev->hv_dev = hv_dev; | |
327 | kbd_dev->hv_serio = hv_serio; | |
328 | spin_lock_init(&kbd_dev->lock); | |
329 | init_completion(&kbd_dev->wait_event); | |
330 | hv_set_drvdata(hv_dev, kbd_dev); | |
331 | ||
332 | hv_serio->dev.parent = &hv_dev->device; | |
333 | hv_serio->id.type = SERIO_8042_XL; | |
334 | hv_serio->port_data = kbd_dev; | |
335 | strlcpy(hv_serio->name, dev_name(&hv_dev->device), | |
336 | sizeof(hv_serio->name)); | |
337 | strlcpy(hv_serio->phys, dev_name(&hv_dev->device), | |
338 | sizeof(hv_serio->phys)); | |
339 | ||
340 | hv_serio->start = hv_kbd_start; | |
341 | hv_serio->stop = hv_kbd_stop; | |
342 | ||
343 | error = vmbus_open(hv_dev->channel, | |
344 | KBD_VSC_SEND_RING_BUFFER_SIZE, | |
345 | KBD_VSC_RECV_RING_BUFFER_SIZE, | |
346 | NULL, 0, | |
347 | hv_kbd_on_channel_callback, | |
348 | hv_dev); | |
349 | if (error) | |
350 | goto err_free_mem; | |
351 | ||
352 | error = hv_kbd_connect_to_vsp(hv_dev); | |
353 | if (error) | |
354 | goto err_close_vmbus; | |
355 | ||
356 | serio_register_port(kbd_dev->hv_serio); | |
62238f3a DC |
357 | |
358 | device_init_wakeup(&hv_dev->device, true); | |
359 | ||
aed06b9c S |
360 | return 0; |
361 | ||
362 | err_close_vmbus: | |
363 | vmbus_close(hv_dev->channel); | |
364 | err_free_mem: | |
365 | kfree(hv_serio); | |
366 | kfree(kbd_dev); | |
367 | return error; | |
368 | } | |
369 | ||
370 | static int hv_kbd_remove(struct hv_device *hv_dev) | |
371 | { | |
372 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); | |
373 | ||
374 | serio_unregister_port(kbd_dev->hv_serio); | |
375 | vmbus_close(hv_dev->channel); | |
376 | kfree(kbd_dev); | |
377 | ||
378 | hv_set_drvdata(hv_dev, NULL); | |
379 | ||
380 | return 0; | |
381 | } | |
382 | ||
aed06b9c S |
383 | static const struct hv_vmbus_device_id id_table[] = { |
384 | /* Keyboard guid */ | |
385 | { HV_KBD_GUID, }, | |
386 | { }, | |
387 | }; | |
388 | ||
389 | MODULE_DEVICE_TABLE(vmbus, id_table); | |
390 | ||
391 | static struct hv_driver hv_kbd_drv = { | |
392 | .name = KBUILD_MODNAME, | |
393 | .id_table = id_table, | |
394 | .probe = hv_kbd_probe, | |
395 | .remove = hv_kbd_remove, | |
af0a5646 AV |
396 | .driver = { |
397 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | |
398 | }, | |
aed06b9c S |
399 | }; |
400 | ||
401 | static int __init hv_kbd_init(void) | |
402 | { | |
403 | return vmbus_driver_register(&hv_kbd_drv); | |
404 | } | |
405 | ||
406 | static void __exit hv_kbd_exit(void) | |
407 | { | |
408 | vmbus_driver_unregister(&hv_kbd_drv); | |
409 | } | |
410 | ||
411 | MODULE_LICENSE("GPL"); | |
9d1c2f06 JS |
412 | MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Keyboard Driver"); |
413 | ||
aed06b9c S |
414 | module_init(hv_kbd_init); |
415 | module_exit(hv_kbd_exit); |