X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finput%2Fmouse%2Fsynaptics.c;h=ad5d0a85e960157b335915e693a87872e4a9bf96;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=101b8094720a4162b7941d1a45a4018358786fa0;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 101b80947..ad5d0a85e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "psmouse.h" #include "synaptics.h" @@ -50,7 +51,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned { 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; } @@ -65,7 +66,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char 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; } @@ -142,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; @@ -192,34 +160,48 @@ static int synaptics_query_hardware(struct psmouse *psmouse) 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; } +static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) +{ + struct synaptics_data *priv = psmouse->private; + + 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); +} + /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ 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)) 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; } @@ -231,13 +213,13 @@ 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) + if (child->pktsize == 4) serio_interrupt(ptport, packet[2], 0, NULL); } else serio_interrupt(ptport, packet[1], 0, NULL); @@ -245,12 +227,19 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet static void synaptics_pt_activate(struct psmouse *psmouse) { - struct psmouse *child = psmouse->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 && 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"); } } @@ -258,23 +247,22 @@ 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; - serio->parent = psmouse->serio; + serio->parent = psmouse->ps2dev.serio; psmouse->pt_activate = synaptics_pt_activate; - psmouse->serio->child = serio; + printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys); + serio_register_port(serio); } /***************************************************************************** @@ -301,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; @@ -349,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; @@ -358,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; @@ -460,7 +471,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) 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); @@ -470,8 +481,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r priv->pkt_type = synaptics_detect_pkt_type(psmouse); if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { - if (psmouse->serio->child) - synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); + if (psmouse->ps2dev.serio->child) + synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); } else synaptics_process_packet(psmouse); @@ -507,7 +518,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); } @@ -530,6 +542,7 @@ static void synaptics_disconnect(struct psmouse *psmouse) { synaptics_reset(psmouse); kfree(psmouse->private); + psmouse->private = NULL; } static int synaptics_reconnect(struct psmouse *psmouse) @@ -537,7 +550,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) struct synaptics_data *priv = psmouse->private; struct synaptics_data old_priv = *priv; - if (!synaptics_detect(psmouse)) + if (synaptics_detect(psmouse, 0)) return -1; if (synaptics_query_hardware(psmouse)) { @@ -551,7 +564,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) old_priv.ext_cap != priv->ext_cap) return -1; - if (synaptics_set_mode(psmouse, 0)) { + if (synaptics_set_absolute_mode(psmouse)) { printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); return -1; } @@ -559,51 +572,108 @@ static int synaptics_reconnect(struct psmouse *psmouse) return 0; } -int synaptics_detect(struct psmouse *psmouse) +int synaptics_detect(struct psmouse *psmouse, int set_properties) { + struct ps2dev *ps2dev = &psmouse->ps2dev; 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); + 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 param[1] == 0x47; + return 0; } +#if defined(__i386__) +#include +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"); goto init_fail; } - if (synaptics_set_mode(psmouse, 0)) { + 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; - 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->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;