-
Notifications
You must be signed in to change notification settings - Fork 13
/
hid.c
189 lines (168 loc) · 4.56 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
178
179
180
181
182
183
184
185
186
187
188
189
/* This file is part of ukbdc.
*
* ukbdc is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ukbdc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ukbdc; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hid.h"
#include "system.h"
/* The protocol the keyboard is using at the moment */
static volatile uint8_t keyboard_protocol = REPORT_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;
/* 256-bit HID report to send to the host */
static volatile uint8_t key_map[32] = {0};
static volatile uint8_t six_keys[6] = {0};
void HID_send_boot_report()
{
/* Send byte 28 of key_map, which is the state of modifiers */
USB_IN_write_byte(key_map[28]);
/* send reserved byte (0) */
USB_IN_write_byte(0x00);
USB_IN_write_buffer((void*)six_keys, 6);
}
void HID_send_report()
{
switch (keyboard_protocol) {
case REPORT_PROTOCOL:
USB_IN_write_buffer((void*)key_map, 32);
break;
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(void *data)
{
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] ----------------------------------------------------------- */
void HID_init()
{
SYSTEM_subscribe(USB_SOF, ANY, HID_handle_sof);
}
/* 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);
}
void HID_set_scancode_state(uint8_t code, bool state)
{
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);
/* The part below is not tested! */
if (keyboard_protocol == BOOT_PROTOCOL) {
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] ---------------------------------------------------------- */