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