xref: /haiku/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
1 /*
2  * Copyright 2009-2011, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include <debug.h>
10 #include <debugger_keymaps.h>
11 
12 static bool sUseUSBKeyboard = false;
13 static uint8 sUSBTransferData[64];
14 static uint8 sLastTransferData[64];
15 static size_t sUSBTransferLength = 0;
16 static void *sUSBPipe = NULL;
17 
18 // simple ring buffer
19 static int sBufferedChars[32];
20 static uint8 sBufferSize = sizeof(sBufferedChars) / sizeof(sBufferedChars[0]);
21 static uint8 sBufferedCharCount = 0;
22 static uint8 sBufferWriteIndex = 0;
23 static uint8 sBufferReadIndex = 0;
24 
25 #define MODIFIER_CONTROL	0x01
26 #define MODIFIER_SHIFT		0x02
27 #define MODIFIER_ALT		0x04
28 
29 static uint32 sModifierTable[] = {
30 	MODIFIER_CONTROL,
31 	MODIFIER_SHIFT,
32 	MODIFIER_ALT,
33 	0,
34 	MODIFIER_CONTROL,
35 	MODIFIER_SHIFT,
36 	MODIFIER_ALT,
37 	0
38 };
39 
40 static uint8 sKeyTable[] = {
41 	0,	// ERROR
42 	0,	// ERROR
43 	0,	// ERROR
44 	0,	// ERROR
45 	30,	// A
46 	48,	// B
47 	46,	// C
48 	32,	// D
49 	18,	// E
50 	33,	// F
51 	34,	// G
52 	35,	// H
53 	23,	// I
54 	36,	// J
55 	37,	// K
56 	38,	// L
57 	50,	// M
58 	49,	// N
59 	24,	// O
60 	25,	// P
61 	16,	// Q
62 	19,	// R
63 	31,	// S
64 	20,	// T
65 	22,	// U
66 	47,	// V
67 	17,	// W
68 	45,	// X
69 	21,	// Y
70 	44,	// Z
71 	2,	// 1
72 	3,	// 2
73 	4,	// 3
74 	5,	// 4
75 	6,	// 5
76 	7,	// 6
77 	8,	// 7
78 	9,	// 8
79 	10,	// 9
80 	11,	// 0
81 	28,	// enter
82 	1,	// Esc
83 	14,	// Backspace
84 	15,	// Tab
85 	57,	// Space
86 	12,	// -
87 	13,	// =
88 	26,	// [
89 	27,	// ]
90 	43,	// backslash
91 	80,	// backslash
92 	39,	// ;
93 	40,	// '
94 	41,	// `
95 	51,	// ,
96 	52,	// .
97 	53,	// /
98 	0,	// Caps
99 	0,	// F1
100 	0,	// F2
101 	0,	// F3
102 	0,	// F4
103 	0,	// F5
104 	0,	// F6
105 	0,	// F7
106 	0,	// F8
107 	0,	// F9
108 	0,	// F10
109 	0,	// F11
110 	0,	// F12
111 	0,	// PrintScreen
112 	0,	// Scroll Lock
113 	0,	// Pause (0x7f with Ctrl)
114 	0,	// Insert
115 	0x80 | 'H',	// Home
116 	0x80 | '5',	// Page up
117 	0x80 | '3',	// Delete
118 	0x80 | 'F',	// End
119 	0x80 | '6',	// Page down
120 	0x80 | 'C',	// Right arrow
121 	0x80 | 'D',	// Left arrow
122 	0x80 | 'B',	// Down arrow
123 	0x80 | 'A',	// Up arrow
124 	0,	// Num Lock
125 	53,	// Pad /
126 	55,	// Pad *
127 	12,	// Pad -
128 	54,	// Pad +
129 	28,	// Pad Enter
130 	2,	// Pad 1
131 	3,	// Pad 2
132 	4,	// Pad 3
133 	5,	// Pad 4
134 	6,	// Pad 5
135 	7,	// Pad 6
136 	8,	// Pad 7
137 	9,	// Pad 8
138 	10,	// Pad 9
139 	11,	// Pad 0
140 	52,	// Pad .
141 	86,	// <
142 	0,	// Menu
143 	0,	// Power
144 	13	// Pad =
145 };
146 
147 static size_t sKeyTableSize = sizeof(sKeyTable) / sizeof(sKeyTable[0]);
148 
149 
150 static void
151 enter_debugger(void)
152 {
153 	if (!has_debugger_command("get_usb_keyboard_config")
154 		|| !has_debugger_command("get_usb_pipe_for_id")
155 		|| !has_debugger_command("usb_process_transfer")) {
156 		return;
157 	}
158 
159 	unset_debug_variable("_usbPipe");
160 	unset_debug_variable("_usbReportSize");
161 
162 	evaluate_debug_command("get_usb_keyboard_config");
163 	sUSBTransferLength = get_debug_variable("_usbReportSize", 0);
164 	if (sUSBTransferLength == 0 || sUSBTransferLength > sizeof(sUSBTransferData))
165 		return;
166 
167 	evaluate_debug_command("get_usb_pipe_for_id");
168 	sUSBPipe = (void *)get_debug_variable("_usbPipe", 0);
169 	if (sUSBPipe == NULL)
170 		return;
171 
172 	sUseUSBKeyboard = true;
173 }
174 
175 
176 static void
177 exit_debugger(void)
178 {
179 	if (sUseUSBKeyboard) {
180 		// make sure a possibly pending transfer is canceled
181 		set_debug_variable("_usbPipe", (uint64)sUSBPipe);
182 		evaluate_debug_command("usb_process_transfer cancel");
183 		sUseUSBKeyboard = false;
184 	}
185 }
186 
187 
188 static void
189 write_key(int key)
190 {
191 	sBufferedChars[sBufferWriteIndex++] = key;
192 	sBufferWriteIndex %= sBufferSize;
193 	sBufferedCharCount++;
194 }
195 
196 
197 static int
198 debugger_getchar(void)
199 {
200 	if (!sUseUSBKeyboard)
201 		return -1;
202 
203 	if (sBufferedCharCount == 0) {
204 		set_debug_variable("_usbPipe", (uint64)sUSBPipe);
205 		set_debug_variable("_usbTransferData", (uint64)sUSBTransferData);
206 		set_debug_variable("_usbTransferLength", (uint64)sUSBTransferLength);
207 
208 		status_t status = evaluate_debug_command("usb_process_transfer");
209 		if (status == B_DEV_PENDING)
210 			return -1;
211 
212 		if (status != B_OK) {
213 			// try clearing a possibly set halt due to toggle mismatches
214 			evaluate_debug_command("usb_clear_stall");
215 			return -1;
216 		}
217 
218 		bool phantomState = true;
219 		for (size_t i = 2; i < sUSBTransferLength; i++) {
220 			if (sUSBTransferData[i] != 0x01) {
221 				phantomState = false;
222 				break;
223 			}
224 		}
225 
226 		if (phantomState)
227 			return -1;
228 
229 		uint8 modifiers = 0;
230 		for (uint32 i = 0; i < 8; i++) {
231 			if (sUSBTransferData[0] & (1 << i))
232 				modifiers |= sModifierTable[i];
233 		}
234 
235 		uint8 *current = sUSBTransferData;
236 		uint8 *compare = sLastTransferData;
237 		for (uint32 i = 2; i < sUSBTransferLength; i++) {
238 			if (current[i] == 0x00 || current[i] == 0x01)
239 				continue;
240 
241 			bool found = false;
242 			for (uint32 j = 2; j < sUSBTransferLength; j++) {
243 				if (compare[j] == current[i]) {
244 					found = true;
245 					break;
246 				}
247 			}
248 
249 			if (found)
250 				continue;
251 
252 			if (current[i] >= sKeyTableSize)
253 				continue;
254 
255 			int result = -1;
256 			uint8 key = sKeyTable[current[i]];
257 			if (key & 0x80) {
258 				write_key(27);
259 				write_key('[');
260 
261 				key &= ~0x80;
262 				write_key(key);
263 
264 				if (key == '5' || key == '6' || key == '3')
265 					write_key('~');
266 
267 				continue;
268 			} else if (modifiers & MODIFIER_CONTROL) {
269 				char c = kShiftedKeymap[key];
270 				if (c >= 'A' && c <= 'Z')
271 					result = 0x1f & c;
272 			} else if (modifiers & MODIFIER_ALT)
273 				result = kAltedKeymap[key];
274 			else if (modifiers & MODIFIER_SHIFT)
275 				result = kShiftedKeymap[key];
276 			else
277 				result = kUnshiftedKeymap[key];
278 
279 			if (result < 0)
280 				continue;
281 
282 			write_key(result);
283 		}
284 
285 		for (uint32 i = 0; i < sUSBTransferLength; i++)
286 			sLastTransferData[i] = sUSBTransferData[i];
287 	}
288 
289 	if (sBufferedCharCount == 0)
290 		return -1;
291 
292 	int result = sBufferedChars[sBufferReadIndex++];
293 	sBufferReadIndex %= sBufferSize;
294 	sBufferedCharCount--;
295 	return result;
296 }
297 
298 
299 static status_t
300 std_ops(int32 op, ...)
301 {
302 	if (op == B_MODULE_INIT || op == B_MODULE_UNINIT)
303 		return B_OK;
304 
305 	return B_BAD_VALUE;
306 }
307 
308 
309 static struct debugger_module_info sModuleInfo = {
310 	{
311 		"debugger/usb_keyboard/v1",
312 		0,
313 		&std_ops
314 	},
315 
316 	&enter_debugger,
317 	&exit_debugger,
318 	NULL,
319 	&debugger_getchar
320 };
321 
322 module_info *modules[] = {
323 	(module_info *)&sModuleInfo,
324 	NULL
325 };
326 
327