fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / input / mouse / synaptics.c
index 3d41031..f0f9413 100644 (file)
@@ -143,39 +143,6 @@ static int synaptics_identify(struct psmouse *psmouse)
        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))
-                       printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
-                              (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
-               if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
-                       printk(KERN_INFO " -> middle button\n");
-               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;
@@ -229,7 +196,7 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
  ****************************************************************************/
 static int synaptics_pt_write(struct serio *serio, unsigned char c)
 {
-       struct psmouse *parent = serio->parent->private;
+       struct psmouse *parent = serio_get_drvdata(serio->parent);
        char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
 
        if (psmouse_sliced_command(parent, c))
@@ -246,26 +213,27 @@ static inline int synaptics_is_pt_packet(unsigned char *buf)
 
 static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
 {
-       struct psmouse *child = ptport->private;
+       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->type >= PSMOUSE_GENPS)
-                       serio_interrupt(ptport, packet[2], 0, NULL);
+               serio_interrupt(ptport, packet[1], 0);
+               serio_interrupt(ptport, packet[4], 0);
+               serio_interrupt(ptport, packet[5], 0);
+               if (child->pktsize == 4)
+                       serio_interrupt(ptport, packet[2], 0);
        } else
-               serio_interrupt(ptport, packet[1], 0, NULL);
+               serio_interrupt(ptport, packet[1], 0);
 }
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-       struct psmouse *child = psmouse->ps2dev.serio->child->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) {
-               if (child->type >= PSMOUSE_GENPS)
+               if (child->pktsize == 4)
                        priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
                else
                        priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
@@ -279,15 +247,13 @@ static void synaptics_pt_create(struct psmouse *psmouse)
 {
        struct serio *serio;
 
-       serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!serio) {
                printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
                return;
        }
 
-       memset(serio, 0, sizeof(struct serio));
-
-       serio->type = SERIO_PS_PSTHRU;
+       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;
@@ -295,7 +261,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
 
        psmouse->pt_activate = synaptics_pt_activate;
 
-       psmouse->ps2dev.serio->child = serio;
+       printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
+       serio_register_port(serio);
 }
 
 /*****************************************************************************
@@ -322,8 +289,11 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
                hw->left  = (buf[0] & 0x01) ? 1 : 0;
                hw->right = (buf[0] & 0x02) ? 1 : 0;
 
-               if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+               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;
@@ -370,7 +340,7 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
  */
 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;
@@ -379,6 +349,26 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 
        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;
@@ -440,11 +430,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 
 static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
 {
-       static unsigned char newabs_mask[]      = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
-       static unsigned char newabs_rel_mask[]  = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
-       static unsigned char newabs_rslt[]      = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
-       static unsigned char oldabs_mask[]      = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
-       static unsigned char oldabs_rslt[]      = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+       static const unsigned char newabs_mask[]        = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
+       static const unsigned char newabs_rel_mask[]    = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
+       static const unsigned char newabs_rslt[]        = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
+       static const unsigned char oldabs_mask[]        = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
+       static const unsigned char oldabs_rslt[]        = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
 
        if (idx < 0 || idx > 4)
                return 0;
@@ -479,13 +469,10 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
        return SYN_NEWABS_STRICT;
 }
 
-static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
 {
-       struct input_dev *dev = &psmouse->dev;
        struct synaptics_data *priv = psmouse->private;
 
-       input_regs(dev, regs);
-
        if (psmouse->pktcnt >= 6) { /* Full packet received */
                if (unlikely(priv->pkt_type == SYN_NEWABS))
                        priv->pkt_type = synaptics_detect_pkt_type(psmouse);
@@ -528,7 +515,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
        if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
                set_bit(BTN_MIDDLE, dev->keybit);
 
-       if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+       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);
        }
@@ -551,6 +539,7 @@ static void synaptics_disconnect(struct psmouse *psmouse)
 {
        synaptics_reset(psmouse);
        kfree(psmouse->private);
+       psmouse->private = NULL;
 }
 
 static int synaptics_reconnect(struct psmouse *psmouse)
@@ -604,14 +593,41 @@ int synaptics_detect(struct psmouse *psmouse, int set_properties)
        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 = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+       psmouse->private = priv = kzalloc(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");
@@ -625,17 +641,37 @@ int synaptics_init(struct psmouse *psmouse)
 
        priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
 
-       if (SYN_CAP_PASS_THROUGH(priv->capabilities))
-               synaptics_pt_create(psmouse);
+       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);
 
-       print_ident(priv);
-       set_input_params(&psmouse->dev, priv);
+       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->cleanup = synaptics_reset;
        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;