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