1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fcntl.h>
6 #include <poll.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <fuchsia/hardware/input/c/fidl.h>
12 #include <hid/hid.h>
13 #include <hid/usages.h>
14 #include <lib/fzl/fdio.h>
15 #include <zircon/syscalls.h>
16 
17 #include <port/port.h>
18 
19 #include <utility>
20 
21 #include "keyboard.h"
22 
23 #define LOW_REPEAT_KEY_FREQ 250000000
24 #define HIGH_REPEAT_KEY_FREQ 50000000
25 
modifiers_from_keycode(uint8_t keycode)26 static int modifiers_from_keycode(uint8_t keycode) {
27     switch (keycode) {
28     case HID_USAGE_KEY_LEFT_SHIFT:
29         return MOD_LSHIFT;
30     case HID_USAGE_KEY_RIGHT_SHIFT:
31         return MOD_RSHIFT;
32     case HID_USAGE_KEY_LEFT_ALT:
33         return MOD_LALT;
34     case HID_USAGE_KEY_RIGHT_ALT:
35         return MOD_RALT;
36     case HID_USAGE_KEY_LEFT_CTRL:
37         return MOD_LCTRL;
38     case HID_USAGE_KEY_RIGHT_CTRL:
39         return MOD_RCTRL;
40     }
41     return 0;
42 }
43 
set_caps_lock_led(int keyboard_fd,bool caps_lock)44 static void set_caps_lock_led(int keyboard_fd, bool caps_lock) {
45     // The following bit to set is specified in "Device Class Definition
46     // for Human Interface Devices (HID)", Version 1.11,
47     // http://www.usb.org/developers/hidpage/HID1_11.pdf.  Zircon leaves
48     // USB keyboards in boot mode, so the relevant section is Appendix B,
49     // "Boot Interface Descriptors", "B.1 Protocol 1 (Keyboard)".
50     const uint8_t kUsbCapsLockBit = 1 << 1;
51     const uint8_t report_body[1] = { static_cast<uint8_t>(caps_lock ? kUsbCapsLockBit : 0) };
52 
53     // Temporarily wrap keyboard_fd, we will release it after the call so we don't close it.
54     fzl::FdioCaller caller{fbl::unique_fd(keyboard_fd)};
55     zx_status_t call_status;
56     zx_status_t status = fuchsia_hardware_input_DeviceSetReport(
57         caller.borrow_channel(), fuchsia_hardware_input_ReportType_OUTPUT, 0, report_body,
58         sizeof(report_body), &call_status);
59     caller.release().release();
60     if (status != ZX_OK || call_status != ZX_OK) {
61 #if !BUILD_FOR_TEST
62         printf("fuchsia.hardware.input.Device.SetReport() failed (returned %d, %d)\n", status,
63                call_status);
64 #endif
65     }
66 }
67 
68 struct vc_input {
69     port_fd_handler_t fh;
70     port_handler_t th;
71     zx_handle_t timer;
72 
73     keypress_handler_t handler;
74     int fd;
75 
76     uint8_t previous_report_buf[8];
77     uint8_t report_buf[8];
78     hid_keys_t state[2];
79     int cur_idx;
80     int prev_idx;
81     int modifiers;
82     uint64_t repeat_interval;
83     bool repeat_enabled;
84 };
85 
86 // returns true if key was pressed and none were released
vc_input_process(vc_input_t * vi,uint8_t report[8])87 bool vc_input_process(vc_input_t* vi, uint8_t report[8]) {
88     bool do_repeat = false;
89 
90     // process the key
91     uint8_t keycode;
92     hid_keys_t keys;
93 
94     hid_kbd_parse_report(report, &vi->state[vi->cur_idx]);
95 
96     hid_kbd_pressed_keys(&vi->state[vi->prev_idx], &vi->state[vi->cur_idx], &keys);
97     hid_for_every_key(&keys, keycode) {
98         vi->modifiers |= modifiers_from_keycode(keycode);
99         if (keycode == HID_USAGE_KEY_CAPSLOCK) {
100             vi->modifiers ^= MOD_CAPSLOCK;
101             set_caps_lock_led(vi->fd, vi->modifiers & MOD_CAPSLOCK);
102         }
103         vi->handler(keycode, vi->modifiers);
104         do_repeat = true;
105     }
106 
107     hid_kbd_released_keys(&vi->state[vi->prev_idx], &vi->state[vi->cur_idx], &keys);
108     hid_for_every_key(&keys, keycode) {
109         vi->modifiers &= ~modifiers_from_keycode(keycode);
110         do_repeat = false;
111     }
112 
113     // swap key states
114     vi->cur_idx = 1 - vi->cur_idx;
115     vi->prev_idx = 1 - vi->prev_idx;
116 
117     return do_repeat;
118 }
119 
120 #if !BUILD_FOR_TEST
vc_input_destroy(vc_input_t * vi)121 static void vc_input_destroy(vc_input_t* vi) {
122     port_cancel(&port, &vi->th);
123     if (vi->fd >= 0) {
124         port_fd_handler_done(&vi->fh);
125         close(vi->fd);
126     }
127     zx_handle_close(vi->timer);
128     free(vi);
129 }
130 
vc_timer_cb(port_handler_t * ph,zx_signals_t signals,uint32_t evt)131 static zx_status_t vc_timer_cb(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
132     vc_input_t* vi = containerof(ph, vc_input_t, th);
133 
134     // if interval is infinite, repeat was canceled
135     if (vi->repeat_interval != ZX_TIME_INFINITE) {
136         vc_input_process(vi, vi->previous_report_buf);
137         vc_input_process(vi, vi->report_buf);
138 
139         // increase repeat rate if we're not yet at the fastest rate
140         if ((vi->repeat_interval = vi->repeat_interval * 3 / 4) < HIGH_REPEAT_KEY_FREQ) {
141             vi->repeat_interval = HIGH_REPEAT_KEY_FREQ;
142         }
143 
144         zx_timer_set(vi->timer, zx_deadline_after(vi->repeat_interval), 0);
145     }
146 
147     // return non-OK to avoid needlessly re-arming the repeating wait
148     return ZX_ERR_NEXT;
149 }
150 
vc_input_cb(port_fd_handler_t * fh,unsigned pollevt,uint32_t evt)151 static zx_status_t vc_input_cb(port_fd_handler_t* fh, unsigned pollevt, uint32_t evt) {
152     vc_input_t* vi = containerof(fh, vc_input_t, fh);
153     ssize_t r;
154 
155     if (!(pollevt & POLLIN)) {
156         r = ZX_ERR_PEER_CLOSED;
157     } else {
158         memcpy(vi->previous_report_buf, vi->report_buf, sizeof(vi->report_buf));
159         r = read(vi->fd, vi->report_buf, sizeof(vi->report_buf));
160     }
161     if (r <= 0) {
162         vc_input_destroy(vi);
163         return ZX_ERR_STOP;
164     }
165     if ((size_t)(r) != sizeof(vi->report_buf)) {
166         vi->repeat_interval = ZX_TIME_INFINITE;
167         return ZX_OK;
168     }
169 
170     if (vc_input_process(vi, vi->report_buf) && vi->repeat_enabled) {
171         vi->repeat_interval = LOW_REPEAT_KEY_FREQ;
172         zx_timer_set(vi->timer, zx_deadline_after(vi->repeat_interval), 0);
173     } else {
174         vi->repeat_interval = ZX_TIME_INFINITE;
175     }
176     return ZX_OK;
177 }
178 #endif
179 
vc_input_create(vc_input_t ** out,keypress_handler_t handler,int fd)180 zx_status_t vc_input_create(vc_input_t** out, keypress_handler_t handler, int fd) {
181     vc_input_t* vi = reinterpret_cast<vc_input_t*>(calloc(1, sizeof(vc_input_t)));
182     if (vi == NULL) {
183         return ZX_ERR_NO_MEMORY;
184     }
185 
186     vi->fd = fd;
187     vi->handler = handler;
188 
189     vi->cur_idx = 0;
190     vi->prev_idx = 1;
191     vi->modifiers = 0;
192     vi->repeat_interval = ZX_TIME_INFINITE;
193     vi->repeat_enabled = true;
194 
195     char* flag = getenv("virtcon.keyrepeat");
196     if (flag && (!strcmp(flag, "0") || !strcmp(flag, "false"))) {
197         printf("vc: Key repeat disabled\n");
198         vi->repeat_enabled = false;
199     }
200 
201 #if !BUILD_FOR_TEST
202     zx_status_t r;
203     if ((r = zx_timer_create(0, ZX_CLOCK_MONOTONIC, &vi->timer)) < 0) {
204         free(vi);
205         return r;
206     }
207 
208     vi->fh.func = vc_input_cb;
209     if ((r = port_fd_handler_init(&vi->fh, fd, POLLIN | POLLHUP | POLLRDHUP)) < 0) {
210         zx_handle_close(vi->timer);
211         free(vi);
212         return r;
213     }
214 
215     if ((r = port_wait(&port, &vi->fh.ph)) < 0) {
216         port_fd_handler_done(&vi->fh);
217         zx_handle_close(vi->timer);
218         free(vi);
219         return r;
220     }
221 
222     vi->th.handle = vi->timer;
223     vi->th.waitfor = ZX_TIMER_SIGNALED;
224     vi->th.func = vc_timer_cb;
225     port_wait_repeating(&port, &vi->th);
226 #endif
227 
228     *out = vi;
229     return ZX_OK;
230 }
231 
232 #if !BUILD_FOR_TEST
new_input_device(int fd,keypress_handler_t handler)233 zx_status_t new_input_device(int fd, keypress_handler_t handler) {
234     // test to see if this is a device we can read
235     uint32_t proto = fuchsia_hardware_input_BootProtocol_NONE;
236 
237     // Temporarily wrap fd, we will release it after the call so we don't close it.
238     fzl::FdioCaller caller{fbl::unique_fd(fd)};
239     zx_status_t status =
240         fuchsia_hardware_input_DeviceGetBootProtocol(caller.borrow_channel(), &proto);
241     caller.release().release();
242     if ((status != ZX_OK) || (proto != fuchsia_hardware_input_BootProtocol_KBD)) {
243         // skip devices that aren't keyboards
244         close(fd);
245         return ZX_ERR_NOT_SUPPORTED;
246     }
247 
248     vc_input_t* vi;
249     if ((status = vc_input_create(&vi, handler, fd)) < 0) {
250         close(fd);
251     }
252     return status;
253 }
254 #endif
255