btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / add-ons / kernel / bus_managers / ps2 / ps2_keyboard.cpp
blobb41fdea02eaf5dbbb1efac16b05e7eb84501719a
1 /*
2 * Copyright 2004-2010 Haiku, Inc.
3 * Distributed under the terms of the MIT License.
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 */
12 /*! PS/2 keyboard device driver */
15 #include <string.h>
17 #include <new>
19 #include <debug.h>
20 #include <debugger_keymaps.h>
21 #include <lock.h>
22 #include <util/AutoLock.h>
24 #include "ATKeymap.h"
25 #include "ps2_service.h"
26 #include "keyboard_mouse_driver.h"
27 #include "packet_buffer.h"
30 #define KEY_BUFFER_SIZE 100
31 // we will buffer 100 key strokes before we start dropping them
33 enum {
34 LED_SCROLL = 1,
35 LED_NUM = 2,
36 LED_CAPS = 4
39 enum {
40 EXTENDED_KEY = 0xe0,
42 LEFT_ALT_KEY = 0x38,
43 RIGHT_ALT_KEY = 0xb8,
44 SYS_REQ_KEY = 0x54
48 struct keyboard_cookie {
49 bool is_reader;
50 bool is_debugger;
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;
62 static int32 sKeyboardRepeatRate;
63 static bigtime_t sKeyboardRepeatDelay;
64 static uint8 sKeyboardIds[2];
67 static status_t
68 set_leds(led_info *ledInfo)
70 uint8 leds = 0;
72 TRACE("ps2: set keyboard LEDs\n");
74 if (ledInfo->scroll_lock)
75 leds |= LED_SCROLL;
76 if (ledInfo->num_lock)
77 leds |= LED_NUM;
78 if (ledInfo->caps_lock)
79 leds |= LED_CAPS;
81 return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
82 PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0);
86 static status_t
87 set_typematic(int32 rate, bigtime_t delay)
89 uint8 value;
91 TRACE("ps2: set_typematic rate %" B_PRId32 ", delay %" B_PRId64 "\n",
92 rate, delay);
94 // input server and keyboard preferences *seem* to use a range of 20-300
95 if (rate < 20)
96 rate = 20;
97 if (rate > 300)
98 rate = 300;
100 // map this into range 0-31
101 rate = ((rate - 20) * 31) / (300 - 20);
103 // keyboard uses 0 == fast, 31 == slow
104 value = 31 - rate;
106 if (delay >= 875000)
107 value |= 3 << 5;
108 else if (delay >= 625000)
109 value |= 2 << 5;
110 else if (delay >= 375000)
111 value |= 1 << 5;
112 else
113 value |= 0 << 5;
115 return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
116 PS2_CMD_SET_TYPEMATIC, &value, 1, NULL, 0);
120 static int32
121 keyboard_handle_int(ps2_dev *dev)
123 enum emergency_keys {
124 EMERGENCY_LEFT_ALT = 0x01,
125 EMERGENCY_RIGHT_ALT = 0x02,
126 EMERGENCY_SYS_REQ = 0x04,
128 static int emergencyKeyStatus = 0;
129 raw_key_info keyInfo;
130 uint8 scancode = dev->history[0].data;
132 if (atomic_get(&sKeyboardOpenCount) == 0)
133 return B_HANDLED_INTERRUPT;
135 // TODO: Handle braindead "pause" key special case
137 if (scancode == EXTENDED_KEY) {
138 sIsExtended = true;
139 // TRACE("Extended key\n");
140 return B_HANDLED_INTERRUPT;
143 // TRACE("scancode: %x\n", scancode);
145 if ((scancode & 0x80) != 0) {
146 keyInfo.is_keydown = false;
147 scancode &= 0x7f;
148 } else
149 keyInfo.is_keydown = true;
151 if (sIsExtended) {
152 scancode |= 0x80;
153 sIsExtended = false;
156 // Handle emergency keys
157 if (scancode == LEFT_ALT_KEY || scancode == RIGHT_ALT_KEY) {
158 // left or right alt-key pressed
159 if (keyInfo.is_keydown) {
160 emergencyKeyStatus |= scancode == LEFT_ALT_KEY
161 ? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT;
162 } else {
163 emergencyKeyStatus &= ~(scancode == LEFT_ALT_KEY
164 ? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT);
166 } else if (scancode == SYS_REQ_KEY) {
167 if (keyInfo.is_keydown)
168 emergencyKeyStatus |= EMERGENCY_SYS_REQ;
169 else
170 emergencyKeyStatus &= EMERGENCY_SYS_REQ;
171 } else if (emergencyKeyStatus > EMERGENCY_SYS_REQ
172 && debug_emergency_key_pressed(kUnshiftedKeymap[scancode])) {
173 static const int kKeys[] = {LEFT_ALT_KEY, RIGHT_ALT_KEY, SYS_REQ_KEY};
175 // we probably have lost some keys, so reset our key states
176 emergencyKeyStatus = 0;
178 // send key ups for alt-sysreq
179 keyInfo.timestamp = system_time();
180 keyInfo.is_keydown = false;
181 for (size_t i = 0; i < sizeof(kKeys) / sizeof(kKeys[0]); i++) {
182 keyInfo.keycode = kATKeycodeMap[kKeys[i] - 1];
183 if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo,
184 sizeof(keyInfo)) != 0)
185 release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE);
188 return B_HANDLED_INTERRUPT;
191 keyInfo.timestamp = dev->history[0].time;
192 keyInfo.keycode = kATKeycodeMap[scancode - 1];
194 if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo,
195 sizeof(keyInfo)) == 0) {
196 // If there is no space left in the buffer, we drop this key stroke. We
197 // avoid dropping old key strokes, to not destroy what already was
198 // typed.
199 return B_HANDLED_INTERRUPT;
202 release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE);
204 return B_INVOKE_SCHEDULER;
208 static status_t
209 read_keyboard_packet(raw_key_info *packet, bool isDebugger)
211 status_t status;
213 TRACE("ps2: read_keyboard_packet: enter\n");
215 while (true) {
216 status = acquire_sem_etc(sKeyboardSem, 1, B_CAN_INTERRUPT, 0);
217 if (status != B_OK)
218 return status;
220 if (!ps2_device[PS2_DEVICE_KEYB].active) {
221 TRACE("ps2: read_keyboard_packet, Error device no longer active\n");
222 return B_ERROR;
225 if (isDebugger || !sHasDebugReader)
226 break;
228 // Give the debugger a chance to read this packet
229 release_sem(sKeyboardSem);
230 snooze(100000);
233 if (packet_buffer_read(sKeyBuffer, (uint8 *)packet, sizeof(*packet)) == 0) {
234 TRACE("ps2: read_keyboard_packet, Error reading packet: %s\n",
235 strerror(status));
236 return B_ERROR;
239 TRACE("ps2: read_keyboard_packet: keycode: %" B_PRIx32 ", keydown: %s\n",
240 packet->keycode, packet->is_keydown ? "true" : "false");
242 return B_OK;
246 static void
247 ps2_keyboard_disconnect(ps2_dev *dev)
249 // the keyboard might not be opened at this point
250 INFO("ps2: ps2_keyboard_disconnect %s\n", dev->name);
251 if (atomic_get(&sKeyboardOpenCount) != 0)
252 release_sem(sKeyboardSem);
256 // #pragma mark -
259 status_t
260 probe_keyboard(void)
262 uint8 data;
263 status_t status;
265 // This test doesn't work relyable on some notebooks (it reports 0x03)
266 // status = ps2_command(PS2_CTRL_KEYBOARD_TEST, NULL, 0, &data, 1);
267 // if (status != B_OK || data != 0x00) {
268 // INFO("ps2: keyboard test failed, status 0x%08lx, data 0x%02x\n", status, data);
269 // return B_ERROR;
270 // }
272 status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL,
273 0, &data, 1);
274 if (status != B_OK || data != 0xaa) {
275 INFO("ps2: keyboard reset failed, status 0x%08" B_PRIx32 ", data 0x%02x"
276 "\n", status, data);
277 return B_ERROR;
280 // default settings after keyboard reset: delay = 0x01 (500 ms),
281 // rate = 0x0b (10.9 chr/sec)
282 sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20;
283 sKeyboardRepeatDelay = 500000;
285 // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_ENABLE_KEYBOARD, NULL, 0, NULL, 0);
287 // On my notebook, the keyboard controller does NACK the echo command.
288 // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_ECHO, NULL, 0, &data, 1);
289 // if (status != B_OK || data != 0xee) {
290 // INFO("ps2: keyboard echo test failed, status 0x%08lx, data 0x%02x\n", status, data);
291 // return B_ERROR;
292 // }
294 // Some controllers set the disble keyboard command bit to "on" after resetting
295 // the keyboard device. Read #7973 #6313 for more details.
296 // So check the command byte now and re-enable the keyboard if it is the case.
297 uint8 cmdbyte = 0;
298 status = ps2_command(PS2_CTRL_READ_CMD, NULL, 0, &cmdbyte, 1);
300 if (status != B_OK) {
301 INFO("ps2: cannot read CMD byte on kbd probe:%#08" B_PRIx32 "\n",
302 status);
303 } else
304 if ((cmdbyte & PS2_BITS_KEYBOARD_DISABLED) == PS2_BITS_KEYBOARD_DISABLED) {
305 cmdbyte &= ~PS2_BITS_KEYBOARD_DISABLED;
306 status = ps2_command(PS2_CTRL_WRITE_CMD, &cmdbyte, 1, NULL, 0);
307 if (status != B_OK) {
308 INFO("ps2: cannot write 0x%02x to CMD byte on kbd probe:%#08"
309 B_PRIx32 "\n", cmdbyte, status);
313 status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
314 PS2_CMD_GET_DEVICE_ID, NULL, 0, sKeyboardIds, sizeof(sKeyboardIds));
316 if (status != B_OK) {
317 INFO("ps2: cannot read keyboard device id:%#08" B_PRIx32 "\n", status);
320 return B_OK;
324 // #pragma mark -
327 static status_t
328 keyboard_open(const char *name, uint32 flags, void **_cookie)
330 TRACE("ps2: keyboard_open %s\n", name);
332 keyboard_cookie* cookie = new(std::nothrow) keyboard_cookie();
333 if (cookie == NULL)
334 return B_NO_MEMORY;
336 cookie->is_reader = false;
337 cookie->is_debugger = false;
339 MutexLocker locker(sInitializeLock);
341 if (atomic_get(&sKeyboardOpenCount) == 0) {
342 status_t status = probe_keyboard();
343 if (status != B_OK) {
344 INFO("ps2: keyboard probing failed\n");
345 ps2_service_notify_device_removed(&ps2_device[PS2_DEVICE_KEYB]);
346 delete cookie;
347 return status;
350 INFO("ps2: keyboard found\n");
352 sKeyboardSem = create_sem(0, "keyboard_sem");
353 if (sKeyboardSem < 0) {
354 delete cookie;
355 return sKeyboardSem;
358 sKeyBuffer
359 = create_packet_buffer(KEY_BUFFER_SIZE * sizeof(raw_key_info));
360 if (sKeyBuffer == NULL) {
361 delete_sem(sKeyboardSem);
362 delete cookie;
363 return B_NO_MEMORY;
366 ps2_device[PS2_DEVICE_KEYB].disconnect = &ps2_keyboard_disconnect;
367 ps2_device[PS2_DEVICE_KEYB].handle_int = &keyboard_handle_int;
369 atomic_or(&ps2_device[PS2_DEVICE_KEYB].flags, PS2_FLAG_ENABLED);
372 atomic_add(&sKeyboardOpenCount, 1);
373 *_cookie = cookie;
375 TRACE("ps2: keyboard_open %s success\n", name);
376 return B_OK;
380 static status_t
381 keyboard_close(void *_cookie)
383 keyboard_cookie *cookie = (keyboard_cookie *)_cookie;
385 TRACE("ps2: keyboard_close enter\n");
387 if (atomic_add(&sKeyboardOpenCount, -1) == 1) {
388 delete_packet_buffer(sKeyBuffer);
389 delete_sem(sKeyboardSem);
391 atomic_and(&ps2_device[PS2_DEVICE_KEYB].flags, ~PS2_FLAG_ENABLED);
393 sKeyboardIds[0] = sKeyboardIds[1] = 0;
396 if (cookie->is_reader)
397 sHasKeyboardReader = false;
398 if (cookie->is_debugger)
399 sHasDebugReader = false;
401 TRACE("ps2: keyboard_close done\n");
402 return B_OK;
406 static status_t
407 keyboard_freecookie(void *cookie)
409 delete (keyboard_cookie*)cookie;
410 return B_OK;
414 static status_t
415 keyboard_read(void *cookie, off_t pos, void *buffer, size_t *_length)
417 TRACE("ps2: keyboard read\n");
418 *_length = 0;
419 return B_NOT_ALLOWED;
423 static status_t
424 keyboard_write(void *cookie, off_t pos, const void *buffer, size_t *_length)
426 TRACE("ps2: keyboard write\n");
427 *_length = 0;
428 return B_NOT_ALLOWED;
432 static status_t
433 keyboard_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
435 keyboard_cookie *cookie = (keyboard_cookie *)_cookie;
437 switch (op) {
438 case KB_READ:
440 if (!sHasKeyboardReader && !cookie->is_debugger) {
441 cookie->is_reader = true;
442 sHasKeyboardReader = true;
443 } else if (!cookie->is_debugger && !cookie->is_reader)
444 return B_BUSY;
446 raw_key_info packet;
447 status_t status = read_keyboard_packet(&packet,
448 cookie->is_debugger);
449 TRACE("ps2: ioctl KB_READ: %s\n", strerror(status));
450 if (status != B_OK)
451 return status;
453 return user_memcpy(buffer, &packet, sizeof(packet));
456 case KB_SET_LEDS:
458 led_info info;
459 TRACE("ps2: ioctl KB_SET_LEDS\n");
460 if (user_memcpy(&info, buffer, sizeof(led_info)) < B_OK)
461 return B_BAD_ADDRESS;
462 return set_leds(&info);
465 case KB_SET_KEY_REPEATING:
467 TRACE("ps2: ioctl KB_SET_KEY_REPEATING\n");
468 // 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds
469 // with "ack" (0xFA).
470 return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0,
471 NULL, 0);
474 case KB_SET_KEY_NONREPEATING:
476 TRACE("ps2: ioctl KB_SET_KEY_NONREPEATING\n");
477 // 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack"
478 // (0xFA).
479 return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0,
480 NULL, 0);
483 case KB_SET_KEY_REPEAT_RATE:
485 int32 key_repeat_rate;
486 TRACE("ps2: ioctl KB_SET_KEY_REPEAT_RATE\n");
487 if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate))
488 != B_OK)
489 return B_BAD_ADDRESS;
490 if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) != B_OK)
491 return B_ERROR;
492 sKeyboardRepeatRate = key_repeat_rate;
493 return B_OK;
496 case KB_GET_KEY_REPEAT_RATE:
498 TRACE("ps2: ioctl KB_GET_KEY_REPEAT_RATE\n");
499 return user_memcpy(buffer, &sKeyboardRepeatRate,
500 sizeof(sKeyboardRepeatRate));
503 case KB_SET_KEY_REPEAT_DELAY:
505 bigtime_t key_repeat_delay;
506 TRACE("ps2: ioctl KB_SET_KEY_REPEAT_DELAY\n");
507 if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay))
508 != B_OK)
509 return B_BAD_ADDRESS;
510 if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) != B_OK)
511 return B_ERROR;
512 sKeyboardRepeatDelay = key_repeat_delay;
513 return B_OK;
517 case KB_GET_KEY_REPEAT_DELAY:
519 TRACE("ps2: ioctl KB_GET_KEY_REPEAT_DELAY\n");
520 return user_memcpy(buffer, &sKeyboardRepeatDelay,
521 sizeof(sKeyboardRepeatDelay));
524 case KB_GET_KEYBOARD_ID:
526 TRACE("ps2: ioctl KB_GET_KEYBOARD_ID\n");
527 uint16 keyboardId = sKeyboardIds[1] << 8 | sKeyboardIds[0];
528 return user_memcpy(buffer, &keyboardId, sizeof(keyboardId));
531 case KB_SET_CONTROL_ALT_DEL_TIMEOUT:
532 case KB_CANCEL_CONTROL_ALT_DEL:
533 case KB_DELAY_CONTROL_ALT_DEL:
534 INFO("ps2: ioctl 0x%" B_PRIx32 " not implemented yet, returning "
535 "B_OK\n", op);
536 return B_OK;
538 case KB_SET_DEBUG_READER:
539 if (sHasDebugReader)
540 return B_BUSY;
542 cookie->is_debugger = true;
543 sHasDebugReader = true;
544 return B_OK;
546 default:
547 INFO("ps2: invalid ioctl 0x%" B_PRIx32 "\n", op);
548 return B_DEV_INVALID_IOCTL;
553 device_hooks gKeyboardDeviceHooks = {
554 keyboard_open,
555 keyboard_close,
556 keyboard_freecookie,
557 keyboard_ioctl,
558 keyboard_read,
559 keyboard_write,