Author: siarzhuk Date: 2011-06-26 21:38:26 +0200 (Sun, 26 Jun 2011) New Revision: 42325 Changeset: https://dev.haiku-os.org/changeset/42325 Ticket: https://dev.haiku-os.org/ticket/2867 Ticket: https://dev.haiku-os.org/ticket/3594 Ticket: https://dev.haiku-os.org/ticket/4315 Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp Log: * Implemented PS2_CMD_RESEND command handlig; * Workaround for touchpad reset timeouts on some HP/Compaq KBCs. Looks like such KBC marks the mouse reset request (xFF) as correctly sent (by xFA answer) but does not wait enough time for the answer from touchpad. So complete answer finally contains xFE xAA x00 bytes. The workaround detects this xFE xAA answer and issues the RESEND (xFE) request to touchpad. This forces touchpad to resend the last packet of data (xAA x00) that can be processed normally by the host; * Fix for handling passthrough_command() call. The parent device was disabled at start of processing command and was not re-enabled back in case any error return. This fixes the touchpad "pass-through" feature handling on the same HP/Compaq HW. This KBC has the "pass-through" capability marked ON but cannot handle it as currently implemented - there is no answer from corresponding port. The parent device stay in disabled state after this; * Fix ps2_dev_publish() for handling passthrough devices (parent_dev != NULL) This workaround postpone the publishing such device until the parent device finishes it's opening and set the PS2_ENABLED_FALG. It prevent from mixing the Synaptics multi-command sequences from synaptics_open() and ps2_dev_publish() routines and failing both initializations; Fixes #2867 #3594 #4315 Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h 2011-06-26 18:35:56 UTC (rev 42324) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h 2011-06-26 19:38:26 UTC (rev 42325) @@ -57,6 +57,7 @@ #define PS2_CMD_ENABLE 0xf4 #define PS2_CMD_DISABLE 0xf5 #define PS2_CMD_RESET 0xff +#define PS2_CMD_RESEND 0xfe // reply codes #define PS2_REPLY_TEST_PASSED 0x55 Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.cpp 2011-06-26 18:35:56 UTC (rev 42324) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.cpp 2011-06-26 19:38:26 UTC (rev 42325) @@ -36,6 +36,14 @@ status = ps2_dev_command(dev, PS2_CMD_RESET, NULL, 0, data, 2); + if (status == B_OK && data[0] == 0xFE && data[1] == 0xAA) { + // workaround for HP/Compaq KBCs timeout condition. #2867 #3594 #4315 + TRACE("ps2: KBC has timed out the mouse reset request. " + "Response was: 0x%02x 0x%02x. Requesting the answer data.\n", + data[0], data[1]); + status = ps2_dev_command(dev, PS2_CMD_RESEND, NULL, 0, data, 2); + } + if (status == B_OK && data[0] != 0xAA && data[1] != 0x00) { TRACE("ps2: reset mouse failed, response was: 0x%02x 0x%02x\n", data[0], data[1]); @@ -173,7 +181,7 @@ void ps2_dev_publish(ps2_dev *dev) { - status_t status; + status_t status = B_OK; TRACE("ps2: ps2_dev_publish %s\n", dev->name); if (dev->active) @@ -182,10 +190,30 @@ if (atomic_get(&dev->flags) & PS2_FLAG_KEYB) { status = devfs_publish_device(dev->name, &gKeyboardDeviceHooks); } else { - device_hooks *hooks; - status = ps2_dev_detect_pointing(dev, &hooks); + // Check if this is the "pass-through" device and wait until + // the parent_dev goes to enabled state. It is required to prevent + // from messing up the Synaptics command sequences in synaptics_open. + if (dev->parent_dev) { + const bigtime_t timeout = 2000000; + bigtime_t start = system_time(); + while (!(atomic_get(&dev->parent_dev->flags) & PS2_FLAG_ENABLED)) { + if ((system_time() - start) > timeout) { + status = B_BUSY; + break; + } + snooze(timeout / 20); + } + TRACE("ps2: publishing %s: parent %s is %s; wait time %Ld\n", + dev->name, dev->parent_dev->name, + status == B_OK ? "enabled" : "busy", system_time() - start); + } + if (status == B_OK) { - status = devfs_publish_device(dev->name, hooks); + device_hooks *hooks; + status = ps2_dev_detect_pointing(dev, &hooks); + if (status == B_OK) { + status = devfs_publish_device(dev->name, hooks); + } } } @@ -247,6 +275,18 @@ cnt++; } } + } else if ((flags & PS2_FLAG_RESEND)) { + TRACE("ps2: ps2_dev_handle_int: processing RESEND request\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) { + atomic_and(&dev->flags, ~PS2_FLAG_CMD); + cnt++; + } + } } else { // TRACE("ps2: ps2_dev_handle_int unexpected data 0x%02x while " // "waiting for ack\n", data); @@ -345,7 +385,7 @@ for (i = -1; res == B_OK && i < out_count; i++) { atomic_and(&dev->flags, - ~(PS2_FLAG_ACK | PS2_FLAG_NACK | PS2_FLAG_GETID)); + ~(PS2_FLAG_ACK | PS2_FLAG_NACK | PS2_FLAG_GETID | PS2_FLAG_RESEND)); acquire_sem(gControllerSem); @@ -365,6 +405,8 @@ if (i == -1) { if (cmd == PS2_CMD_GET_DEVICE_ID) atomic_or(&dev->flags, PS2_FLAG_CMD | PS2_FLAG_GETID); + else if (cmd == PS2_CMD_RESEND) + atomic_or(&dev->flags, PS2_FLAG_CMD | PS2_FLAG_RESEND); else atomic_or(&dev->flags, PS2_FLAG_CMD); ps2_write_data(cmd); Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h 2011-06-26 18:35:56 UTC (rev 42324) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h 2011-06-26 19:38:26 UTC (rev 42325) @@ -59,6 +59,7 @@ #define PS2_FLAG_ACK (1 << 4) #define PS2_FLAG_NACK (1 << 5) #define PS2_FLAG_GETID (1 << 6) +#define PS2_FLAG_RESEND (1 << 7) #ifdef __cplusplus Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp 2011-06-26 18:35:56 UTC (rev 42324) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp 2011-06-26 19:38:26 UTC (rev 42325) @@ -232,24 +232,24 @@ val = out[i]; status = send_touchpad_arg_timeout(dev->parent_dev, val, timeout); if (status != B_OK) - return status; + goto finalize; if (i != outCount -1) { status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE, &passThroughCmd, 1, NULL, 0, timeout); if (status != B_OK) - return status; + goto finalize; } } status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE, &passThroughCmd, 1, passThroughIn, passThroughInCount, timeout); if (status != B_OK) - return status; + goto finalize; for (i = 0; i < inCount + 1; i++) { uint8 *inPointer = &passThroughIn[i * 6]; if (!IS_SYN_PT_PACKAGE(inPointer)) { TRACE("SYNAPTICS: not a pass throught package\n"); - return B_OK; + goto finalize; } if (i == 0) continue; @@ -257,11 +257,13 @@ in[i - 1] = passThroughIn[i * 6 + 1]; } - status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); - if (status != B_OK) - return status; +finalize: + status_t statusOfEnable = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, + NULL, 0, NULL, 0); + if (statusOfEnable != B_OK) + TRACE("SYNAPTICS: enabling of parent failed: 0x%lx.\n", statusOfEnable); - return B_OK; + return status != B_OK ? status : statusOfEnable; }