static status_t set_typematic(int32 rate, bigtime_t delay) { uint8 value; TRACE("ps2: set_typematic rate %ld, delay %Ld\n", rate, delay); // input server and keyboard preferences *seem* to use a range of 20-300 if (rate < 20) rate = 20; if (rate > 300) rate = 300; // map this into range 0-31 rate = ((rate - 20) * 31) / (300 - 20); // keyboard uses 0 == fast, 31 == slow value = 31 - rate; if (delay >= 875000) value |= 3 << 5; else if (delay >= 625000) value |= 2 << 5; else if (delay >= 375000) value |= 1 << 5; else value |= 0 << 5; return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_KEYBOARD_SET_TYPEMATIC, &value, 1, NULL, 0); }
static status_t set_leds(led_info *ledInfo) { uint8 leds = 0; TRACE("ps2: set keyboard LEDs\n"); if (ledInfo->scroll_lock) leds |= LED_SCROLL; if (ledInfo->num_lock) leds |= LED_NUM; if (ledInfo->caps_lock) leds |= LED_CAPS; return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0); }
status_t probe_trackpoint(ps2_dev* dev) { uint8 val[2]; TRACE("TRACKPOINT: probe\n"); ps2_dev_command(dev, 0xE1, NULL, 0, val, 2); if (val[0] != 0x01) { TRACE("TRACKPOINT: not found\n"); return B_ERROR; } dev->name = kTrackpointPath[dev->idx]; dev->packet_size = 3; TRACE("TRACKPOINT: version 0x%x found\n", val[1]); return B_OK; }
status_t probe_keyboard(void) { uint8 data; status_t status; // This test doesn't work relyable on some notebooks (it reports 0x03) // status = ps2_command(PS2_CTRL_KEYBOARD_TEST, NULL, 0, &data, 1); // if (status != B_OK || data != 0x00) { // INFO("ps2: keyboard test failed, status 0x%08lx, data 0x%02x\n", status, data); // return B_ERROR; // } status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL, 0, &data, 1); if (status != B_OK || data != 0xaa) { INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n", status, data); return B_ERROR; } // default settings after keyboard reset: delay = 0x01 (500 ms), // rate = 0x0b (10.9 chr/sec) sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20; sKeyboardRepeatDelay = 500000; // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_ENABLE_KEYBOARD, NULL, 0, NULL, 0); // On my notebook, the keyboard controller does NACK the echo command. // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_ECHO, NULL, 0, &data, 1); // if (status != B_OK || data != 0xee) { // INFO("ps2: keyboard echo test failed, status 0x%08lx, data 0x%02x\n", status, data); // return B_ERROR; // } return B_OK; }
static status_t keyboard_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) { keyboard_cookie *cookie = (keyboard_cookie *)_cookie; switch (op) { case KB_READ: { if (!sHasKeyboardReader && !cookie->is_debugger) { cookie->is_reader = true; sHasKeyboardReader = true; } else if (!cookie->is_debugger && !cookie->is_reader) return B_BUSY; raw_key_info packet; status_t status = read_keyboard_packet(&packet, cookie->is_debugger); TRACE("ps2: ioctl KB_READ: %s\n", strerror(status)); if (status != B_OK) return status; return user_memcpy(buffer, &packet, sizeof(packet)); } case KB_SET_LEDS: { led_info info; TRACE("ps2: ioctl KB_SET_LEDS\n"); if (user_memcpy(&info, buffer, sizeof(led_info)) < B_OK) return B_BAD_ADDRESS; return set_leds(&info); } case KB_SET_KEY_REPEATING: { TRACE("ps2: ioctl KB_SET_KEY_REPEATING\n"); // 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds // with "ack" (0xFA). return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0, NULL, 0); } case KB_SET_KEY_NONREPEATING: { TRACE("ps2: ioctl KB_SET_KEY_NONREPEATING\n"); // 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack" // (0xFA). return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0, NULL, 0); } case KB_SET_KEY_REPEAT_RATE: { int32 key_repeat_rate; TRACE("ps2: ioctl KB_SET_KEY_REPEAT_RATE\n"); if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate)) != B_OK) return B_BAD_ADDRESS; if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) != B_OK) return B_ERROR; sKeyboardRepeatRate = key_repeat_rate; return B_OK; } case KB_GET_KEY_REPEAT_RATE: { TRACE("ps2: ioctl KB_GET_KEY_REPEAT_RATE\n"); return user_memcpy(buffer, &sKeyboardRepeatRate, sizeof(sKeyboardRepeatRate)); } case KB_SET_KEY_REPEAT_DELAY: { bigtime_t key_repeat_delay; TRACE("ps2: ioctl KB_SET_KEY_REPEAT_DELAY\n"); if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay)) != B_OK) return B_BAD_ADDRESS; if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) != B_OK) return B_ERROR; sKeyboardRepeatDelay = key_repeat_delay; return B_OK; } case KB_GET_KEY_REPEAT_DELAY: { TRACE("ps2: ioctl KB_GET_KEY_REPEAT_DELAY\n"); return user_memcpy(buffer, &sKeyboardRepeatDelay, sizeof(sKeyboardRepeatDelay)); } case KB_GET_KEYBOARD_ID: case KB_SET_CONTROL_ALT_DEL_TIMEOUT: case KB_CANCEL_CONTROL_ALT_DEL: case KB_DELAY_CONTROL_ALT_DEL: INFO("ps2: ioctl 0x%lx not implemented yet, returning B_OK\n", op); return B_OK; case KB_SET_DEBUG_READER: if (sHasDebugReader) return B_BUSY; cookie->is_debugger = true; sHasDebugReader = true; return B_OK; default: INFO("ps2: invalid ioctl 0x%lx\n", op); return B_DEV_INVALID_IOCTL; } }
status_t probe_keyboard(void) { uint8 data; status_t status; // This test doesn't work relyable on some notebooks (it reports 0x03) // status = ps2_command(PS2_CTRL_KEYBOARD_TEST, NULL, 0, &data, 1); // if (status != B_OK || data != 0x00) { // INFO("ps2: keyboard test failed, status 0x%08lx, data 0x%02x\n", status, data); // return B_ERROR; // } status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL, 0, &data, 1); if (status != B_OK || data != 0xaa) { INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n", status, data); return B_ERROR; } // default settings after keyboard reset: delay = 0x01 (500 ms), // rate = 0x0b (10.9 chr/sec) sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20; sKeyboardRepeatDelay = 500000; // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_ENABLE_KEYBOARD, NULL, 0, NULL, 0); // On my notebook, the keyboard controller does NACK the echo command. // status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_ECHO, NULL, 0, &data, 1); // if (status != B_OK || data != 0xee) { // INFO("ps2: keyboard echo test failed, status 0x%08lx, data 0x%02x\n", status, data); // return B_ERROR; // } // Some controllers set the disble keyboard command bit to "on" after resetting // the keyboard device. Read #7973 #6313 for more details. // So check the command byte now and re-enable the keyboard if it is the case. uint8 cmdbyte = 0; status = ps2_command(PS2_CTRL_READ_CMD, NULL, 0, &cmdbyte, 1); if (status != B_OK) { INFO("ps2: cannot read CMD byte on kbd probe:0x%#08lx\n", status); } else if ((cmdbyte & PS2_BITS_KEYBOARD_DISABLED) == PS2_BITS_KEYBOARD_DISABLED) { cmdbyte &= ~PS2_BITS_KEYBOARD_DISABLED; status = ps2_command(PS2_CTRL_WRITE_CMD, &cmdbyte, 1, NULL, 0); if (status != B_OK) { INFO("ps2: cannot write 0x%02x to CMD byte on kbd probe:0x%08lx\n", cmdbyte, status); } } status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_GET_DEVICE_ID, NULL, 0, sKeyboardIds, sizeof(sKeyboardIds)); if (status != B_OK) { INFO("ps2: cannot read keyboard device id:0x%#08lx\n", status); } return B_OK; }