xref: /haiku/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp (revision a6e73cb9e8addfe832c064bfcb68067f1c2fa3eb)
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("uhci_process_transfer")
156 			&& !has_debugger_command("ohci_process_transfer")))
157 		return;
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("uhci_process_transfer cancel");
183 
184 		sUseUSBKeyboard = false;
185 	}
186 }
187 
188 
189 static void
190 write_key(int key)
191 {
192 	sBufferedChars[sBufferWriteIndex++] = key;
193 	sBufferWriteIndex %= sBufferSize;
194 	sBufferedCharCount++;
195 }
196 
197 
198 static int
199 debugger_getchar(void)
200 {
201 	if (!sUseUSBKeyboard)
202 		return -1;
203 
204 	if (sBufferedCharCount == 0) {
205 		set_debug_variable("_usbPipe", (uint64)sUSBPipe);
206 		set_debug_variable("_usbTransferData", (uint64)sUSBTransferData);
207 		set_debug_variable("_usbTransferLength", (uint64)sUSBTransferLength);
208 		if (evaluate_debug_command("uhci_process_transfer") != 0)
209 			return -1;
210 
211 		bool phantomState = true;
212 		for (size_t i = 2; i < sUSBTransferLength; i++) {
213 			if (sUSBTransferData[i] != 0x01) {
214 				phantomState = false;
215 				break;
216 			}
217 		}
218 
219 		if (phantomState)
220 			return -1;
221 
222 		uint8 modifiers = 0;
223 		for (uint32 i = 0; i < 8; i++) {
224 			if (sUSBTransferData[0] & (1 << i))
225 				modifiers |= sModifierTable[i];
226 		}
227 
228 		uint8 *current = sUSBTransferData;
229 		uint8 *compare = sLastTransferData;
230 		for (uint32 i = 2; i < sUSBTransferLength; i++) {
231 			if (current[i] == 0x00 || current[i] == 0x01)
232 				continue;
233 
234 			bool found = false;
235 			for (uint32 j = 2; j < sUSBTransferLength; j++) {
236 				if (compare[j] == current[i]) {
237 					found = true;
238 					break;
239 				}
240 			}
241 
242 			if (found)
243 				continue;
244 
245 			if (current[i] >= sKeyTableSize)
246 				continue;
247 
248 			int result = -1;
249 			uint8 key = sKeyTable[current[i]];
250 			if (key & 0x80) {
251 				write_key(27);
252 				write_key('[');
253 
254 				key &= ~0x80;
255 				write_key(key);
256 
257 				if (key == '5' || key == '6' || key == '3')
258 					write_key('~');
259 
260 				continue;
261 			} else if (modifiers & MODIFIER_CONTROL) {
262 				char c = kShiftedKeymap[key];
263 				if (c >= 'A' && c <= 'Z')
264 					result = 0x1f & c;
265 			} else if (modifiers & MODIFIER_ALT)
266 				result = kAltedKeymap[key];
267 			else if (modifiers & MODIFIER_SHIFT)
268 				result = kShiftedKeymap[key];
269 			else
270 				result = kUnshiftedKeymap[key];
271 
272 			if (result < 0)
273 				continue;
274 
275 			write_key(result);
276 		}
277 
278 		for (uint32 i = 0; i < sUSBTransferLength; i++)
279 			sLastTransferData[i] = sUSBTransferData[i];
280 	}
281 
282 	if (sBufferedCharCount == 0)
283 		return -1;
284 
285 	int result = sBufferedChars[sBufferReadIndex++];
286 	sBufferReadIndex %= sBufferSize;
287 	sBufferedCharCount--;
288 	return result;
289 }
290 
291 
292 static status_t
293 std_ops(int32 op, ...)
294 {
295 	if (op == B_MODULE_INIT || op == B_MODULE_UNINIT)
296 		return B_OK;
297 
298 	return B_BAD_VALUE;
299 }
300 
301 
302 static struct debugger_module_info sModuleInfo = {
303 	{
304 		"debugger/usb_keyboard/v1",
305 		0,
306 		&std_ops
307 	},
308 
309 	&enter_debugger,
310 	&exit_debugger,
311 	NULL,
312 	&debugger_getchar
313 };
314 
315 module_info *modules[] = {
316 	(module_info *)&sModuleInfo,
317 	NULL
318 };
319 
320