-
Notifications
You must be signed in to change notification settings - Fork 3
/
hid.c
177 lines (158 loc) · 3.83 KB
/
hid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include "hid.h"
/* The protocol the keyboard is using at the moment */
static volatile uint8_t keyboard_protocol = BOOT_PROTOCOL;
/* the idle configuration, how often we send the report to the
* host (ms * 4) even when it hasn't changed */
static volatile uint16_t keyboard_idle_config=500;
/* countdown until idle timeout */
static volatile uint16_t keyboard_idle_countdown=500;
static volatile bool keyboard_send_now = false;
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
static volatile uint8_t keyboard_leds = 0;
static volatile bool leds_changed = false;
static volatile uint8_t six_keys[6] = {0};
static volatile uint8_t mods = 0;
void HID_send_boot_report()
{
/* Send byte 28 of key_map, which is the state of modifiers */
USB_IN_write_byte(mods);
/* send reserved byte (0) */
USB_IN_write_byte(0x00);
USB_IN_write_buffer((void*)six_keys, 6);
}
void HID_send_report()
{
switch (keyboard_protocol) {
#if 0
case REPORT_PROTOCOL:
USB_IN_write_buffer((void*)key_map, 32);
break;
#endif
case BOOT_PROTOCOL:
HID_send_boot_report();
break;
default:
break;
}
}
/* [Callbacks section] ----------------------------------------------------- */
bool HID_handle_control_request(struct setup_packet *s)
{
if (request_type(s, DIRECTION, DEVICE_TO_HOST)) {
USB_wait_IN();
switch (s->bRequest) {
case HID_GET_REPORT:
HID_send_report();
break;
case HID_GET_IDLE:
USB_IN_write_byte(keyboard_idle_config);
break;
case HID_GET_PROTOCOL:
USB_IN_write_byte(keyboard_protocol);
break;
default:
return false;
}
USB_flush_IN();
} else {
switch(s->bRequest) {
case HID_SET_REPORT:
USB_wait_OUT();
keyboard_leds = USB_OUT_read_byte();
leds_changed = true;
USB_flush_OUT();
break;
case HID_SET_IDLE:
keyboard_idle_config = (s->wValue >> 8);
keyboard_idle_countdown = keyboard_idle_config;
break;
case HID_SET_PROTOCOL:
keyboard_protocol = s->wValue;
break;
default:
return false;
}
}
return true;
}
void HID_handle_sof()
{
if (!USB_get_configuration())
return;
bool should_send = keyboard_send_now ||
(keyboard_idle_config != 0 && keyboard_idle_countdown == 0);
if (!should_send)
return;
USB_set_endpoint(KEYBOARD_ENDPOINT);
/* substitute data to be sent with new version if last buffer has not
* been sent */
if (!USB_IN_ready())
USB_kill_banks();
HID_send_report();
USB_flush_IN();
keyboard_send_now = false;
keyboard_idle_countdown = keyboard_idle_config;
}
/* [/Callbacks section] ---------------------------------------------------- */
/* [API section] ----------------------------------------------------------- */
#if 0
/* Checks if a key is pressed */
bool HID_scancode_is_pressed(uint8_t code)
{
uint8_t byte_no = code / 8;
uint8_t bit_no = code & 0x07;
return key_map[byte_no] & _BV(bit_no);
}
#endif
void HID_set_scancode_state(uint8_t code, bool state)
{
#if 0
uint8_t byte_no = code / 8;
uint8_t bit_no = code & 0x07;
if (state == false)
key_map[byte_no] &= ~_BV(bit_no);
else
key_map[byte_no] |= _BV(bit_no);
#endif
/* The part below is not tested! */
if (keyboard_protocol == BOOT_PROTOCOL) {
if (code / 8 == 28) {
if (state)
mods |= _BV(code & 0x07);
else
mods &= ~_BV(code & 0x07);
}
if (state == true) {
uint8_t pos = 0;
for (; pos < 6 && six_keys[pos] != 0; ++pos)
;
if (pos < 6)
six_keys[pos] = code;
} else {
uint8_t pos = 0;
for (; pos < 6 && six_keys[pos] != code; ++pos)
;
if (pos < 6)
six_keys[pos] = 0;
}
}
}
/* send the contents of keyboard_keys and keyboard_modifier_keys */
void HID_commit_state()
{
keyboard_send_now = true;
}
uint8_t HID_get_leds()
{
return keyboard_leds;
}
uint8_t HID_leds_changed()
{
if (leds_changed) {
leds_changed = false;
return true;
} else {
return false;
}
}
/* [/API section] ---------------------------------------------------------- */