@@ -39,6 +39,7 @@
#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
6-byte ALPS packet */
+#define ALPS_SHARED_BTNSTATE 0x100 /* PS/2 and touchpad share button st. */
static const struct alps_model_info alps_model_data[] = {
{ { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
@@ -61,7 +62,7 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED | ALPS_SHARED_BTNSTATE },
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
};
@@ -108,18 +109,49 @@ static const struct alps_model_info alps_model_data[] = {
* on a dualpoint, etc.
*/
-static void alps_report_buttons(struct input_dev *dev,
- int left, int right, int middle,
- bool release_only)
+static void alps_report_single_button(struct psmouse *psmouse,
+ int keycode, int mask, int state,
+ struct input_dev *dev)
{
- if (!left || !release_only)
- input_report_key(dev, BTN_LEFT, left);
+ struct alps_data *priv = psmouse->private;
+ const struct alps_model_info *model = priv->i;
- if (!right || !release_only)
- input_report_key(dev, BTN_RIGHT, right);
+ /* some Alps units do not report touchpad and trackpoint
+ buttons separately (e.g. even the trackpoint movement
+ packets have buttons set while touchpad buttons are down) */
+ if (model->flags & ALPS_SHARED_BTNSTATE) {
+ if (state) {
+ /* need to avoid sending a button-down to both
+ devices (can cause spurious double-click */
+ if (priv->btn_state & mask)
+ return;
+
+ priv->btn_state |= mask;
+ } else {
+ /* we don't know which device got the button
+ down event. just release both to be sure. */
+ struct input_dev *other = psmouse->dev;
+ if (dev == other)
+ other = priv->dev2;
+ input_report_key(other, keycode, state);
+ input_sync(other);
+
+ priv->btn_state &= 7 ^ mask;
+ }
+ }
- if (!middle || !release_only)
- input_report_key(dev, BTN_MIDDLE, middle);
+ /* input_sync called by our caller */
+ input_report_key(dev, keycode, state);
+}
+
+
+static void alps_report_buttons(struct psmouse *psmouse,
+ struct input_dev *dev,
+ int left, int right, int middle)
+{
+ alps_report_single_button(psmouse, BTN_LEFT, 1, left, dev);
+ alps_report_single_button(psmouse, BTN_RIGHT, 2, right, dev);
+ alps_report_single_button(psmouse, BTN_MIDDLE, 4, middle, dev);
}
static void alps_process_packet(struct psmouse *psmouse)
@@ -167,25 +199,13 @@ static void alps_process_packet(struct psmouse *psmouse)
input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
- alps_report_buttons(dev2, left, right, middle, false);
+ alps_report_buttons(psmouse, dev2, left, right, middle);
input_sync(dev2);
- input_sync(dev);
return;
}
- alps_report_buttons(dev, left, right, middle, false);
-
- if (model->flags & ALPS_PS2_INTERLEAVED) {
- /*
- * On devices using interleaved packets, when user presses
- * the same button on both trackpoint and touchpad, the
- * release for the trackpoint is not reported so we have
- * send release events to both devices.
- */
- alps_report_buttons(dev2, left, right, middle, true);
- input_sync(dev2);
- }
+ alps_report_buttons(psmouse, dev, left, right, middle);
/* Convert hardware tap to a reasonable Z value */
if (ges && !fin)
@@ -248,14 +268,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
int right = packet[0] & 2;
int middle = packet[0] & 4;
-
- if (priv->i->flags & ALPS_PS2_INTERLEAVED) {
- alps_report_buttons(psmouse->dev,
- left, right, middle, true);
- input_sync(psmouse->dev);
- }
-
- alps_report_buttons(dev2, left, right, middle, false);
+ alps_report_buttons(psmouse, dev2, left, right, middle);
}
input_report_rel(dev2, REL_X,
@@ -675,6 +688,7 @@ int alps_init(struct psmouse *psmouse)
priv->dev2 = dev2;
setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
+ priv->btn_state = 0;
psmouse->private = priv;
@@ -15,7 +15,7 @@
struct alps_model_info {
unsigned char signature[3];
unsigned char byte0, mask0;
- unsigned char flags;
+ unsigned int flags;
};
struct alps_data {
@@ -23,6 +23,7 @@ struct alps_data {
char phys[32]; /* Phys */
const struct alps_model_info *i;/* Info */
int prev_fin; /* Finger bit from previous packet */
+ int btn_state; /* buttons reported to input_dev */
struct timer_list timer;
};