* 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



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42325 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Siarzhuk Zharski
2011-06-26 19:38:26 +00:00
parent f225c7e944
commit 7f4deb4400
4 changed files with 59 additions and 13 deletions
@@ -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
@@ -36,6 +36,14 @@ ps2_reset_mouse(ps2_dev *dev)
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 @@ ps2_dev_exit(void)
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 @@ ps2_dev_publish(ps2_dev *dev)
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 @@ ps2_dev_handle_int(ps2_dev *dev)
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 @@ standard_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out,
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 @@ standard_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out,
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);
@@ -59,6 +59,7 @@ extern ps2_dev ps2_device[PS2_DEVICE_COUNT];
#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
@@ -232,24 +232,24 @@ passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int outCount,
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 @@ passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int outCount,
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;
}