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
12static bool sUseUSBKeyboard = false;
13static uint8 sUSBTransferData[64];
14static uint8 sLastTransferData[64];
15static size_t sUSBTransferLength = 0;
16static void *sUSBPipe = NULL;
17
18// simple ring buffer
19static int sBufferedChars[32];
20static uint8 sBufferSize = sizeof(sBufferedChars) / sizeof(sBufferedChars[0]);
21static uint8 sBufferedCharCount = 0;
22static uint8 sBufferWriteIndex = 0;
23static uint8 sBufferReadIndex = 0;
24
25#define MODIFIER_CONTROL	0x01
26#define MODIFIER_SHIFT		0x02
27#define MODIFIER_ALT		0x04
28
29static 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
40static 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
147static size_t sKeyTableSize = sizeof(sKeyTable) / sizeof(sKeyTable[0]);
148
149
150static void
151enter_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
176static void
177exit_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
188static void
189write_key(int key)
190{
191	sBufferedChars[sBufferWriteIndex++] = key;
192	sBufferWriteIndex %= sBufferSize;
193	sBufferedCharCount++;
194}
195
196
197static int
198debugger_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
299static status_t
300std_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
309static 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
322module_info *modules[] = {
323	(module_info *)&sModuleInfo,
324	NULL
325};
326
327