1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2013, Microsoft Corporation. |
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 ; |
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 ; |
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 ; |
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 ; |
70 | __le16 make_code; |
71 | __le16 reserved0; |
72 | __le32 info; /* Additional information */ |
73 | }; |
74 | |
75 | |
76 | #define HK_MAXIMUM_MESSAGE_SIZE 256 |
77 | |
78 | #define KBD_VSC_SEND_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024) |
79 | #define KBD_VSC_RECV_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024) |
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(dev: 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(serio: kbd_dev->hv_serio, |
154 | XTKBD_EMUL0, flags: 0); |
155 | if (info & IS_E1) |
156 | serio_interrupt(serio: kbd_dev->hv_serio, |
157 | XTKBD_EMUL1, flags: 0); |
158 | scan_code = __le16_to_cpu(ks_msg->make_code); |
159 | if (info & IS_BREAK) |
160 | scan_code |= XTKBD_RELEASE; |
161 | |
162 | serio_interrupt(serio: kbd_dev->hv_serio, data: scan_code, flags: 0); |
163 | } |
164 | spin_unlock_irqrestore(lock: &kbd_dev->lock, flags); |
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)) |
172 | pm_wakeup_hard_event(dev: &hv_dev->device); |
173 | |
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_length: 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 | { |
240 | struct vmpacket_descriptor *desc; |
241 | struct hv_device *hv_dev = context; |
242 | u32 bytes_recvd; |
243 | u64 req_id; |
244 | |
245 | foreach_vmbus_pkt(desc, hv_dev->channel) { |
246 | bytes_recvd = desc->len8 * 8; |
247 | req_id = desc->trans_id; |
248 | |
249 | hv_kbd_handle_received_packet(hv_dev, desc, bytes_recvd, |
250 | req_id); |
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(dev: 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 | reinit_completion(x: &kbd_dev->wait_event); |
263 | |
264 | request = &kbd_dev->protocol_req; |
265 | memset(request, 0, sizeof(struct synth_kbd_protocol_request)); |
266 | request->header.type = __cpu_to_le32(SYNTH_KBD_PROTOCOL_REQUEST); |
267 | request->version_requested.version = __cpu_to_le32(SYNTH_KBD_VERSION); |
268 | |
269 | error = vmbus_sendpacket(channel: hv_dev->channel, buffer: request, |
270 | bufferLen: sizeof(struct synth_kbd_protocol_request), |
271 | requestid: (unsigned long)request, |
272 | type: VM_PKT_DATA_INBAND, |
273 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
274 | if (error) |
275 | return error; |
276 | |
277 | if (!wait_for_completion_timeout(x: &kbd_dev->wait_event, timeout: 10 * HZ)) |
278 | return -ETIMEDOUT; |
279 | |
280 | response = &kbd_dev->protocol_resp; |
281 | proto_status = __le32_to_cpu(response->proto_status); |
282 | if (!(proto_status & PROTOCOL_ACCEPTED)) { |
283 | dev_err(&hv_dev->device, |
284 | "synth_kbd protocol request failed (version %d)\n" , |
285 | SYNTH_KBD_VERSION); |
286 | return -ENODEV; |
287 | } |
288 | |
289 | return 0; |
290 | } |
291 | |
292 | static int hv_kbd_start(struct serio *serio) |
293 | { |
294 | struct hv_kbd_dev *kbd_dev = serio->port_data; |
295 | unsigned long flags; |
296 | |
297 | spin_lock_irqsave(&kbd_dev->lock, flags); |
298 | kbd_dev->started = true; |
299 | spin_unlock_irqrestore(lock: &kbd_dev->lock, flags); |
300 | |
301 | return 0; |
302 | } |
303 | |
304 | static void hv_kbd_stop(struct serio *serio) |
305 | { |
306 | struct hv_kbd_dev *kbd_dev = serio->port_data; |
307 | unsigned long flags; |
308 | |
309 | spin_lock_irqsave(&kbd_dev->lock, flags); |
310 | kbd_dev->started = false; |
311 | spin_unlock_irqrestore(lock: &kbd_dev->lock, flags); |
312 | } |
313 | |
314 | static int hv_kbd_probe(struct hv_device *hv_dev, |
315 | const struct hv_vmbus_device_id *dev_id) |
316 | { |
317 | struct hv_kbd_dev *kbd_dev; |
318 | struct serio *hv_serio; |
319 | int error; |
320 | |
321 | kbd_dev = kzalloc(size: sizeof(struct hv_kbd_dev), GFP_KERNEL); |
322 | hv_serio = kzalloc(size: sizeof(struct serio), GFP_KERNEL); |
323 | if (!kbd_dev || !hv_serio) { |
324 | error = -ENOMEM; |
325 | goto err_free_mem; |
326 | } |
327 | |
328 | kbd_dev->hv_dev = hv_dev; |
329 | kbd_dev->hv_serio = hv_serio; |
330 | spin_lock_init(&kbd_dev->lock); |
331 | init_completion(x: &kbd_dev->wait_event); |
332 | hv_set_drvdata(dev: hv_dev, data: kbd_dev); |
333 | |
334 | hv_serio->dev.parent = &hv_dev->device; |
335 | hv_serio->id.type = SERIO_8042_XL; |
336 | hv_serio->port_data = kbd_dev; |
337 | strscpy(p: hv_serio->name, q: dev_name(dev: &hv_dev->device), |
338 | size: sizeof(hv_serio->name)); |
339 | strscpy(p: hv_serio->phys, q: dev_name(dev: &hv_dev->device), |
340 | size: sizeof(hv_serio->phys)); |
341 | |
342 | hv_serio->start = hv_kbd_start; |
343 | hv_serio->stop = hv_kbd_stop; |
344 | |
345 | error = vmbus_open(channel: hv_dev->channel, |
346 | KBD_VSC_SEND_RING_BUFFER_SIZE, |
347 | KBD_VSC_RECV_RING_BUFFER_SIZE, |
348 | NULL, userdatalen: 0, |
349 | onchannel_callback: hv_kbd_on_channel_callback, |
350 | context: hv_dev); |
351 | if (error) |
352 | goto err_free_mem; |
353 | |
354 | error = hv_kbd_connect_to_vsp(hv_dev); |
355 | if (error) |
356 | goto err_close_vmbus; |
357 | |
358 | serio_register_port(kbd_dev->hv_serio); |
359 | |
360 | device_init_wakeup(dev: &hv_dev->device, enable: true); |
361 | |
362 | return 0; |
363 | |
364 | err_close_vmbus: |
365 | vmbus_close(channel: hv_dev->channel); |
366 | err_free_mem: |
367 | kfree(objp: hv_serio); |
368 | kfree(objp: kbd_dev); |
369 | return error; |
370 | } |
371 | |
372 | static void hv_kbd_remove(struct hv_device *hv_dev) |
373 | { |
374 | struct hv_kbd_dev *kbd_dev = hv_get_drvdata(dev: hv_dev); |
375 | |
376 | serio_unregister_port(serio: kbd_dev->hv_serio); |
377 | vmbus_close(channel: hv_dev->channel); |
378 | kfree(objp: kbd_dev); |
379 | |
380 | hv_set_drvdata(dev: hv_dev, NULL); |
381 | } |
382 | |
383 | static int hv_kbd_suspend(struct hv_device *hv_dev) |
384 | { |
385 | vmbus_close(channel: hv_dev->channel); |
386 | |
387 | return 0; |
388 | } |
389 | |
390 | static int hv_kbd_resume(struct hv_device *hv_dev) |
391 | { |
392 | int ret; |
393 | |
394 | ret = vmbus_open(channel: hv_dev->channel, |
395 | KBD_VSC_SEND_RING_BUFFER_SIZE, |
396 | KBD_VSC_RECV_RING_BUFFER_SIZE, |
397 | NULL, userdatalen: 0, |
398 | onchannel_callback: hv_kbd_on_channel_callback, |
399 | context: hv_dev); |
400 | if (ret == 0) |
401 | ret = hv_kbd_connect_to_vsp(hv_dev); |
402 | |
403 | return ret; |
404 | } |
405 | |
406 | static const struct hv_vmbus_device_id id_table[] = { |
407 | /* Keyboard guid */ |
408 | { HV_KBD_GUID, }, |
409 | { }, |
410 | }; |
411 | |
412 | MODULE_DEVICE_TABLE(vmbus, id_table); |
413 | |
414 | static struct hv_driver hv_kbd_drv = { |
415 | .name = KBUILD_MODNAME, |
416 | .id_table = id_table, |
417 | .probe = hv_kbd_probe, |
418 | .remove = hv_kbd_remove, |
419 | .suspend = hv_kbd_suspend, |
420 | .resume = hv_kbd_resume, |
421 | .driver = { |
422 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
423 | }, |
424 | }; |
425 | |
426 | static int __init hv_kbd_init(void) |
427 | { |
428 | return vmbus_driver_register(&hv_kbd_drv); |
429 | } |
430 | |
431 | static void __exit hv_kbd_exit(void) |
432 | { |
433 | vmbus_driver_unregister(hv_driver: &hv_kbd_drv); |
434 | } |
435 | |
436 | MODULE_LICENSE("GPL" ); |
437 | MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Keyboard Driver" ); |
438 | |
439 | module_init(hv_kbd_init); |
440 | module_exit(hv_kbd_exit); |
441 | |