#include <linux/module.h>
#include <linux/input.h>
#include <linux/serio.h>
+#include <linux/libps2.h>
#include "psmouse.h"
#include "synaptics.h"
* Synaptics communications functions
****************************************************************************/
-/*
- * Use the Synaptics extended ps/2 syntax to write a special command byte.
- * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
- * is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
- * and synaptics_mode_cmd)
- */
-static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
-{
- int i;
-
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
- return -1;
-
- for (i = 6; i >= 0; i -= 2) {
- unsigned char d = (command >> i) & 3;
- if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
- return -1;
- }
-
- return 0;
-}
-
/*
* Send a command to the synpatics touchpad by special commands
*/
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
{
- if (synaptics_special_cmd(psmouse, c))
+ if (psmouse_sliced_command(psmouse, c))
return -1;
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
return 0;
}
{
unsigned char param[1];
- if (synaptics_special_cmd(psmouse, mode))
+ if (psmouse_sliced_command(psmouse, mode))
return -1;
param[0] = SYN_PS_SET_MODE2;
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
- priv->capabilities = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+ priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
priv->ext_cap = 0;
if (!SYN_CAP_VALID(priv->capabilities))
return -1;
- if (SYN_EXT_CAP_REQUESTS(priv->capabilities)) {
+ /*
+ * Unless capExtended is set the rest of the flags should be ignored
+ */
+ if (!SYN_CAP_EXTENDED(priv->capabilities))
+ priv->capabilities = 0;
+
+ if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
" but I'm not able to read them.");
- } else
- priv->ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+ } else {
+ priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+
+ /*
+ * if nExtBtn is greater than 8 it should be considered
+ * invalid and treated as 0
+ */
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
+ priv->ext_cap &= 0xff0fff;
+ }
}
return 0;
}
return -1;
}
-static void print_ident(struct synaptics_data *priv)
-{
- printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
- printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
- SYN_ID_MINOR(priv->identity));
- if (SYN_MODEL_ROT180(priv->model_id))
- printk(KERN_INFO " 180 degree mounted touchpad\n");
- if (SYN_MODEL_PORTRAIT(priv->model_id))
- printk(KERN_INFO " portrait touchpad\n");
- printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
- if (SYN_MODEL_NEWABS(priv->model_id))
- printk(KERN_INFO " new absolute packet format\n");
- if (SYN_MODEL_PEN(priv->model_id))
- printk(KERN_INFO " pen detection\n");
-
- if (SYN_CAP_EXTENDED(priv->capabilities)) {
- printk(KERN_INFO " Touchpad has extended capability bits\n");
- if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
- SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) <= 8)
- printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
- (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
- else if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
- printk(KERN_INFO " -> four buttons\n");
- if (SYN_CAP_MULTIFINGER(priv->capabilities))
- printk(KERN_INFO " -> multifinger detection\n");
- if (SYN_CAP_PALMDETECT(priv->capabilities))
- printk(KERN_INFO " -> palm detection\n");
- if (SYN_CAP_PASS_THROUGH(priv->capabilities))
- printk(KERN_INFO " -> pass-through port\n");
- }
-}
-
static int synaptics_query_hardware(struct psmouse *psmouse)
{
int retries = 0;
return 0;
}
-static int synaptics_set_mode(struct psmouse *psmouse, int mode)
+static int synaptics_set_absolute_mode(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
- mode |= SYN_BIT_ABSOLUTE_MODE;
- if (psmouse_rate >= 80)
- mode |= SYN_BIT_HIGH_RATE;
+ priv->mode = SYN_BIT_ABSOLUTE_MODE;
if (SYN_ID_MAJOR(priv->identity) >= 4)
- mode |= SYN_BIT_DISABLE_GESTURE;
+ priv->mode |= SYN_BIT_DISABLE_GESTURE;
if (SYN_CAP_EXTENDED(priv->capabilities))
- mode |= SYN_BIT_W_MODE;
- if (synaptics_mode_cmd(psmouse, mode))
+ priv->mode |= SYN_BIT_W_MODE;
+
+ if (synaptics_mode_cmd(psmouse, priv->mode))
return -1;
return 0;
}
-/*****************************************************************************
- * Synaptics pass-through PS/2 port support
- ****************************************************************************/
-static int synaptics_pt_open(struct serio *port)
+static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
{
- return 0;
-}
+ struct synaptics_data *priv = psmouse->private;
-static void synaptics_pt_close(struct serio *port)
-{
+ if (rate >= 80) {
+ priv->mode |= SYN_BIT_HIGH_RATE;
+ psmouse->rate = 80;
+ } else {
+ priv->mode &= ~SYN_BIT_HIGH_RATE;
+ psmouse->rate = 40;
+ }
+
+ synaptics_mode_cmd(psmouse, priv->mode);
}
-static int synaptics_pt_write(struct serio *port, unsigned char c)
+/*****************************************************************************
+ * Synaptics pass-through PS/2 port support
+ ****************************************************************************/
+static int synaptics_pt_write(struct serio *serio, unsigned char c)
{
- struct psmouse *parent = port->driver;
+ struct psmouse *parent = serio_get_drvdata(serio->parent);
char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
- if (synaptics_special_cmd(parent, c))
+ if (psmouse_sliced_command(parent, c))
return -1;
- if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+ if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
{
- struct psmouse *child = ptport->private;
-
- if (child) {
- if (child->state == PSMOUSE_ACTIVATED) {
- serio_interrupt(ptport, packet[1], 0, NULL);
- serio_interrupt(ptport, packet[4], 0, NULL);
- serio_interrupt(ptport, packet[5], 0, NULL);
- if (child->type >= PSMOUSE_GENPS)
- serio_interrupt(ptport, packet[2], 0, NULL);
- } else if (child->state != PSMOUSE_IGNORE) {
- serio_interrupt(ptport, packet[1], 0, NULL);
- }
- }
+ struct psmouse *child = serio_get_drvdata(ptport);
+
+ if (child && child->state == PSMOUSE_ACTIVATED) {
+ serio_interrupt(ptport, packet[1], 0, NULL);
+ serio_interrupt(ptport, packet[4], 0, NULL);
+ serio_interrupt(ptport, packet[5], 0, NULL);
+ if (child->pktsize == 4)
+ serio_interrupt(ptport, packet[2], 0, NULL);
+ } else
+ serio_interrupt(ptport, packet[1], 0, NULL);
}
static void synaptics_pt_activate(struct psmouse *psmouse)
{
- struct psmouse *child = psmouse->ptport->serio.private;
+ struct serio *ptport = psmouse->ps2dev.serio->child;
+ struct psmouse *child = serio_get_drvdata(ptport);
+ struct synaptics_data *priv = psmouse->private;
/* adjust the touchpad to child's choice of protocol */
- if (child && child->type >= PSMOUSE_GENPS) {
- if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT))
- printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+ if (child) {
+ if (child->pktsize == 4)
+ priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
+ else
+ priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
+
+ if (synaptics_mode_cmd(psmouse, priv->mode))
+ printk(KERN_INFO "synaptics: failed to switch guest protocol\n");
}
}
static void synaptics_pt_create(struct psmouse *psmouse)
{
- struct psmouse_ptport *port;
+ struct serio *serio;
- psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL);
- if (!port) {
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!serio) {
printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
return;
}
- memset(port, 0, sizeof(struct psmouse_ptport));
-
- port->serio.type = SERIO_PS_PSTHRU;
- port->serio.name = "Synaptics pass-through";
- port->serio.phys = "synaptics-pt/serio0";
- port->serio.write = synaptics_pt_write;
- port->serio.open = synaptics_pt_open;
- port->serio.close = synaptics_pt_close;
- port->serio.driver = psmouse;
-
- port->activate = synaptics_pt_activate;
-}
-
-/*****************************************************************************
- * Driver initialization/cleanup functions
- ****************************************************************************/
-
-static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
-{
- dev->absmin[axis] = min;
- dev->absmax[axis] = max;
- dev->absfuzz[axis] = fuzz;
- dev->absflat[axis] = flat;
-
- set_bit(axis, dev->absbit);
-}
-
-static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
-{
- set_bit(EV_ABS, dev->evbit);
- set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
- set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
- set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
- set_bit(ABS_TOOL_WIDTH, dev->absbit);
-
- set_bit(EV_KEY, dev->evbit);
- set_bit(BTN_TOUCH, dev->keybit);
- set_bit(BTN_TOOL_FINGER, dev->keybit);
- set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
- set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
-
- set_bit(BTN_LEFT, dev->keybit);
- set_bit(BTN_RIGHT, dev->keybit);
- set_bit(BTN_FORWARD, dev->keybit);
- set_bit(BTN_BACK, dev->keybit);
- if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) {
- switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
- default:
- /*
- * if nExtBtn is greater than 8 it should be considered
- * invalid and treated as 0
- */
- break;
- case 8:
- set_bit(BTN_7, dev->keybit);
- set_bit(BTN_6, dev->keybit);
- case 6:
- set_bit(BTN_5, dev->keybit);
- set_bit(BTN_4, dev->keybit);
- case 4:
- set_bit(BTN_3, dev->keybit);
- set_bit(BTN_2, dev->keybit);
- case 2:
- set_bit(BTN_1, dev->keybit);
- set_bit(BTN_0, dev->keybit);
- break;
- }
- }
-
- clear_bit(EV_REL, dev->evbit);
- clear_bit(REL_X, dev->relbit);
- clear_bit(REL_Y, dev->relbit);
-}
-
-void synaptics_reset(struct psmouse *psmouse)
-{
- /* reset touchpad back to relative mode, gestures enabled */
- synaptics_mode_cmd(psmouse, 0);
-}
-
-static void synaptics_disconnect(struct psmouse *psmouse)
-{
- synaptics_reset(psmouse);
- kfree(psmouse->private);
-}
-
-static int synaptics_reconnect(struct psmouse *psmouse)
-{
- struct synaptics_data *priv = psmouse->private;
- struct synaptics_data old_priv = *priv;
-
- if (!synaptics_detect(psmouse))
- return -1;
-
- if (synaptics_query_hardware(psmouse)) {
- printk(KERN_ERR "Unable to query Synaptics hardware.\n");
- return -1;
- }
-
- if (old_priv.identity != priv->identity ||
- old_priv.model_id != priv->model_id ||
- old_priv.capabilities != priv->capabilities ||
- old_priv.ext_cap != priv->ext_cap)
- return -1;
-
- if (synaptics_set_mode(psmouse, 0)) {
- printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
- return -1;
- }
-
- return 0;
-}
-
-int synaptics_detect(struct psmouse *psmouse)
-{
- unsigned char param[4];
-
- param[0] = 0;
-
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
-
- return param[1] == 0x47;
-}
-
-int synaptics_init(struct psmouse *psmouse)
-{
- struct synaptics_data *priv;
-
- psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
- if (!priv)
- return -1;
- memset(priv, 0, sizeof(struct synaptics_data));
-
- if (synaptics_query_hardware(psmouse)) {
- printk(KERN_ERR "Unable to query Synaptics hardware.\n");
- goto init_fail;
- }
-
- if (synaptics_set_mode(psmouse, 0)) {
- printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
- goto init_fail;
- }
-
- priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
-
- if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
- synaptics_pt_create(psmouse);
-
- print_ident(priv);
- set_input_params(&psmouse->dev, priv);
-
- psmouse->disconnect = synaptics_disconnect;
- psmouse->reconnect = synaptics_reconnect;
+ serio->id.type = SERIO_PS_PSTHRU;
+ strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
+ strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
+ serio->write = synaptics_pt_write;
+ serio->parent = psmouse->ps2dev.serio;
- return 0;
+ psmouse->pt_activate = synaptics_pt_activate;
- init_fail:
- kfree(priv);
- return -1;
+ printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
+ serio_register_port(serio);
}
/*****************************************************************************
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
- if (SYN_CAP_EXTENDED(priv->capabilities) &&
- (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
- hw->up = ((buf[3] & 0x01)) ? 1 : 0;
- if (hw->left)
- hw->up = !hw->up;
- hw->down = ((buf[3] & 0x02)) ? 1 : 0;
- if (hw->right)
- hw->down = !hw->down;
+
+ if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
+ hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+ if (hw->w == 2)
+ hw->scroll = (signed char)(buf[1]);
}
+
+ if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+ hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+ hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
+ }
+
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
- ((buf[3] & 2) ? !hw->right : hw->right)) {
+ ((buf[0] ^ buf[3]) & 0x02)) {
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
/*
*/
break;
case 8:
- hw->b7 = ((buf[5] & 0x08)) ? 1 : 0;
- hw->b6 = ((buf[4] & 0x08)) ? 1 : 0;
+ hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
+ hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
case 6:
- hw->b5 = ((buf[5] & 0x04)) ? 1 : 0;
- hw->b4 = ((buf[4] & 0x04)) ? 1 : 0;
+ hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
+ hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
case 4:
- hw->b3 = ((buf[5] & 0x02)) ? 1 : 0;
- hw->b2 = ((buf[4] & 0x02)) ? 1 : 0;
+ hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
+ hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
case 2:
- hw->b1 = ((buf[5] & 0x01)) ? 1 : 0;
- hw->b0 = ((buf[4] & 0x01)) ? 1 : 0;
+ hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
+ hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
}
}
} else {
*/
static void synaptics_process_packet(struct psmouse *psmouse)
{
- struct input_dev *dev = &psmouse->dev;
+ struct input_dev *dev = psmouse->dev;
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state hw;
int num_fingers;
int finger_width;
+ int i;
synaptics_parse_hw_state(psmouse->packet, priv, &hw);
+ if (hw.scroll) {
+ priv->scroll += hw.scroll;
+
+ while (priv->scroll >= 4) {
+ input_report_key(dev, BTN_BACK, !hw.down);
+ input_sync(dev);
+ input_report_key(dev, BTN_BACK, hw.down);
+ input_sync(dev);
+ priv->scroll -= 4;
+ }
+ while (priv->scroll <= -4) {
+ input_report_key(dev, BTN_FORWARD, !hw.up);
+ input_sync(dev);
+ input_report_key(dev, BTN_FORWARD, hw.up);
+ input_sync(dev);
+ priv->scroll += 4;
+ }
+ return;
+ }
+
if (hw.z > 0) {
num_fingers = 1;
finger_width = 5;
input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
- input_report_key(dev, BTN_LEFT, hw.left);
- input_report_key(dev, BTN_RIGHT, hw.right);
- input_report_key(dev, BTN_FORWARD, hw.up);
- input_report_key(dev, BTN_BACK, hw.down);
- if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
- switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
- default:
- /*
- * if nExtBtn is greater than 8 it should be considered
- * invalid and treated as 0
- */
- break;
- case 8:
- input_report_key(dev, BTN_7, hw.b7);
- input_report_key(dev, BTN_6, hw.b6);
- case 6:
- input_report_key(dev, BTN_5, hw.b5);
- input_report_key(dev, BTN_4, hw.b4);
- case 4:
- input_report_key(dev, BTN_3, hw.b3);
- input_report_key(dev, BTN_2, hw.b2);
- case 2:
- input_report_key(dev, BTN_1, hw.b1);
- input_report_key(dev, BTN_0, hw.b0);
- break;
- }
+ input_report_key(dev, BTN_LEFT, hw.left);
+ input_report_key(dev, BTN_RIGHT, hw.right);
+
+ if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+ input_report_key(dev, BTN_MIDDLE, hw.middle);
+
+ if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+ input_report_key(dev, BTN_FORWARD, hw.up);
+ input_report_key(dev, BTN_BACK, hw.down);
+ }
+
+ for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+ input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
+
input_sync(dev);
}
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+ if (idx < 0 || idx > 4)
+ return 0;
+
switch (pkt_type) {
case SYN_NEWABS:
case SYN_NEWABS_RELAXED:
return SYN_NEWABS_STRICT;
}
-void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
- struct input_dev *dev = &psmouse->dev;
+ struct input_dev *dev = psmouse->dev;
struct synaptics_data *priv = psmouse->private;
input_regs(dev, regs);
if (psmouse->pktcnt >= 6) { /* Full packet received */
- if (priv->out_of_sync) {
- priv->out_of_sync = 0;
- printk(KERN_NOTICE "Synaptics driver resynced.\n");
- }
-
if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
- if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet))
- synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
- else
+ if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
+ if (psmouse->ps2dev.serio->child)
+ synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
+ } else
synaptics_process_packet(psmouse);
- psmouse->pktcnt = 0;
-
- } else if (psmouse->pktcnt &&
- !synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) {
- printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
- psmouse->pktcnt = 0;
- if (++priv->out_of_sync == psmouse_resetafter) {
- psmouse->state = PSMOUSE_IGNORE;
- printk(KERN_NOTICE "synaptics: issuing reconnect request\n");
- serio_reconnect(psmouse->serio);
- }
+
+ return PSMOUSE_FULL_PACKET;
}
+
+ return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
+ PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
}
+
+/*****************************************************************************
+ * Driver initialization/cleanup functions
+ ****************************************************************************/
+static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
+{
+ int i;
+
+ set_bit(EV_ABS, dev->evbit);
+ input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
+ input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
+ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
+ set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+ set_bit(EV_KEY, dev->evbit);
+ set_bit(BTN_TOUCH, dev->keybit);
+ set_bit(BTN_TOOL_FINGER, dev->keybit);
+ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+
+ set_bit(BTN_LEFT, dev->keybit);
+ set_bit(BTN_RIGHT, dev->keybit);
+
+ if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+ set_bit(BTN_MIDDLE, dev->keybit);
+
+ if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
+ SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
+ set_bit(BTN_FORWARD, dev->keybit);
+ set_bit(BTN_BACK, dev->keybit);
+ }
+
+ for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+ set_bit(BTN_0 + i, dev->keybit);
+
+ clear_bit(EV_REL, dev->evbit);
+ clear_bit(REL_X, dev->relbit);
+ clear_bit(REL_Y, dev->relbit);
+}
+
+void synaptics_reset(struct psmouse *psmouse)
+{
+ /* reset touchpad back to relative mode, gestures enabled */
+ synaptics_mode_cmd(psmouse, 0);
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+ synaptics_reset(psmouse);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int synaptics_reconnect(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+ struct synaptics_data old_priv = *priv;
+
+ if (synaptics_detect(psmouse, 0))
+ return -1;
+
+ if (synaptics_query_hardware(psmouse)) {
+ printk(KERN_ERR "Unable to query Synaptics hardware.\n");
+ return -1;
+ }
+
+ if (old_priv.identity != priv->identity ||
+ old_priv.model_id != priv->model_id ||
+ old_priv.capabilities != priv->capabilities ||
+ old_priv.ext_cap != priv->ext_cap)
+ return -1;
+
+ if (synaptics_set_absolute_mode(psmouse)) {
+ printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int synaptics_detect(struct psmouse *psmouse, int set_properties)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+
+ param[0] = 0;
+
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
+
+ if (param[1] != 0x47)
+ return -1;
+
+ if (set_properties) {
+ psmouse->vendor = "Synaptics";
+ psmouse->name = "TouchPad";
+ }
+
+ return 0;
+}
+
+#if defined(__i386__)
+#include <linux/dmi.h>
+static struct dmi_system_id toshiba_dmi_table[] = {
+ {
+ .ident = "Toshiba Satellite",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
+ },
+ },
+ {
+ .ident = "Toshiba Dynabook",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
+ },
+ },
+ {
+ .ident = "Toshiba Portege M300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
+ },
+ },
+ { }
+};
+#endif
+
+int synaptics_init(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv;
+
+ psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+ if (!priv)
+ return -1;
+
+ if (synaptics_query_hardware(psmouse)) {
+ printk(KERN_ERR "Unable to query Synaptics hardware.\n");
+ goto init_fail;
+ }
+
+ if (synaptics_set_absolute_mode(psmouse)) {
+ printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
+ goto init_fail;
+ }
+
+ priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
+
+ printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
+ SYN_ID_MODEL(priv->identity),
+ SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
+ priv->model_id, priv->capabilities, priv->ext_cap);
+
+ set_input_params(psmouse->dev, priv);
+
+ psmouse->protocol_handler = synaptics_process_byte;
+ psmouse->set_rate = synaptics_set_rate;
+ psmouse->disconnect = synaptics_disconnect;
+ psmouse->reconnect = synaptics_reconnect;
+ psmouse->pktsize = 6;
+ /* Synaptics can usually stay in sync without extra help */
+ psmouse->resync_time = 0;
+
+ if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+ synaptics_pt_create(psmouse);
+
+#if defined(__i386__)
+ /*
+ * Toshiba's KBC seems to have trouble handling data from
+ * Synaptics as full rate, switch to lower rate which is roughly
+ * thye same as rate of standard PS/2 mouse.
+ */
+ if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
+ printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
+ dmi_get_system_info(DMI_PRODUCT_NAME));
+ psmouse->rate = 40;
+ }
+#endif
+
+ return 0;
+
+ init_fail:
+ kfree(priv);
+ return -1;
+}
+
+