blob: f7679f9e852396315cf0d838a25135facad47e8e [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/status.h>
#include <iterator>
#include <ddk/debug.h>
#include <fbl/algorithm.h>
#include "input.h"
#include "src/devices/bus/lib/virtio/trace.h"
#define LOCAL_TRACE 0
namespace virtio {
// clang-format off
// These are Linux input event codes:
// https://github.com/torvalds/linux/blob/HEAD/include/uapi/linux/input-event-codes.h
const uint8_t kEventCodeMap[] = {
0, // KEY_RESERVED (0)
41, // KEY_ESC (1)
30, // KEY_1 (2)
31, // KEY_2 (3)
32, // KEY_3 (4)
33, // KEY_4 (5)
34, // KEY_5 (6)
35, // KEY_6 (7)
36, // KEY_7 (8)
37, // KEY_8 (9)
38, // KEY_9 (10)
39, // KEY_0 (11)
45, // KEY_MINUS (12)
46, // KEY_EQUAL (13)
42, // KEY_BACKSPACE (14)
43, // KEY_TAB (15)
20, // KEY_Q (16)
26, // KEY_W (17)
8, // KEY_E (18)
21, // KEY_R (19)
23, // KEY_T (20)
28, // KEY_Y (21)
24, // KEY_U (22)
12, // KEY_I (23)
18, // KEY_O (24)
19, // KEY_P (25)
47, // KEY_LEFTBRACE (26)
48, // KEY_RIGHTBRACE (27)
40, // KEY_ENTER (28)
224, // KEY_LEFTCTRL (29)
4, // KEY_A (30)
22, // KEY_S (31)
7, // KEY_D (32)
9, // KEY_F (33)
10, // KEY_G (34)
11, // KEY_H (35)
13, // KEY_J (36)
14, // KEY_K (37)
15, // KEY_L (38)
51, // KEY_SEMICOLON (39)
52, // KEY_APOSTROPHE (40)
53, // KEY_GRAVE (41)
225, // KEY_LEFTSHIFT (42)
49, // KEY_BACKSLASH (43)
29, // KEY_Z (44)
27, // KEY_X (45)
6, // KEY_C (46)
25, // KEY_V (47)
5, // KEY_B (48)
17, // KEY_N (49)
16, // KEY_M (50)
54, // KEY_COMMA (51)
55, // KEY_DOT (52)
56, // KEY_SLASH (53)
229, // KEY_RIGHTSHIFT (54)
85, // KEY_KPASTERISK (55)
226, // KEY_LEFTALT (56)
44, // KEY_SPACE (57)
57, // KEY_CAPSLOCK (58)
58, // KEY_F1 (59)
59, // KEY_F2 (60)
60, // KEY_F3 (61)
61, // KEY_F4 (62)
62, // KEY_F5 (63)
63, // KEY_F6 (64)
64, // KEY_F7 (65)
65, // KEY_F8 (66)
66, // KEY_F9 (67)
67, // KEY_F10 (68)
83, // KEY_NUMLOCK (69)
71, // KEY_SCROLLLOCK (70)
95, // KEY_KP7 (71)
96, // KEY_KP8 (72)
97, // KEY_KP9 (73)
86, // KEY_KPMINUS (74)
92, // KEY_KP4 (75)
93, // KEY_KP5 (76)
94, // KEY_KP6 (77)
87, // KEY_KPPLUS (78)
89, // KEY_KP1 (79)
90, // KEY_KP2 (80)
91, // KEY_KP3 (81)
98, // KEY_KP0 (82)
99, // KEY_KPDOT (83)
0, 0, 0, 0, 0, 0, // Unsupported
0, 0, 0, 0, 0, 0, 0, // Unsupported
228, // KEY_RIGHTCTRL (97)
0, 0, // Unsupported
230, // KEY_RIGHTALT (100)
0, 0, // Unsupported
82, // KEY_UP (103)
0, // Unsupported
80, // KEY_LEFT (105)
79, // KEY_RIGHT (106)
0, // Unsupported
81, // KEY_DOWN (108)
78, // KEY_PAGEDOWN (109)
73, // KEY_INSERT (110)
76, // KEY_DELETE (111)
0, 0, 0, 0, 0, 0, 0, // Unsupported
72, // KEY_PAUSE (119)
0, 0, 0, 0, 0, // Unsupported
227, // KEY_LEFTMETA (125)
231, // KEY_RIGHTMETA (126)
};
static const uint8_t kbd_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,
// Non-volatile)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,
// Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
};
// clang-format on
zx_status_t HidKeyboard::GetDescriptor(uint8_t desc_type, void* out_data_buffer, size_t data_size,
size_t* out_data_actual) {
if (out_data_buffer == nullptr || out_data_actual == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
if (desc_type != HID_DESCRIPTION_TYPE_REPORT) {
return ZX_ERR_NOT_FOUND;
}
if (data_size < sizeof(kbd_hid_report_desc)) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
memcpy(out_data_buffer, kbd_hid_report_desc, sizeof(kbd_hid_report_desc));
*out_data_actual = sizeof(kbd_hid_report_desc);
return ZX_OK;
}
void HidKeyboard::AddKeypressToReport(uint16_t event_code) {
uint8_t hid_code = kEventCodeMap[event_code];
for (size_t i = 0; i != 6; ++i) {
if (report_.usage[i] == hid_code) {
// The key already exists in the report so we ignore it.
return;
}
if (report_.usage[i] == 0) {
report_.usage[i] = hid_code;
return;
}
}
// There's no free slot in the report.
// TODO: Record a rollover status.
}
void HidKeyboard::RemoveKeypressFromReport(uint16_t event_code) {
uint8_t hid_code = kEventCodeMap[event_code];
int id = -1;
for (int i = 0; i != 6; ++i) {
if (report_.usage[i] == hid_code) {
id = i;
break;
}
}
if (id == -1) {
// They key is not in the report so we ignore it.
return;
}
for (size_t i = id; i != 5; ++i) {
report_.usage[i] = report_.usage[i + 1];
}
report_.usage[5] = 0;
}
void HidKeyboard::ReceiveEvent(virtio_input_event_t* event) {
if (event->type != VIRTIO_INPUT_EV_KEY) {
return;
}
if (event->code == 0) {
return;
}
if (event->code >= std::size(kEventCodeMap)) {
LTRACEF("unknown key\n");
return;
}
if (event->value == VIRTIO_INPUT_EV_KEY_PRESSED) {
AddKeypressToReport(event->code);
} else if (event->value == VIRTIO_INPUT_EV_KEY_RELEASED) {
RemoveKeypressFromReport(event->code);
}
}
const uint8_t* HidKeyboard::GetReport(size_t* size) {
*size = sizeof(report_);
return reinterpret_cast<const uint8_t*>(&report_);
}
} // namespace virtio