X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finput%2Fmouse%2Flogips2pp.c;h=d3ddea26b8ca65fec6f714032425d50e801bda3a;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=0063af0379d6ce79b4e1bd90404cc1c302f2c4ca;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 0063af037..d3ddea26b 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -11,6 +11,7 @@ #include #include +#include #include "psmouse.h" #include "logips2pp.h" @@ -18,6 +19,7 @@ #define PS2PP_KIND_WHEEL 1 #define PS2PP_KIND_MX 2 #define PS2PP_KIND_TP3 3 +#define PS2PP_KIND_TRACKMAN 4 /* Logitech mouse features */ #define PS2PP_WHEEL 0x01 @@ -28,22 +30,30 @@ #define PS2PP_NAV_BTN 0x20 struct ps2pp_info { - const int model; - unsigned const int kind; - unsigned const int features; + u8 model; + u8 kind; + u16 features; }; /* * Process a PS2++ or PS2T++ packet. */ -void ps2pp_process_packet(struct psmouse *psmouse) +static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) { - struct input_dev *dev = &psmouse->dev; - unsigned char *packet = psmouse->packet; + struct input_dev *dev = psmouse->dev; + unsigned char *packet = psmouse->packet; + + if (psmouse->pktcnt < 3) + return PSMOUSE_GOOD_DATA; + +/* + * Full packet accumulated, process it + */ if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { + /* Logitech extended packet */ switch ((packet[1] >> 4) | (packet[0] & 0x30)) { case 0x0d: /* Mouse extra info */ @@ -78,11 +88,20 @@ void ps2pp_process_packet(struct psmouse *psmouse) (packet[1] >> 4) | (packet[0] & 0x30)); #endif } - - packet[0] &= 0x0f; - packet[1] = 0; - packet[2] = 0; + } else { + /* Standard PS/2 motion data */ + input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); + input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); } + + input_report_key(dev, BTN_LEFT, packet[0] & 1); + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); + + input_sync(dev); + + return PSMOUSE_FULL_PACKET; + } /* @@ -97,7 +116,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha if (psmouse_sliced_command(psmouse, command)) return -1; - if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) + if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300)) return -1; return 0; @@ -108,47 +127,84 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha * enabled if we do nothing to it. Of course I put this in because I want it * disabled :P * 1 - enabled (if previously disabled, also default) - * 0/2 - disabled + * 0 - disabled */ -static void ps2pp_set_smartscroll(struct psmouse *psmouse) +static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll) { + struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; + if (smartscroll > 1) + smartscroll = 1; + ps2pp_cmd(psmouse, param, 0x32); param[0] = 0; - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - - if (psmouse_smartscroll < 2) { - /* 0 - disabled, 1 - enabled */ - param[0] = psmouse_smartscroll; - psmouse_command(psmouse, 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); + + param[0] = smartscroll; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); +} + +static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf) +{ + return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0); +} + +static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count) +{ + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest || value > 1) + return -EINVAL; + + ps2pp_set_smartscroll(psmouse, value); + psmouse->smartscroll = value; + return count; } +PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL, + ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll); + /* * Support 800 dpi resolution _only_ if the user wants it (there are good * reasons to not use it even if the mouse supports it, and of course there are * also good reasons to use it, let the user decide). */ -void ps2pp_set_800dpi(struct psmouse *psmouse) +static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution) { - unsigned char param = 3; - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, ¶m, PSMOUSE_CMD_SETRES); + if (resolution > 400) { + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param = 3; + + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); + ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); + psmouse->resolution = 800; + } else + psmouse_set_resolution(psmouse, resolution); } -static struct ps2pp_info *get_model_info(unsigned char model) +static void ps2pp_disconnect(struct psmouse *psmouse) { - static struct ps2pp_info ps2pp_list[] = { + device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); +} + +static const struct ps2pp_info *get_model_info(unsigned char model) +{ + static const struct ps2pp_info ps2pp_list[] = { { 12, 0, PS2PP_SIDE_BTN}, { 13, 0, 0 }, + { 15, PS2PP_KIND_MX, /* MX1000 */ + PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, { 40, 0, PS2PP_SIDE_BTN }, { 41, 0, PS2PP_SIDE_BTN }, { 42, 0, PS2PP_SIDE_BTN }, @@ -157,34 +213,45 @@ static struct ps2pp_info *get_model_info(unsigned char model) { 51, 0, 0 }, { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 61, PS2PP_KIND_MX, + { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */ + { 61, PS2PP_KIND_MX, /* MX700 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX700 */ + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, + { 66, PS2PP_KIND_MX, /* MX3100 reciver */ + PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, { 73, 0, PS2PP_SIDE_BTN }, { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 79, PS2PP_KIND_TRACKMAN, PS2PP_WHEEL }, /* TrackMan with wheel */ { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 87, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 96, 0, 0 }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, - { 100, PS2PP_KIND_MX, + { 99, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 100, PS2PP_KIND_MX, /* MX510 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX510 */ - { 112, PS2PP_KIND_MX, + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, + { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */ + { 112, PS2PP_KIND_MX, /* MX500 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX500 */ - { 114, PS2PP_KIND_MX, + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, + { 114, PS2PP_KIND_MX, /* MX310 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | - PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, /* M310 */ - { } + PS2PP_TASK_BTN | PS2PP_EXTRA_BTN } }; int i; - for (i = 0; ps2pp_list[i].model; i++) + for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++) if (model == ps2pp_list[i].model) return &ps2pp_list[i]; + + printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); return NULL; } @@ -192,27 +259,31 @@ static struct ps2pp_info *get_model_info(unsigned char model) * Set up input device's properties based on the detected mouse model. */ -static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info) +static void ps2pp_set_model_properties(struct psmouse *psmouse, + const struct ps2pp_info *model_info, + int using_ps2pp) { + struct input_dev *input_dev = psmouse->dev; + if (model_info->features & PS2PP_SIDE_BTN) - set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_SIDE, input_dev->keybit); if (model_info->features & PS2PP_EXTRA_BTN) - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_EXTRA, input_dev->keybit); if (model_info->features & PS2PP_TASK_BTN) - set_bit(BTN_TASK, psmouse->dev.keybit); + set_bit(BTN_TASK, input_dev->keybit); if (model_info->features & PS2PP_NAV_BTN) { - set_bit(BTN_FORWARD, psmouse->dev.keybit); - set_bit(BTN_BACK, psmouse->dev.keybit); + set_bit(BTN_FORWARD, input_dev->keybit); + set_bit(BTN_BACK, input_dev->keybit); } if (model_info->features & PS2PP_WHEEL) - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_WHEEL, input_dev->relbit); if (model_info->features & PS2PP_HWHEEL) - set_bit(REL_HWHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, input_dev->relbit); switch (model_info->kind) { case PS2PP_KIND_WHEEL: @@ -226,6 +297,20 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_inf case PS2PP_KIND_TP3: psmouse->name = "TouchPad 3"; break; + + case PS2PP_KIND_TRACKMAN: + psmouse->name = "TrackMan"; + break; + + default: + /* + * Set name to "Mouse" only when using PS2++, + * otherwise let other protocols define suitable + * name + */ + if (using_ps2pp) + psmouse->name = "Mouse"; + break; } } @@ -238,46 +323,51 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_inf int ps2pp_init(struct psmouse *psmouse, int set_properties) { + struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; - unsigned char protocol = PSMOUSE_PS2; unsigned char model, buttons; - struct ps2pp_info *model_info; + const struct ps2pp_info *model_info; + int use_ps2pp = 0; + int error; param[0] = 0; - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); param[1] = 0; - psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); + + if (!param[1]) + return -1; + + model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + buttons = param[1]; - if (param[1] != 0) { - model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); - buttons = param[1]; - model_info = get_model_info(model); + if ((model_info = get_model_info(model)) != NULL) { /* * Do Logitech PS2++ / PS2T++ magic init. */ - if (model == 97) { /* Touch Pad 3 */ + if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */ /* Unprotect RAM */ param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; - psmouse_command(psmouse, param, 0x30d1); + ps2_command(ps2dev, param, 0x30d1); /* Enable features */ param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; - psmouse_command(psmouse, param, 0x30d1); + ps2_command(ps2dev, param, 0x30d1); /* Enable PS2++ */ param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; - psmouse_command(psmouse, param, 0x30d1); + ps2_command(ps2dev, param, 0x30d1); param[0] = 0; - if (!psmouse_command(psmouse, param, 0x13d1) && + if (!ps2_command(ps2dev, param, 0x13d1) && param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { - protocol = PSMOUSE_PS2TPP; + use_ps2pp = 1; } - } else if (get_model_info(model) != NULL) { + } else { param[0] = param[1] = param[2] = 0; ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ @@ -286,25 +376,42 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && (param[2] & 0x03) == ((param[1] >> 2) & 3)) { - ps2pp_set_smartscroll(psmouse); - protocol = PSMOUSE_PS2PP; + ps2pp_set_smartscroll(psmouse, psmouse->smartscroll); + use_ps2pp = 1; } } + } - if (set_properties) { - psmouse->vendor = "Logitech"; - psmouse->model = model; + if (set_properties) { + psmouse->vendor = "Logitech"; + psmouse->model = model; + + if (use_ps2pp) { + psmouse->protocol_handler = ps2pp_process_byte; + psmouse->pktsize = 3; + + if (model_info->kind != PS2PP_KIND_TP3) { + psmouse->set_resolution = ps2pp_set_resolution; + psmouse->disconnect = ps2pp_disconnect; + + error = device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_smartscroll.dattr); + if (error) { + printk(KERN_ERR + "logips2pp.c: failed to create smartscroll " + "sysfs attribute, error: %d\n", error); + return -1; + } + } + } - if (buttons < 3) - clear_bit(BTN_MIDDLE, psmouse->dev.keybit); - if (buttons < 2) - clear_bit(BTN_RIGHT, psmouse->dev.keybit); + if (buttons < 3) + clear_bit(BTN_MIDDLE, psmouse->dev->keybit); - if (model_info) - ps2pp_set_model_properties(psmouse, model_info); - } + if (model_info) + ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); } - return protocol; + return use_ps2pp ? 0 : -1; }