xref: /haiku/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.cpp (revision cb837539f5d245cedff238f8894c0ae326c2eaf5)
1 /*
2  * Copyright 2004-2010 Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors (in chronological order):
6  *		Stefano Ceccherini (burton666@libero.it)
7  *		Axel Dörfler, axeld@pinc-software.de
8  *      Marcus Overhagen <marcus@overhagen.de>
9  */
10 
11 
12 /*! PS/2 keyboard device driver */
13 
14 
15 #include <string.h>
16 
17 #include <new>
18 
19 #include <debug.h>
20 #include <debugger_keymaps.h>
21 #include <lock.h>
22 #include <util/AutoLock.h>
23 
24 #include "ATKeymap.h"
25 #include "ps2_service.h"
26 #include "keyboard_mouse_driver.h"
27 #include "packet_buffer.h"
28 
29 
30 #define KEY_BUFFER_SIZE 100
31 	// we will buffer 100 key strokes before we start dropping them
32 
33 enum {
34 	LED_SCROLL 	= 1,
35 	LED_NUM 	= 2,
36 	LED_CAPS	= 4
37 };
38 
39 enum {
40 	EXTENDED_KEY	= 0xe0,
41 
42 	LEFT_ALT_KEY	= 0x38,
43 	RIGHT_ALT_KEY	= 0xb8,
44 	SYS_REQ_KEY		= 0x54,
45 	PRNT_SCRN_KEY	= 0x80 | 0x37,
46 };
47 
48 
49 struct keyboard_cookie {
50 	bool is_reader;
51 	bool is_debugger;
52 };
53 
54 
55 static mutex sInitializeLock = MUTEX_INITIALIZER("keyboard init");
56 static int32 sKeyboardOpenCount = 0;
57 static bool sHasKeyboardReader = false;
58 static bool sHasDebugReader = false;
59 static sem_id sKeyboardSem;
60 static struct packet_buffer *sKeyBuffer;
61 static bool sIsExtended = false;
62 
63 static int32 sKeyboardRepeatRate;
64 static bigtime_t sKeyboardRepeatDelay;
65 static uint8 sKeyboardIds[2];
66 
67 
68 static status_t
69 set_leds(led_info *ledInfo)
70 {
71 	uint8 leds = 0;
72 
73 	TRACE("ps2: set keyboard LEDs\n");
74 
75 	if (ledInfo->scroll_lock)
76 		leds |= LED_SCROLL;
77 	if (ledInfo->num_lock)
78 		leds |= LED_NUM;
79 	if (ledInfo->caps_lock)
80 		leds |= LED_CAPS;
81 
82 	return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
83 		PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0);
84 }
85 
86 
87 static status_t
88 set_typematic(int32 rate, bigtime_t delay)
89 {
90 	uint8 value;
91 
92 	TRACE("ps2: set_typematic rate %" B_PRId32 ", delay %" B_PRId64 "\n",
93 		rate, delay);
94 
95 	// input server and keyboard preferences *seem* to use a range of 20-300
96 	if (rate < 20)
97 		rate = 20;
98 	if (rate > 300)
99 		rate = 300;
100 
101 	// map this into range 0-31
102 	rate = ((rate - 20) * 31) / (300 - 20);
103 
104 	// keyboard uses 0 == fast, 31 == slow
105 	value = 31 - rate;
106 
107 	if (delay >= 875000)
108 		value |= 3 << 5;
109 	else if (delay >= 625000)
110 		value |= 2 << 5;
111 	else if (delay >= 375000)
112 		value |= 1 << 5;
113 	else
114 		value |= 0 << 5;
115 
116 	return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
117 		PS2_CMD_SET_TYPEMATIC, &value, 1, NULL, 0);
118 }
119 
120 
121 static int32
122 keyboard_handle_int(ps2_dev *dev)
123 {
124 	enum emergency_keys {
125 		EMERGENCY_LEFT_ALT	= 0x01,
126 		EMERGENCY_RIGHT_ALT	= 0x02,
127 		EMERGENCY_SYS_REQ	= 0x04,
128 	};
129 	static int emergencyKeyStatus = 0;
130 	raw_key_info keyInfo;
131 	uint8 scancode = dev->history[0].data;
132 
133 	if (atomic_get(&sKeyboardOpenCount) == 0)
134 		return B_HANDLED_INTERRUPT;
135 
136 	// TODO: Handle braindead "pause" key special case
137 
138 	if (scancode == EXTENDED_KEY) {
139 		sIsExtended = true;
140 //		TRACE("Extended key\n");
141 		return B_HANDLED_INTERRUPT;
142 	}
143 
144 //	TRACE("scancode: %x\n", scancode);
145 
146 	if ((scancode & 0x80) != 0) {
147 		keyInfo.is_keydown = false;
148 		scancode &= 0x7f;
149 	} else
150 		keyInfo.is_keydown = true;
151 
152 	if (sIsExtended) {
153 		scancode |= 0x80;
154 		sIsExtended = false;
155 	}
156 
157 	// Handle emergency keys
158 	if (scancode == LEFT_ALT_KEY || scancode == RIGHT_ALT_KEY) {
159 		// left or right alt-key pressed
160 		if (keyInfo.is_keydown) {
161 			emergencyKeyStatus |= scancode == LEFT_ALT_KEY
162 				? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT;
163 		} else {
164 			emergencyKeyStatus &= ~(scancode == LEFT_ALT_KEY
165 				? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT);
166 		}
167 	} else if (scancode == SYS_REQ_KEY || scancode == PRNT_SCRN_KEY) {
168 		if (keyInfo.is_keydown)
169 			emergencyKeyStatus |= EMERGENCY_SYS_REQ;
170 		else
171 			emergencyKeyStatus &= ~EMERGENCY_SYS_REQ;
172 	} else if (emergencyKeyStatus > EMERGENCY_SYS_REQ
173 		&& debug_emergency_key_pressed(kUnshiftedKeymap[scancode])) {
174 		static const int kKeys[] = {LEFT_ALT_KEY, RIGHT_ALT_KEY, SYS_REQ_KEY};
175 
176 		// we probably have lost some keys, so reset our key states
177 		emergencyKeyStatus = 0;
178 
179 		// send key ups for alt-sysreq
180 		keyInfo.timestamp = system_time();
181 		keyInfo.is_keydown = false;
182 		for (size_t i = 0; i < sizeof(kKeys) / sizeof(kKeys[0]); i++) {
183 			keyInfo.keycode = kATKeycodeMap[kKeys[i] - 1];
184 			if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo,
185 					sizeof(keyInfo)) != 0)
186 				release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE);
187 		}
188 
189 		return B_HANDLED_INTERRUPT;
190 	}
191 
192 	keyInfo.timestamp = dev->history[0].time;
193 	keyInfo.keycode = kATKeycodeMap[scancode - 1];
194 
195 	if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo,
196 			sizeof(keyInfo)) == 0) {
197 		// If there is no space left in the buffer, we drop this key stroke. We
198 		// avoid dropping old key strokes, to not destroy what already was
199 		// typed.
200 		return B_HANDLED_INTERRUPT;
201 	}
202 
203 	release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE);
204 
205 	return B_INVOKE_SCHEDULER;
206 }
207 
208 
209 static status_t
210 read_keyboard_packet(raw_key_info *packet, bool isDebugger)
211 {
212 	status_t status;
213 
214 	TRACE("ps2: read_keyboard_packet: enter\n");
215 
216 	while (true) {
217 		status = acquire_sem_etc(sKeyboardSem, 1, B_CAN_INTERRUPT, 0);
218 		if (status != B_OK)
219 			return status;
220 
221 		if (!ps2_device[PS2_DEVICE_KEYB].active) {
222 			TRACE("ps2: read_keyboard_packet, Error device no longer active\n");
223 			return B_ERROR;
224 		}
225 
226 		if (isDebugger || !sHasDebugReader)
227 			break;
228 
229 		// Give the debugger a chance to read this packet
230 		release_sem(sKeyboardSem);
231 		snooze(100000);
232 	}
233 
234 	if (packet_buffer_read(sKeyBuffer, (uint8 *)packet, sizeof(*packet)) == 0) {
235 		TRACE("ps2: read_keyboard_packet, Error reading packet: %s\n",
236 			strerror(status));
237 		return B_ERROR;
238 	}
239 
240 	TRACE("ps2: read_keyboard_packet: keycode: %" B_PRIx32 ", keydown: %s\n",
241 		packet->keycode, packet->is_keydown ? "true" : "false");
242 
243 	return B_OK;
244 }
245 
246 
247 static void
248 ps2_keyboard_disconnect(ps2_dev *dev)
249 {
250 	// the keyboard might not be opened at this point
251 	INFO("ps2: ps2_keyboard_disconnect %s\n", dev->name);
252 	if (atomic_get(&sKeyboardOpenCount) != 0)
253 		release_sem(sKeyboardSem);
254 }
255 
256 
257 //	#pragma mark -
258 
259 
260 status_t
261 probe_keyboard(void)
262 {
263 	uint8 data;
264 	status_t status;
265 
266 //  This test doesn't work relyable on some notebooks (it reports 0x03)
267 //	status = ps2_command(PS2_CTRL_KEYBOARD_TEST, NULL, 0, &data, 1);
268 //	if (status != B_OK || data != 0x00) {
269 //		INFO("ps2: keyboard test failed, status 0x%08lx, data 0x%02x\n", status, data);
270 //		return B_ERROR;
271 //	}
272 
273 	status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL,
274 		0, &data, 1);
275 	if (status != B_OK || data != 0xaa) {
276 		INFO("ps2: keyboard reset failed, status 0x%08" B_PRIx32 ", data 0x%02x"
277 			"\n", status, data);
278 		return B_ERROR;
279 	}
280 
281 	// default settings after keyboard reset: delay = 0x01 (500 ms),
282 	// rate = 0x0b (10.9 chr/sec)
283 	sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20;
284 	sKeyboardRepeatDelay = 500000;
285 
286 //	status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_ENABLE_KEYBOARD, NULL, 0, NULL, 0);
287 
288 //  On my notebook, the keyboard controller does NACK the echo command.
289 //	status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_ECHO, NULL, 0, &data, 1);
290 //	if (status != B_OK || data != 0xee) {
291 //		INFO("ps2: keyboard echo test failed, status 0x%08lx, data 0x%02x\n", status, data);
292 //		return B_ERROR;
293 //	}
294 
295 // Some controllers set the disble keyboard command bit to "on" after resetting
296 // the keyboard device. Read #7973 #6313 for more details.
297 // So check the command byte now and re-enable the keyboard if it is the case.
298 	uint8 cmdbyte = 0;
299 	status = ps2_command(PS2_CTRL_READ_CMD, NULL, 0, &cmdbyte, 1);
300 
301 	if (status != B_OK) {
302 		INFO("ps2: cannot read CMD byte on kbd probe:%#08" B_PRIx32 "\n",
303 			status);
304 	} else
305 	if ((cmdbyte & PS2_BITS_KEYBOARD_DISABLED) == PS2_BITS_KEYBOARD_DISABLED) {
306 		cmdbyte &= ~PS2_BITS_KEYBOARD_DISABLED;
307 		status = ps2_command(PS2_CTRL_WRITE_CMD, &cmdbyte, 1, NULL, 0);
308 		if (status != B_OK) {
309 			INFO("ps2: cannot write 0x%02x to CMD byte on kbd probe:%#08"
310 				B_PRIx32 "\n", cmdbyte, status);
311 		}
312 	}
313 
314 	status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
315 			PS2_CMD_GET_DEVICE_ID, NULL, 0, sKeyboardIds, sizeof(sKeyboardIds));
316 
317 	if (status != B_OK) {
318 		INFO("ps2: cannot read keyboard device id:%#08" B_PRIx32 "\n", status);
319 	}
320 
321 	return B_OK;
322 }
323 
324 
325 //	#pragma mark -
326 
327 
328 static status_t
329 keyboard_open(const char *name, uint32 flags, void **_cookie)
330 {
331 	TRACE("ps2: keyboard_open %s\n", name);
332 
333 	keyboard_cookie* cookie = new(std::nothrow) keyboard_cookie();
334 	if (cookie == NULL)
335 		return B_NO_MEMORY;
336 
337 	cookie->is_reader = false;
338 	cookie->is_debugger = false;
339 
340 	MutexLocker locker(sInitializeLock);
341 
342 	if (atomic_get(&sKeyboardOpenCount) == 0) {
343 		status_t status = probe_keyboard();
344 		if (status != B_OK) {
345 			INFO("ps2: keyboard probing failed\n");
346 			ps2_service_notify_device_removed(&ps2_device[PS2_DEVICE_KEYB]);
347 			delete cookie;
348 			return status;
349 		}
350 
351 		INFO("ps2: keyboard found\n");
352 
353 		sKeyboardSem = create_sem(0, "keyboard_sem");
354 		if (sKeyboardSem < 0) {
355 			delete cookie;
356 			return sKeyboardSem;
357 		}
358 
359 		sKeyBuffer
360 			= create_packet_buffer(KEY_BUFFER_SIZE * sizeof(raw_key_info));
361 		if (sKeyBuffer == NULL) {
362 			delete_sem(sKeyboardSem);
363 			delete cookie;
364 			return B_NO_MEMORY;
365 		}
366 
367 		ps2_device[PS2_DEVICE_KEYB].disconnect = &ps2_keyboard_disconnect;
368 		ps2_device[PS2_DEVICE_KEYB].handle_int = &keyboard_handle_int;
369 
370 		atomic_or(&ps2_device[PS2_DEVICE_KEYB].flags, PS2_FLAG_ENABLED);
371 	}
372 
373 	atomic_add(&sKeyboardOpenCount, 1);
374 	*_cookie = cookie;
375 
376 	TRACE("ps2: keyboard_open %s success\n", name);
377 	return B_OK;
378 }
379 
380 
381 static status_t
382 keyboard_close(void *_cookie)
383 {
384 	keyboard_cookie *cookie = (keyboard_cookie *)_cookie;
385 
386 	TRACE("ps2: keyboard_close enter\n");
387 
388 	if (atomic_add(&sKeyboardOpenCount, -1) == 1) {
389 		delete_packet_buffer(sKeyBuffer);
390 		delete_sem(sKeyboardSem);
391 
392 		atomic_and(&ps2_device[PS2_DEVICE_KEYB].flags, ~PS2_FLAG_ENABLED);
393 
394 		sKeyboardIds[0] = sKeyboardIds[1] = 0;
395 	}
396 
397 	if (cookie->is_reader)
398 		sHasKeyboardReader = false;
399 	if (cookie->is_debugger)
400 		sHasDebugReader = false;
401 
402 	TRACE("ps2: keyboard_close done\n");
403 	return B_OK;
404 }
405 
406 
407 static status_t
408 keyboard_freecookie(void *cookie)
409 {
410 	delete (keyboard_cookie*)cookie;
411 	return B_OK;
412 }
413 
414 
415 static status_t
416 keyboard_read(void *cookie, off_t pos, void *buffer, size_t *_length)
417 {
418 	TRACE("ps2: keyboard read\n");
419 	*_length = 0;
420 	return B_NOT_ALLOWED;
421 }
422 
423 
424 static status_t
425 keyboard_write(void *cookie, off_t pos, const void *buffer,  size_t *_length)
426 {
427 	TRACE("ps2: keyboard write\n");
428 	*_length = 0;
429 	return B_NOT_ALLOWED;
430 }
431 
432 
433 static status_t
434 keyboard_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
435 {
436 	keyboard_cookie *cookie = (keyboard_cookie *)_cookie;
437 
438 	switch (op) {
439 		case KB_READ:
440 		{
441 			if (!sHasKeyboardReader && !cookie->is_debugger) {
442 				cookie->is_reader = true;
443 				sHasKeyboardReader = true;
444 			} else if (!cookie->is_debugger && !cookie->is_reader)
445 				return B_BUSY;
446 
447 			raw_key_info packet;
448 			status_t status = read_keyboard_packet(&packet,
449 				cookie->is_debugger);
450 			TRACE("ps2: ioctl KB_READ: %s\n", strerror(status));
451 			if (status != B_OK)
452 				return status;
453 
454 			return user_memcpy(buffer, &packet, sizeof(packet));
455 		}
456 
457 		case KB_SET_LEDS:
458 		{
459 			led_info info;
460 			TRACE("ps2: ioctl KB_SET_LEDS\n");
461 			if (user_memcpy(&info, buffer, sizeof(led_info)) < B_OK)
462 				return B_BAD_ADDRESS;
463 			return set_leds(&info);
464 		}
465 
466 		case KB_SET_KEY_REPEATING:
467 		{
468 			TRACE("ps2: ioctl KB_SET_KEY_REPEATING\n");
469 			// 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds
470 			// with "ack" (0xFA).
471 			return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0,
472 				NULL, 0);
473 		}
474 
475 		case KB_SET_KEY_NONREPEATING:
476 		{
477 			TRACE("ps2: ioctl KB_SET_KEY_NONREPEATING\n");
478 			// 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack"
479 			// (0xFA).
480 			return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0,
481 				NULL, 0);
482 		}
483 
484 		case KB_SET_KEY_REPEAT_RATE:
485 		{
486 			int32 key_repeat_rate;
487 			TRACE("ps2: ioctl KB_SET_KEY_REPEAT_RATE\n");
488 			if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate))
489 					!= B_OK)
490 				return B_BAD_ADDRESS;
491 			if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) != B_OK)
492 				return B_ERROR;
493 			sKeyboardRepeatRate = key_repeat_rate;
494 			return B_OK;
495 		}
496 
497 		case KB_GET_KEY_REPEAT_RATE:
498 		{
499 			TRACE("ps2: ioctl KB_GET_KEY_REPEAT_RATE\n");
500 			return user_memcpy(buffer, &sKeyboardRepeatRate,
501 				sizeof(sKeyboardRepeatRate));
502 		}
503 
504 		case KB_SET_KEY_REPEAT_DELAY:
505 		{
506 			bigtime_t key_repeat_delay;
507 			TRACE("ps2: ioctl KB_SET_KEY_REPEAT_DELAY\n");
508 			if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay))
509 					!= B_OK)
510 				return B_BAD_ADDRESS;
511 			if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) != B_OK)
512 				return B_ERROR;
513 			sKeyboardRepeatDelay = key_repeat_delay;
514 			return B_OK;
515 
516 		}
517 
518 		case KB_GET_KEY_REPEAT_DELAY:
519 		{
520 			TRACE("ps2: ioctl KB_GET_KEY_REPEAT_DELAY\n");
521 			return user_memcpy(buffer, &sKeyboardRepeatDelay,
522 				sizeof(sKeyboardRepeatDelay));
523 		}
524 
525 		case KB_GET_KEYBOARD_ID:
526 		{
527 			TRACE("ps2: ioctl KB_GET_KEYBOARD_ID\n");
528 			uint16 keyboardId = sKeyboardIds[1] << 8 | sKeyboardIds[0];
529 			return user_memcpy(buffer, &keyboardId, sizeof(keyboardId));
530 		}
531 
532 		case KB_SET_CONTROL_ALT_DEL_TIMEOUT:
533 		case KB_CANCEL_CONTROL_ALT_DEL:
534 		case KB_DELAY_CONTROL_ALT_DEL:
535 			INFO("ps2: ioctl 0x%" B_PRIx32 " not implemented yet, returning "
536 				"B_OK\n", op);
537 			return B_OK;
538 
539 		case KB_SET_DEBUG_READER:
540 			if (sHasDebugReader)
541 				return B_BUSY;
542 
543 			cookie->is_debugger = true;
544 			sHasDebugReader = true;
545 			return B_OK;
546 
547 		default:
548 			INFO("ps2: invalid ioctl 0x%" B_PRIx32 "\n", op);
549 			return B_DEV_INVALID_IOCTL;
550 	}
551 }
552 
553 
554 device_hooks gKeyboardDeviceHooks = {
555 	keyboard_open,
556 	keyboard_close,
557 	keyboard_freecookie,
558 	keyboard_ioctl,
559 	keyboard_read,
560 	keyboard_write,
561 };
562