diff --git a/src/daemon/processmouse.c b/src/daemon/processmouse.c index 1d94ffe..7061909 100644 --- a/src/daemon/processmouse.c +++ b/src/daemon/processmouse.c @@ -46,6 +46,7 @@ int processMouse(int fd, Gpm_Event *event, Gpm_Type *type, int kd_mode) static int fine_dx, fine_dy, i, j, m, + obuttons, newB=0, /* old buttons and Type to chain events */ oldB=0, oldT=0; @@ -91,8 +92,18 @@ int processMouse(int fd, Gpm_Event *event, Gpm_Type *type, int kd_mode) event->modifiers = nEvent.modifiers; /* propagate modifiers */ /* propagate buttons */ + /* Change the button order */ + obuttons = nEvent.buttons; + nEvent.buttons = 0; + for (j = 0; j < 8; j++) { + if (obuttons & (1 << j)) { + nEvent.buttons |= which_mouse->opt_buts[j]; + } + } +#if 0 nEvent.buttons = ((which_mouse->opt_sequence)[nEvent.buttons&7]&7) | (nEvent.buttons & ~7); /* change the order */ +#endif oldB=newB; newB=nEvent.buttons; if (!i) event->buttons=nEvent.buttons; diff --git a/src/daemon/startup.c b/src/daemon/startup.c index e76b348..636f143 100644 --- a/src/daemon/startup.c +++ b/src/daemon/startup.c @@ -35,21 +35,9 @@ void startup(int argc, char **argv) { - int i, opt; + int i, j, opt; + char *p; - static struct { - char *in; - char *out; - } seq[] = { - {"123","01234567"}, - {"132","02134657"}, - {"213","01452367"}, /* warning: these must be readable as integers... */ - {"231","02461357"}, - {"312","04152637"}, - {"321","04261537"}, - {NULL,NULL} - }; - /* log to debug, who we are */ gpm_report(GPM_PR_DEBUG, GPM_MESS_VERSION); @@ -92,16 +80,23 @@ void startup(int argc, char **argv) which_mouse=mouse_table+i; /* used to access options */ if ((which_mouse->opt_accel) < 1) exit(usage("acceleration")); if ((which_mouse->opt_delta) < 2) exit(usage("delta")); - if (strlen((which_mouse->opt_sequence)) != 3 || atoi((which_mouse->opt_sequence))<100) + if (strlen(which_mouse->opt_sequence) <= 0) exit(usage("sequence")); - if ((which_mouse->opt_glidepoint_tap) > 3) exit(usage("glidepoint tap button")); - if ((which_mouse->opt_glidepoint_tap)) - (which_mouse->opt_glidepoint_tap)=GPM_B_LEFT >> ((which_mouse->opt_glidepoint_tap)-1); /* choose the sequence */ - for (opt=0; seq[opt].in && strcmp(seq[opt].in,(which_mouse->opt_sequence)); opt++) ; - if(!seq[opt].in) exit(usage("button sequence")); - (which_mouse->opt_sequence)=strdup(seq[opt].out); /* I can rewrite on it */ + for (j = 0; j < 9; j++) + which_mouse->opt_buts[j] = 1 << j; + + for (p = which_mouse->opt_sequence, j = 0; *p != '\0'; p++, j++) { + if ((*p < '0') || (*p > '9')) + exit(usage("button sequence")); + which_mouse->opt_buts[j] = (1 << (*p - '1')); + } + + if (which_mouse->opt_glidepoint_tap > 9) + exit(usage("glidepoint tap button")); + if (which_mouse->opt_glidepoint_tap) + which_mouse->opt_glidepoint_tap = which_mouse->opt_buts[which_mouse->opt_glidepoint_tap - 1]; /* look for the mouse type */ (which_mouse->m_type) = find_mouse_by_name((which_mouse->opt_type)); diff --git a/src/headers/daemon.h b/src/headers/daemon.h index 1313121..60c0189 100644 --- a/src/headers/daemon.h +++ b/src/headers/daemon.h @@ -97,6 +97,7 @@ struct mouse_features { char *opt_options; /* extra textual configuration */ Gpm_Type *m_type; int fd; + int opt_buts[9]; }; /************************************************************************* diff --git a/src/headers/gpmInt.h b/src/headers/gpmInt.h index 397d996..754d40d 100644 --- a/src/headers/gpmInt.h +++ b/src/headers/gpmInt.h @@ -54,6 +54,7 @@ #define GPM_AUX_ID_ERROR -1 #define GPM_AUX_ID_PS2 0 #define GPM_AUX_ID_IMPS2 3 +#define GPM_AUX_ID_EXPS2 4 /* these are shameless stolen from /usr/src/linux/include/linux/pc_keyb.h */ @@ -65,6 +66,7 @@ #define GPM_AUX_SET_SAMPLE 0xF3 /* Set sample rate */ #define GPM_AUX_ENABLE_DEV 0xF4 /* Enable aux device */ #define GPM_AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define GPM_AUX_DEFAULTS 0xF6 /* Reset to defaults */ #define GPM_AUX_RESET 0xFF /* Reset aux device */ #define GPM_AUX_ACK 0xFA /* Command byte ACK. */ diff --git a/src/mice.c b/src/mice.c index 52597ba..2e8f708 100644 --- a/src/mice.c +++ b/src/mice.c @@ -5,6 +5,7 @@ * Copyright (C) 1994-2000 Alessandro Rubini * Copyright (C) 1998,1999 Ian Zimmerman * Copyright (C) 2001-2008 Nico Schottelius + * Copyright (C) 2002 Zephaniah E. Hull * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,6 +56,7 @@ #include #include /* stat() */ #include /* select() */ +#include /* poll() */ #include /* MAJOR */ #include @@ -603,14 +605,21 @@ static int M_bm(Gpm_Event *state, unsigned char *data) /* equal to sun */ return 0; } +/* + * PS/2 mouse parser. + * Also called by the 'children' of the PS/2 mouse, for insanity sake. + * -- Zephaniah E. Hull. + */ static int M_ps2(Gpm_Event *state, unsigned char *data) { static int tap_active=0; /* there exist glidepoint ps2 mice */ - state->buttons= - !!(data[0]&1) * GPM_B_LEFT + - !!(data[0]&2) * GPM_B_RIGHT + - !!(data[0]&4) * GPM_B_MIDDLE; + state->wdx = state->wdy = 0; + + state->buttons = + ((data[0] & 0x02) ? (1 << 0) : 0) | // Right. + ((data[0] & 0x04) ? (1 << 1) : 0) | // Middle. + ((data[0] & 0x01) ? (1 << 2) : 0); // Left. if (data[0]==0 && (which_mouse->opt_glidepoint_tap)) /* by default this is false */ state->buttons = tap_active = (which_mouse->opt_glidepoint_tap); @@ -639,27 +648,28 @@ static int M_ps2(Gpm_Event *state, unsigned char *data) return 0; } +/* + * I cheat, because the two protocols are almost identical except for + * the 4th and 5th buttons, I just handle both. + * + * Note, the only thing that I've seen describe the 4th and 5th buttons + * for the IMPS/2 protocol is the X4 source, someone let me know if they + * actually see this used? + * -- Zephaniah E. Hull. + */ static int M_imps2(Gpm_Event *state, unsigned char *data) { - - static int tap_active=0; /* there exist glidepoint ps2 mice */ - state->wdx = state->wdy = 0; /* Clear them.. */ - state->dx = state->dy = state->wdx = state->wdy = 0; - - state->buttons= ((data[0] & 1) << 2) /* left */ - | ((data[0] & 6) >> 1); /* middle and right */ - - if (data[0]==0 && (which_mouse->opt_glidepoint_tap)) // by default this is false - state->buttons = tap_active = (which_mouse->opt_glidepoint_tap); - else if (tap_active) { - if (data[0]==8) - state->buttons = tap_active = 0; - else state->buttons = tap_active; - } + M_ps2(state, data); /* Standard movement.. */ state->dx = (data[0] & 0x10) ? data[1] - 256 : data[1]; state->dy = (data[0] & 0x20) ? -(data[2] - 256) : -data[2]; + + state->buttons += + ((data[0] & 0x40) ? (1 << 3) : 0) | // IMPS/2 Button 4 + ((data[0] & 0x80) ? (1 << 4) : 0) | // IMPS/2 Button 5 + ((data[3] & 0x10) ? (1 << 3) : 0) | // EXPS/2 Button 4 + ((data[3] & 0x20) ? (1 << 4) : 0); // EXPS/2 Button 5 /* The wheels.. */ unsigned char wheel = data[3] & 0x0f; @@ -723,17 +733,6 @@ static int M_netmouse(Gpm_Event *state, unsigned char *data) return 0; } -/* standard ps2 */ -static Gpm_Type *I_ps2(int fd, unsigned short flags, - struct Gpm_Type *type, int argc, char **argv) -{ - static unsigned char s[] = { 246, 230, 244, 243, 100, 232, 3, }; - write (fd, s, sizeof (s)); - usleep (30000); - tcflush (fd, TCIFLUSH); - return type; -} - static Gpm_Type *I_netmouse(int fd, unsigned short flags, struct Gpm_Type *type, int argc, char **argv) { @@ -1930,92 +1929,168 @@ static int read_mouse_id(int fd) * * Returns 0 if OK, or >0 if 1 or more errors occurred. */ -static int write_to_mouse(int fd, unsigned char *data, size_t len) +static int write_ps2(int fd, unsigned char cmd0, unsigned char cmd1, + size_t num, size_t rnum, unsigned long int sleep) { - int i; - int error = 0; - for (i = 0; i < len; i++) { - unsigned char c; - write(fd, &data[i], 1); - read(fd, &c, 1); - if (c != GPM_AUX_ACK) error++; + int i, error = 0, rcnt; + unsigned char cmd[2], ret[512]; + + cmd[0] = cmd0; + cmd[1] = cmd1; + + if (sleep == -1) + sleep = 50000; + + alarm(5); + rcnt = write(fd, cmd, num); + alarm(0); + if (rcnt != num) + return 1; + + usleep(sleep); + + alarm(5); + rcnt = read(fd, ret, rnum); + alarm(0); + + usleep(sleep); + + if (rcnt <= 0) + error++; + + for (i = 0; i < rcnt; i++) { + if (ret[i] != GPM_AUX_ACK) { + gpm_report(GPM_PR_ERR, "write_ps2: %d %d, %x", rcnt, i, ret[i]); + error++; + } } - /* flush any left-over input */ - usleep (30000); - tcflush (fd, TCIFLUSH); return(error); } +static Gpm_Type *get_mouse_type(char *name) +{ + Gpm_Type *type; + for (type = mice; type->fun; type++) { + if (strcmp(type->name, name) == 0) + return(type); + } + return NULL; +} + /* intellimouse, ps2 version: Ben Pfaff and Colin Plumb */ /* Autodetect: Steve Bennett */ -static Gpm_Type *I_imps2(int fd, unsigned short flags, struct Gpm_Type *type, - int argc, char **argv) +static Gpm_Type *I_ps2(int fd, unsigned short flags_unused, + struct Gpm_Type *type, int argc, char **argv) { - int id; - static unsigned char basic_init[] = { GPM_AUX_ENABLE_DEV, GPM_AUX_SET_SAMPLE, 100 }; - static unsigned char imps2_init[] = { GPM_AUX_SET_SAMPLE, 200, GPM_AUX_SET_SAMPLE, 100, GPM_AUX_SET_SAMPLE, 80, }; - static unsigned char ps2_init[] = { GPM_AUX_SET_SCALE11, GPM_AUX_ENABLE_DEV, GPM_AUX_SET_SAMPLE, 100, GPM_AUX_SET_RES, 3, }; + int id, error = 0, rate; - /* Do a basic init in case the mouse is confused */ - write_to_mouse(fd, basic_init, sizeof (basic_init)); + /* Flush any existing input. */ + tcflush(fd, TCIOFLUSH); - /* Now try again and make sure we have a PS/2 mouse */ - if (write_to_mouse(fd, basic_init, sizeof (basic_init)) != 0) { - gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_INIT); + if (write_ps2(fd, GPM_AUX_DEFAULTS, '\0', 1, 1, -1)) { + gpm_report(GPM_PR_ERR, "PS/2 mouse failed init"); return(NULL); } - /* Try to switch to 3 button mode */ - if (write_to_mouse(fd, imps2_init, sizeof (imps2_init)) != 0) { - gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_FAILED); - return(NULL); + // Magic to enable the IMPS/2 protocol. + if ((!strcmp(type->name, "imps2")) || (!strcmp(type->name, "autops2"))) { + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 200, 2, 2, -1); + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 100, 2, 2, -1); + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 80, 2, 2, -1); + if (error) { + gpm_report(GPM_PR_ERR, "imps2: PS/2 mouse failed (3 button) init"); + return(NULL); + } + } + if ((!strcmp(type->name, "exps2")) || (!strcmp(type->name, "autops2"))) { + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 200, 2, 2, -1); + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 200, 2, 2, -1); + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 80, 2, 2, -1); + if (error) { + gpm_report(GPM_PR_ERR, "exps2: PS/2 mouse failed (3 button) init"); + return (NULL); + } } - /* Read the mouse id */ - id = read_mouse_id(fd); - if (id == GPM_AUX_ID_ERROR) { - gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_MID_FAIL); - id = GPM_AUX_ID_PS2; + if (write_ps2(fd, GPM_AUX_SET_SCALE11, '\0', 1, 1, -1)) { + gpm_report(GPM_PR_ERR, "PS/2 mouse failed init: Unable to set 1:1 scale."); + return (NULL); } - /* And do the real initialisation */ - if (write_to_mouse(fd, ps2_init, sizeof (ps2_init)) != 0) { - gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_SETUP_FAIL); + if (which_mouse->opt_sample > 0) { + if (which_mouse->opt_sample >= 200) rate = 200; + else if (which_mouse->opt_sample >= 100) rate = 100; + else if (which_mouse->opt_sample >= 80) rate = 80; + else if (which_mouse->opt_sample >= 60) rate = 60; + else if (which_mouse->opt_sample >= 40) rate = 40; + else if (which_mouse->opt_sample >= 20) rate = 20; + else if (which_mouse->opt_sample >= 10) rate = 10; + else rate = 100; + } else { + rate = 100; } - if (id == GPM_AUX_ID_IMPS2) { - /* Really an intellipoint, so initialise 3 button mode (4 byte packets) */ - gpm_report(GPM_PR_INFO,GPM_MESS_IMPS2_AUTO); - return type; + if (write_ps2(fd, GPM_AUX_SET_SAMPLE, rate, 2, 1, -1)) { + gpm_report(GPM_PR_ERR, "PS/2 mouse failed init: Unable to set rate."); + return (NULL); } - if (id != GPM_AUX_ID_PS2) { - gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_BAD_ID, id); + + if (!strcmp(type->name, "autops2")) { + /* Read the mouse id */ + id = read_mouse_id(fd); + + switch (id) { + case GPM_AUX_ID_ERROR: + gpm_report(GPM_PR_ERR, "Unable to read PS/2 mouse ID: Using base PS/2 protocol.\n"); + write_ps2(fd, GPM_AUX_SET_STREAM, '\0', 1, 1, 1); + write_ps2(fd, GPM_AUX_ENABLE_DEV, '\0', 1, 1, 1); + return get_mouse_type("ps2"); + case GPM_AUX_ID_PS2: + gpm_report(GPM_PR_INFO, "Detected base PS/2 protocol mouse."); + write_ps2(fd, GPM_AUX_SET_STREAM, '\0', 1, 1, 1); + write_ps2(fd, GPM_AUX_ENABLE_DEV, '\0', 1, 1, 1); + return get_mouse_type("ps2"); + case GPM_AUX_ID_IMPS2: + gpm_report(GPM_PR_INFO, "Detected IMPS/2 protocol mouse."); + write_ps2(fd, GPM_AUX_SET_STREAM, '\0', 1, 1, 1); + write_ps2(fd, GPM_AUX_ENABLE_DEV, '\0', 1, 1, 1); + return get_mouse_type("imps2"); + case GPM_AUX_ID_EXPS2: + gpm_report(GPM_PR_INFO, "Detected EXPS/2 protocol mouse."); + write_ps2(fd, GPM_AUX_SET_STREAM, '\0', 1, 1, 1); + write_ps2(fd, GPM_AUX_ENABLE_DEV, '\0', 1, 1, 1); + return get_mouse_type("exps2"); + default: + gpm_report(GPM_PR_ERR, "Unknown mouse ID, using base PS/2 protocol."); + write_ps2(fd, GPM_AUX_SET_STREAM, '\0', 1, 1, 1); + write_ps2(fd, GPM_AUX_ENABLE_DEV, '\0', 1, 1, 1); + return get_mouse_type("ps2"); + } } - else gpm_report(GPM_PR_INFO,GPM_MESS_IMPS2_PS2); - for (type=mice; type->fun; type++) - if (strcmp(type->name, "ps2") == 0) return(type); + write_ps2(fd, GPM_AUX_SET_STREAM, '\0', 1, 1, 1); + write_ps2(fd, GPM_AUX_ENABLE_DEV, '\0', 1, 1, 1); - /* ps2 was not found!!! */ - return(NULL); + return type; } -/* - * This works with Dexxa Optical Mouse, but because in X same initstring - * is named ExplorerPS/2 so I named it in the same way. - */ -static Gpm_Type *I_exps2(int fd, unsigned short flags, - struct Gpm_Type *type, int argc, char **argv) +/* PS/2 Init */ +static Gpm_Type *I_fuimps2(int fd, unsigned short flags, + struct Gpm_Type *type, int argc, char **argv) { - static unsigned char s1[] = { 243, 200, 243, 200, 243, 80, }; + int error = 0; if (check_no_argv(argc, argv)) return NULL; - write (fd, s1, sizeof (s1)); - usleep (30000); - tcflush (fd, TCIFLUSH); + // Magic to enable the IMPS/2 protocol. + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 200, 2, 2, -1); + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 100, 2, 2, -1); + error += write_ps2(fd, GPM_AUX_SET_SAMPLE, 80, 2, 2, -1); + if (error) + gpm_report(GPM_PR_ERR, "fuimps2: %d errors in init, ignoring.", error); + return type; } @@ -2409,9 +2484,12 @@ Gpm_Type mice[]={ "", M_evdev, I_empty, STD_FLG, {0x00, 0x00, 0x00, 0x00} , 16, 16, 0, 0, NULL}, #endif /* HAVE_LINUX_INPUT_H */ - {"exps2", "IntelliMouse Explorer (ps2) - 3 buttons, wheel unused", - "ExplorerPS/2", M_imps2, I_exps2, STD_FLG, - {0xc0, 0x00, 0x00, 0x00}, 4, 1, 0, 0, 0}, + {"exps2", "IntelliMouse Explorer (ps2) - 3 buttons (wheel is repeated).", + "ExplorerPS/2", M_imps2, I_ps2, STD_FLG, + {0xc0, 0x00, 0x00, 0x00}, 4, 1, 0, 0, 0}, + {"autops2","For PS/2 type mouse, specific protocol will be auto detected", + "", M_ps2, I_ps2, STD_FLG, + {0xc0, 0x00, 0x00, 0x00}, 3, 1, 0, 0, 0}, #ifdef HAVE_LINUX_JOYSTICK_H {"js", "For joystick mouse emulation", "Joystick", M_js, NULL, 0, @@ -2423,10 +2501,14 @@ Gpm_Type mice[]={ {"gunze", "Gunze touch-screens (only button-1 events, by now)", "", M_gunze, I_gunze, STD_FLG, {0xF9, 0x50, 0xF0, 0x30}, 11, 1, 0, 1, NULL}, - {"imps2","For the Microsoft IntelliMouse on a PS/2 port (round\n" - " connector with 6 pins), 3 buttons (wheel is repeated).", - "", M_imps2, I_imps2, STD_FLG, + {"imps2","For the Microsoft IntelliMouse on a PS/2 port\n" + "(round connector with 6 pins), 3 buttons (wheel is repeated).", + "", M_imps2, I_ps2, STD_FLG, {0xC0, 0x00, 0x00, 0x00}, 4, 1, 0, 0, R_imps2}, + {"fuimps2","For BROKEN wheel mice on a PS/2 port\n" + "(round connector with 6 pins), 3 buttons (wheel is repeated).", + "", M_imps2, I_fuimps2, STD_FLG, + {0xc0, 0x00, 0x00, 0x00}, 4, 1, 0, 0, 0}, {"logi", "For old serial Logitech mice.", "Logitech", M_logi, I_logi, CS8 | CSTOPB | STD_FLG, {0xe0, 0x80, 0x80, 0x00}, 3, 3, 0, 0, 0}, @@ -2463,10 +2545,12 @@ Gpm_Type mice[]={ " Try it if '-t ms' does not work.", "", M_bare, I_pnp, CS7 | STD_FLG, {0x40, 0x40, 0x40, 0x00}, 3, 1, 0, 0, 0}, - {"ps2", "For most busmice connected to a PS/2 port (round with 6 metal\n" - " pins).", + {"ps2", "For PS/2 mice (round with 6 metal pins).\n", "PS/2", M_ps2, I_ps2, STD_FLG, {0xc0, 0x00, 0x00, 0x00}, 3, 1, 0, 0, R_ps2}, + {"fups2", "For /BROKEN/ PS/2 mice (round with 6 metal pins).\n", + "PS/2", M_ps2, I_empty, STD_FLG, + {0xc0, 0x00, 0x00, 0x00}, 3, 1, 0, 0, 0}, {"sun", "For Sun (Sparc) mice.", "", M_sun, I_serial, CS8 | CSTOPB | STD_FLG, {0xf8, 0x80, 0x00, 0x00}, 3, 1, 0, 0, R_sun},