diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h b/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h index df85a3493e..bacfa8342e 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h @@ -54,8 +54,8 @@ #define PS2_CMD_TEST_PASSED 0xaa #define PS2_CMD_GET_DEVICE_ID 0xf2 #define PS2_CMD_SET_SAMPLE_RATE 0xf3 -#define PS2_CMD_ENABLE_MOUSE 0xf4 -#define PS2_CMD_DISABLE_MOUSE 0xf5 +#define PS2_CMD_ENABLE 0xf4 +#define PS2_CMD_DISABLE 0xf5 #define PS2_CMD_RESET 0xff // reply codes diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c index 7e489f1e63..2e54efc120 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c @@ -57,12 +57,11 @@ void ps2_dev_publish(ps2_dev *dev) { status_t status; + TRACE(("ps2_dev_publish %s\n", dev->name)); if (dev->active) return; - TRACE(("ps2_dev_publish %s\n", dev->name)); - dev->active = true; status = devfs_publish_device(dev->name, NULL, @@ -75,12 +74,17 @@ ps2_dev_publish(ps2_dev *dev) void ps2_dev_unpublish(ps2_dev *dev) { + status_t status; + TRACE(("ps2_dev_unpublish %s\n", dev->name)); + if (!dev->active) return; - - TRACE(("ps2_dev_unpublish %s\n", dev->name)); dev->active = false; + + status = -1; + + dprintf("ps2: devfs_unpublish_device %s, status = 0x%08lx\n", dev->name, status); } @@ -94,19 +98,27 @@ ps2_dev_handle_int(ps2_dev *dev, uint8 data) if (flags & PS2_FLAG_CMD) { if ((flags & (PS2_FLAG_ACK | PS2_FLAG_NACK)) == 0) { int cnt = 1; - if ((flags & PS2_FLAG_GETID) && (data == 0 || data == 3 || data == 4)) { + if (data == PS2_REPLY_ACK) { + atomic_or(&dev->flags, PS2_FLAG_ACK); + } else if (data == PS2_REPLY_RESEND || data == PS2_REPLY_ERROR) { + atomic_or(&dev->flags, PS2_FLAG_NACK); + } else if ((flags & PS2_FLAG_GETID) && (data == 0 || data == 3 || data == 4)) { // workaround for broken mice that don't ack the "get id" command - dprintf("ps2_dev_handle_int: mouse didn't ack the 'get id' command\n"); + dprintf("ps2: ps2_dev_handle_int: mouse didn't ack the 'get id' command\n"); atomic_or(&dev->flags, PS2_FLAG_ACK); if (dev->result_buf_cnt) { dev->result_buf[dev->result_buf_idx] = data; dev->result_buf_idx++; dev->result_buf_cnt--; - if (dev->result_buf_cnt == 0) + if (dev->result_buf_cnt == 0) { + atomic_and(&dev->flags, ~PS2_FLAG_CMD); cnt++; + } } } else { - atomic_or(&dev->flags, data == 0xfa ? PS2_FLAG_ACK : PS2_FLAG_NACK); +// dprintf("ps2: ps2_dev_handle_int unexpected data 0x%02x while waiting for ack\n", data); + dprintf("ps2: int1 %02x\n", data); + goto pass_to_handler; } release_sem_etc(dev->result_sem, cnt, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; @@ -115,30 +127,37 @@ ps2_dev_handle_int(ps2_dev *dev, uint8 data) dev->result_buf_idx++; dev->result_buf_cnt--; if (dev->result_buf_cnt == 0) { + atomic_and(&dev->flags, ~PS2_FLAG_CMD); release_sem_etc(dev->result_sem, 1, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; } } else { - dprintf("ps2_dev_handle_int can't handle\n"); +// dprintf("ps2: ps2_dev_handle_int unexpected data 0x%02x during command processing\n", data); + dprintf("ps2: int2 %02x\n", data); + goto pass_to_handler; } return B_HANDLED_INTERRUPT; } +pass_to_handler: + + dev->last_data = system_time(); + if (!dev->active) { ps2_service_notify_device_added(dev); - dprintf("not active, data dropped\n"); + dprintf("ps2: %s not active, data 0x%02x dropped\n", dev->name, data); return B_HANDLED_INTERRUPT; } if ((flags & PS2_FLAG_ENABLED) == 0) { - dprintf("not enabled, data dropped\n"); + dprintf("ps2: %s not enabled, data 0x%02x dropped\n", dev->name, data); // TODO: remove me again; let us drop into the kernel debugger with F12 if ((flags & PS2_FLAG_KEYB) != 0 && data == 88) panic("keyboard requested halt.\n"); return B_HANDLED_INTERRUPT; } - + // temporary hack... if (flags & PS2_FLAG_KEYB) return keyboard_handle_int(data); @@ -167,8 +186,6 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 else release_sem_etc(dev->result_sem, -sem_count, 0); } - - atomic_or(&dev->flags, PS2_FLAG_CMD); dev->result_buf_cnt = in_count; dev->result_buf_idx = 0; @@ -178,8 +195,6 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 for (i = -1; res == B_OK && i < out_count; i++) { atomic_and(&dev->flags, ~(PS2_FLAG_ACK | PS2_FLAG_NACK | PS2_FLAG_GETID)); - if (i == -1 && cmd == PS2_CMD_GET_DEVICE_ID) - atomic_or(&dev->flags, PS2_FLAG_GETID); acquire_sem(gControllerSem); @@ -196,7 +211,15 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 res = ps2_wait_write(); if (res == B_OK) { - ps2_write_data(i == -1 ? cmd : out[i]); + if (i == -1) { + if (cmd == PS2_CMD_GET_DEVICE_ID) + atomic_or(&dev->flags, PS2_FLAG_CMD | PS2_FLAG_GETID); + else + atomic_or(&dev->flags, PS2_FLAG_CMD); + ps2_write_data(cmd); + } else { + ps2_write_data(out[i]); + } } release_sem(gControllerSem); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h index fea940511e..da66ed4314 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h @@ -27,6 +27,7 @@ struct ps2_dev int result_buf_idx; int result_buf_cnt; void * cookie; + bigtime_t last_data; }; #define PS2_DEVICE_COUNT 5 diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c b/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c index 6153ce9622..8a2f0c17dd 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c @@ -11,7 +11,7 @@ */ -#include "ps2_common.h" +#include "ps2_service.h" #include "kb_mouse_driver.h" #include "packet_buffer.h" @@ -216,6 +216,7 @@ keyboard_open(const char *name, uint32 flags, void **_cookie) status = probe_keyboard(); if (status != B_OK) { dprintf("ps2: keyboard probing failed\n"); + ps2_service_notify_device_removed(&ps2_device[PS2_DEVICE_KEYB]); goto err1; } @@ -245,7 +246,7 @@ err3: err2: err1: atomic_and(&sKeyboardOpenMask, 0); - + dprintf("ps2: keyboard_open %s failed\n", name); return status; } diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c b/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c index 4de510c92b..69ba1e5563 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c @@ -64,8 +64,7 @@ #include "kb_mouse_driver.h" #include "packet_buffer.h" -#include "ps2_common.h" -#include "ps2_dev.h" +#include "ps2_service.h" #define MOUSE_HISTORY_SIZE 256 @@ -200,25 +199,6 @@ mouse_read_event(mouse_cookie *cookie, mouse_movement *userMovement) } -/** Enables or disables mouse reporting for the PS/2 port. - */ -static status_t -set_mouse_enabled(mouse_cookie *cookie, bool enable) -{ - int32 tries = 5; - - while (true) { - if (ps2_dev_command(cookie->dev, enable ? PS2_CMD_ENABLE_MOUSE : PS2_CMD_DISABLE_MOUSE, NULL, 0, NULL, 0) == B_OK) - return B_OK; - - if (--tries <= 0) - break; - } - - return B_ERROR; -} - - /** Interrupt handler for the mouse device. Called whenever the I/O * controller generates an interrupt for the PS/2 mouse. Reads mouse * information from the data port, and stores it, so it can be accessed @@ -259,7 +239,7 @@ mouse_handle_int(ps2_dev *dev, uint8 data) // #pragma mark - -status_t +static status_t probe_mouse(mouse_cookie *cookie, size_t *probed_packet_size) { status_t status; @@ -348,7 +328,8 @@ mouse_open(const char *name, uint32 flags, void **_cookie) status = probe_mouse(cookie, &cookie->packet_size); if (status != B_OK) { - TRACE(("can't probe mouse\n")); + TRACE(("probing mouse failed\n")); + ps2_service_notify_device_removed(dev); goto err1; } @@ -366,7 +347,7 @@ mouse_open(const char *name, uint32 flags, void **_cookie) goto err3; } - status = set_mouse_enabled(cookie, true); + status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); if (status < B_OK) { TRACE(("mouse_open(): cannot enable PS/2 mouse\n")); goto err4; @@ -385,7 +366,7 @@ err2: free(cookie); err1: atomic_and(&dev->flags, ~PS2_FLAG_OPEN); - + dprintf("ps2: mouse_open %s failed\n", name); return B_ERROR; } @@ -398,7 +379,7 @@ mouse_close(void *_cookie) TRACE(("mouse_close()\n")); - set_mouse_enabled(cookie, false); + ps2_dev_command(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0); delete_packet_buffer(cookie->mouse_buffer); delete_sem(cookie->mouse_sem); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_service.c b/src/add-ons/kernel/bus_managers/ps2/ps2_service.c index be30638e39..2db6c3fdd3 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_service.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_service.c @@ -16,7 +16,13 @@ static thread_id sServiceThread; static volatile bool sServiceTerminate; static packet_buffer * sServiceCmdBuffer; -#define PS2_SERVICE_INTERVAL 200000 + +#ifdef DEBUG + #define PS2_SERVICE_INTERVAL 10000000 +#else + #define PS2_SERVICE_INTERVAL 1000000 +#endif + typedef struct { @@ -59,35 +65,74 @@ ps2_service_notify_device_removed(ps2_dev *dev) packet_buffer_write(sServiceCmdBuffer, (const uint8 *)&cmd, sizeof(cmd)); release_sem_etc(sServiceSem, 1, B_DO_NOT_RESCHEDULE); + + TRACE(("ps2_service_notify_device_removed done\n")); } static status_t ps2_service_probe_device(ps2_dev *dev) { - uint8 d; status_t res; + uint8 data[2]; TRACE(("ps2_service_probe_device %s\n", dev->name)); -/* + + // assume device still exists if it sent data during last 500 ms + if (dev->active && (system_time() - dev->last_data) < 500000) + return B_OK; + if (dev->flags & PS2_FLAG_KEYB) { + + res = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); + if (res == B_OK) + return B_OK; - res = ps2_command(0xae, NULL, 0, NULL, 0); - dprintf("KBD enable: res 0x%08x\n", res); +// snooze(25000); +// res = ps2_dev_command(dev, 0xee, NULL, 0, NULL, 0); // echo +// if (res == B_OK) +// return B_OK; - res = ps2_command(0xab, NULL, 0, &d, 1); - dprintf("KBD test: res 0x%08x, d 0x%02x\n", res, d); + snooze(25000); + res = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, data, 2); + if (res == B_OK) + return B_OK; + +// if (!dev->active) { +// snooze(25000); +// // 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds with "ack" (0xFA). +// res = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0, NULL, 0); +// if (res == B_OK) +// return B_OK; +// } + + if (!dev->active) { + snooze(25000); + // 0xF3 (Set Typematic Rate/Delay) + data[0] = 0x0b; + res = ps2_dev_command(dev, PS2_CMD_KEYBOARD_SET_TYPEMATIC, data, 1, NULL, 0); + if (res == B_OK) + return B_OK; + } } else { + + res = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); + if (res == B_OK) { + if (!dev->active) + ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0); + return B_OK; + } - res = ps2_command(0xa8, NULL, 0, NULL, 0); - dprintf("AUX enable: res 0x%08x\n", res); - - res = ps2_command(0xa9, NULL, 0, &d, 1); - dprintf("AUX test: res 0x%08x, d 0x%02x\n", res, d); + if (!dev->active) { + snooze(25000); + res = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, data, 1); + if (res == B_OK) + return B_OK; + } } -*/ - return B_OK; + + return B_ERROR; } @@ -102,18 +147,14 @@ ps2_service_thread(void *arg) if (sServiceTerminate) break; if (status == B_OK) { + // process service commands - ps2_service_cmd cmd; - - TRACE(("ps2_service_thread: reading cmd\n")); - packet_buffer_read(sServiceCmdBuffer, (uint8 *)&cmd, sizeof(cmd)); switch (cmd.id) { case PS2_SERVICE_NOTIFY_DEVICE_ADDED: TRACE(("PS2_SERVICE_NOTIFY_DEVICE_ADDED %s\n", cmd.dev->name)); - if (ps2_service_probe_device(cmd.dev) == B_OK) - ps2_dev_publish(cmd.dev); + ps2_dev_publish(cmd.dev); break; case PS2_SERVICE_NOTIFY_DEVICE_REMOVED: @@ -127,7 +168,18 @@ ps2_service_thread(void *arg) } } else if (status == B_TIMED_OUT) { + // do periodic processing + int i; + for (i = 0; i < (gActiveMultiplexingEnabled ? PS2_DEVICE_COUNT : 2); i++) { + ps2_dev *dev = &ps2_device[i]; + status_t status = ps2_service_probe_device(dev); + if (dev->active && status != B_OK) + ps2_dev_unpublish(dev); + else if (!dev->active && status == B_OK) + ps2_dev_publish(dev); + snooze(50000); + } } else { dprintf("ps2_service_thread: Error, status 0x%08lx, terminating\n", status);