vserver 2.0 rc7
[linux-2.6.git] / drivers / input / mouse / synaptics.c
index 3d41031..36c7212 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,7 +213,7 @@ 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);
@@ -260,7 +227,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
 
 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 */
@@ -287,7 +255,7 @@ static void synaptics_pt_create(struct psmouse *psmouse)
 
        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 +263,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 +291,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;
@@ -379,6 +351,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;
@@ -528,7 +520,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 +544,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,6 +598,20 @@ 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"),
+               },
+       },
+       { }
+};
+#endif
+
 int synaptics_init(struct psmouse *psmouse)
 {
        struct synaptics_data *priv;
@@ -625,10 +633,11 @@ 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);
 
        psmouse->protocol_handler = synaptics_process_byte;
@@ -637,6 +646,21 @@ int synaptics_init(struct psmouse *psmouse)
        psmouse->reconnect = synaptics_reconnect;
        psmouse->pktsize = 6;
 
+       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 Satellite detected, limiting rate to 40pps.\n");
+               psmouse->rate = 40;
+       }
+#endif
+
        return 0;
 
  init_fail: