On Mon, Sep 27, 2010 at 11:42:35PM +0600, Alexandr Shadchin wrote: > On Fri, Sep 24, 2010 at 05:40:37PM +0400, Alexandr Shadchin wrote: > > Hi! > > > > Paul Irofti proposed to split the diff in a few easy steps. > > Step 1 - merge drivers pms and pmsi. > > > > Step 2 - cleanup, standardization of interfaces and preparation > for easy addition of new devices. Now the resume of work in polling mode. >
Regen for -current. Also small improvements: 1) add function pms_dev_reset() 2) in struct pms_protocol add function sync() - for check synchronization, proc () - for processing packet. -- Alexandr Shadchin Index: pms.c =================================================================== RCS file: /cvs/src/sys/dev/pckbc/pms.c,v retrieving revision 1.5 diff -u -p -r1.5 pms.c --- pms.c 27 Sep 2010 18:16:25 -0000 1.5 +++ pms.c 29 Sep 2010 14:41:51 -0000 @@ -38,41 +38,100 @@ #include <dev/wscons/wsconsio.h> #include <dev/wscons/wsmousevar.h> +#ifdef PMS_DEBUG +#define DPRINTF(...) do { if (pmsdebug) printf(__VA_ARGS__); } while(0) +#define DPRINTFN(n, ...) do { \ + if (pmsdebug > (n)) printf(__VA_ARGS__); \ +} while(0) +int pmsdebug = 1; +#else +#define DPRINTF(...) +#define DPRINTFN(n, ...) +#endif + +#define DEVNAME(sc) ((sc)->sc_dev.dv_xname) + +/* PS/2 mouse data packet */ +#define PMS_PS2_BUTTONSMASK 0x07 +#define PMS_PS2_BUTTON1 0x01 /* left */ +#define PMS_PS2_BUTTON2 0x04 /* middle */ +#define PMS_PS2_BUTTON3 0x02 /* right */ +#define PMS_PS2_XNEG 0x10 +#define PMS_PS2_YNEG 0x20 + +#define PMS_BUTTON1DOWN 0x01 /* left */ +#define PMS_BUTTON2DOWN 0x02 /* middle */ +#define PMS_BUTTON3DOWN 0x04 /* right */ + +struct pms_softc; + +struct pms_protocol { + int type; +#define PMS_STANDARD 0 +#define PMS_INTELLI 1 + int packetsize; + int syncmask; + int syncval; + int (*enable)(struct pms_softc *); + int (*sync)(struct pms_softc *, int); + void (*proc)(struct pms_softc *, int *, int *, int *, u_int *); +}; + struct pms_softc { /* driver status information */ struct device sc_dev; pckbc_tag_t sc_kbctag; int sc_kbcslot; + int poll; int sc_state; #define PMS_STATE_DISABLED 0 #define PMS_STATE_ENABLED 1 #define PMS_STATE_SUSPENDED 2 - int intelli; + struct pms_protocol protocol; + unsigned char packet[8]; + int inputstate; - u_int buttons, oldbuttons; /* mouse button status */ - signed char dx, dy; + u_int buttons; /* mouse button status */ struct device *sc_wsmousedev; }; -int pmsprobe(struct device *, void *, void *); -void pmsattach(struct device *, struct device *, void *); -int pmsactivate(struct device *, int); -void pmsinput(void *, int); +int pmsprobe(struct device *, void *, void *); +void pmsattach(struct device *, struct device *, void *); +int pmsactivate(struct device *, int); -struct cfattach pms_ca = { - sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, - pmsactivate -}; +void pmsinput(void *, int); int pms_change_state(struct pms_softc *, int); int pms_ioctl(void *, u_long, caddr_t, int, struct proc *); int pms_enable(void *); void pms_disable(void *); -int pms_setintellimode(pckbc_tag_t, pckbc_slot_t); +int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int); +int pms_get_devid(struct pms_softc *, u_char *); +int pms_get_status(struct pms_softc *, u_char *); +int pms_set_rate(struct pms_softc *, int); +int pms_set_resolution(struct pms_softc *, int); +int pms_set_scaling(struct pms_softc *, int); +void pms_dev_reset(struct pms_softc *); +void pms_dev_disable(struct pms_softc *); +void pms_dev_enable(struct pms_softc *); + +int pms_enable_intelli(struct pms_softc *); + +int pms_sync_generic(struct pms_softc *, int); +void pms_proc_generic(struct pms_softc *, int *, int *, int *, u_int *); + +struct cfattach pms_ca = { + sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, + pmsactivate +}; + +struct cfdriver pms_cd = { + NULL, "pms", DV_DULL +}; const struct wsmouse_accessops pms_accessops = { pms_enable, @@ -80,104 +139,54 @@ const struct wsmouse_accessops pms_acces pms_disable, }; -int -pms_setintellimode(pckbc_tag_t tag, pckbc_slot_t slot) -{ - u_char cmd[2], resp[1]; - int i, res; - static const u_char rates[] = {200, 100, 80}; - - cmd[0] = PMS_SET_SAMPLE; - for (i = 0; i < 3; i++) { - cmd[1] = rates[i]; - res = pckbc_enqueue_cmd(tag, slot, cmd, 2, 0, 0, NULL); - if (res) - return (0); - } - - cmd[0] = PMS_SEND_DEV_ID; - res = pckbc_enqueue_cmd(tag, slot, cmd, 1, 1, 1, resp); - if (res || resp[0] != 3) - return (0); - - return (1); -} +const struct pms_protocol pms_protocols[] = { + /* Generic PS/2 mouse */ + {PMS_STANDARD, 3, 0xc0, 0x00, + NULL, pms_sync_generic, pms_proc_generic}, + /* Microsoft IntelliMouse */ + {PMS_INTELLI, 4, 0x08, 0x08, + pms_enable_intelli, pms_sync_generic, pms_proc_generic} +}; int -pmsprobe(parent, match, aux) - struct device *parent; - void *match; - void *aux; +pmsprobe(struct device *parent, void *match, void *aux) { struct pckbc_attach_args *pa = aux; - u_char cmd[1], resp[2]; int res; + u_char cmd[1], resp[2]; if (pa->pa_slot != PCKBC_AUX_SLOT) - return (0); + return 0; - /* Flush any garbage. */ + /* flush any garbage */ pckbc_flush(pa->pa_tag, pa->pa_slot); /* reset the device */ cmd[0] = PMS_RESET; res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); - if (res) { -#ifdef DEBUG - printf("pmsprobe: reset error %d\n", res); -#endif - return (0); - } - if (resp[0] != PMS_RSTDONE) { - printf("pmsprobe: reset response 0x%x\n", resp[0]); - return (0); - } - - /* get type number (0 = mouse) */ - if (resp[1] != 0) { -#ifdef DEBUG - printf("pmsprobe: type 0x%x\n", resp[1]); -#endif - return (0); + if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { + DPRINTF("pms: reset error (%d, response 0x%x, type 0x%x)\n", + res, resp[0], resp[1]); + return 0; } - return (10); + return 1; } void -pmsattach(parent, self, aux) - struct device *parent, *self; - void *aux; +pmsattach(struct device *parent, struct device *self, void *aux) { struct pms_softc *sc = (void *)self; struct pckbc_attach_args *pa = aux; struct wsmousedev_attach_args a; - u_char cmd[1], resp[2]; - int res; sc->sc_kbctag = pa->pa_tag; sc->sc_kbcslot = pa->pa_slot; printf("\n"); - /* Flush any garbage. */ - pckbc_flush(pa->pa_tag, pa->pa_slot); - - /* reset the device */ - cmd[0] = PMS_RESET; - res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); -#ifdef DEBUG - if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { - printf("pmsattach: reset error\n"); - return; - } -#endif - - sc->inputstate = 0; - sc->oldbuttons = 0; - pckbc_set_inputhandler(sc->sc_kbctag, sc->sc_kbcslot, - pmsinput, sc, sc->sc_dev.dv_xname); + pmsinput, sc, DEVNAME(sc)); a.accessops = &pms_accessops; a.accesscookie = sc; @@ -191,11 +200,8 @@ pmsattach(parent, self, aux) sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); /* no interrupts until enabled */ - cmd[0] = PMS_DEV_DISABLE; - res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 0, NULL, 0); - if (res) - printf("pmsattach: disable error\n"); - pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0); + sc->poll = 1; + pms_change_state(sc, PMS_STATE_DISABLED); } int @@ -213,197 +219,304 @@ pmsactivate(struct device *self, int act pms_change_state(sc, PMS_STATE_ENABLED); break; } - return (0); + return 0; } int -pms_change_state(struct pms_softc *sc, int newstate) +pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen) +{ + if (sc->poll) { + return pckbc_poll_cmd(sc->sc_kbctag, sc->sc_kbcslot, + cmd, len, resplen, resp, 1); + } else { + return pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, + cmd, len, resplen, 1, resp); + } +} + +int +pms_get_devid(struct pms_softc *sc, u_char *resp) +{ + u_char cmd[1]; + + cmd[0] = PMS_SEND_DEV_ID; + return pms_cmd(sc, cmd, 1, resp, 1); +} + +int +pms_get_status(struct pms_softc *sc, u_char *resp) { u_char cmd[1]; + + cmd[0] = PMS_SEND_DEV_STATUS; + return pms_cmd(sc, cmd, 1, resp, 3); +} + +int +pms_set_rate(struct pms_softc *sc, int value) +{ + u_char cmd[2]; + + cmd[0] = PMS_SET_SAMPLE; + cmd[1] = value; + return pms_cmd(sc, cmd, 2, NULL, 0); +} + +int +pms_set_resolution(struct pms_softc *sc, int value) +{ + u_char cmd[2]; + + cmd[0] = PMS_SET_RES; + cmd[1] = value; + return pms_cmd(sc, cmd, 2, NULL, 0); +} + +int +pms_set_scaling(struct pms_softc *sc, int scale) +{ + u_char cmd[1]; + + switch (scale) { + case 1: + default: + cmd[0] = PMS_SET_SCALE11; + break; + case 2: + cmd[0] = PMS_SET_SCALE21; + break; + } + return pms_cmd(sc, cmd, 1, NULL, 0); +} + +void +pms_dev_reset(struct pms_softc *sc) +{ int res; + u_char cmd[1], resp[2]; + + cmd[0] = PMS_RESET; + res = pms_cmd(sc, cmd, 1, resp, 2); +#ifdef PMS_DEBUG + if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { + DPRINTF("%s: reset error (%d, response 0x%x, type 0x%x)\n", + DEVNAME(sc), res, resp[0], resp[1]); + } +#endif +} + +void +pms_dev_disable(struct pms_softc *sc) +{ + int res; + u_char cmd[1]; + + cmd[0] = PMS_DEV_DISABLE; + res = pms_cmd(sc, cmd, 1, NULL, 0); +#ifdef PMS_DEBUG + if (res) + DPRINTF("%s: disable error (%d)\n", DEVNAME(sc), res); +#endif + pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0); +} + +void +pms_dev_enable(struct pms_softc *sc) +{ + int i, res; + u_char cmd[1]; + + pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1); + + pms_dev_reset(sc); + + sc->protocol = pms_protocols[0]; + for (i = 1; i < nitems(pms_protocols); i++) + if (pms_protocols[i].enable(sc)) + sc->protocol = pms_protocols[i]; + + DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol.type); + cmd[0] = PMS_DEV_ENABLE; + res = pms_cmd(sc, cmd, 1, NULL, 0); +#ifdef PMS_DEBUG + if (res) + DPRINTF("%s: enable error (%d)\n", DEVNAME(sc), res); +#endif +} + +int +pms_enable_intelli(struct pms_softc *sc) +{ + static const int rates[] = {200, 100, 80}; + int res, i; + u_char resp; + + for (i = 0; i < nitems(rates); i++) + if (pms_set_rate(sc, rates[i])) + return 0; + + res = pms_get_devid(sc, &resp); + if (res || (resp != 0x03)) + return 0; + + return 1; +} + +int +pms_change_state(struct pms_softc *sc, int newstate) +{ switch (newstate) { case PMS_STATE_ENABLED: if (sc->sc_state == PMS_STATE_ENABLED) return EBUSY; - sc->inputstate = 0; - sc->oldbuttons = 0; - - pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1); - pckbc_flush(sc->sc_kbctag, sc->sc_kbcslot); - sc->intelli = pms_setintellimode(sc->sc_kbctag, sc->sc_kbcslot); + sc->inputstate = 0; + sc->buttons = 0; - cmd[0] = PMS_DEV_ENABLE; - res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, - cmd, 1, 0, 1, 0); - if (res) - printf("pms_enable: command error\n"); -#if 0 - { - u_char scmd[2]; - - scmd[0] = PMS_SET_RES; - scmd[1] = 3; /* 8 counts/mm */ - res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd, - 2, 0, 1, 0); - if (res) - printf("pms_enable: setup error1 (%d)\n", res); - - scmd[0] = PMS_SET_SCALE21; - res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd, - 1, 0, 1, 0); - if (res) - printf("pms_enable: setup error2 (%d)\n", res); - - scmd[0] = PMS_SET_SAMPLE; - scmd[1] = 100; /* 100 samples/sec */ - res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd, - 2, 0, 1, 0); - if (res) - printf("pms_enable: setup error3 (%d)\n", res); - } -#endif - sc->sc_state = newstate; + pms_dev_enable(sc); + sc->poll = 0; break; case PMS_STATE_DISABLED: - - /* FALLTHROUGH */ case PMS_STATE_SUSPENDED: - cmd[0] = PMS_DEV_DISABLE; - res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, - cmd, 1, 0, 1, 0); - if (res) - printf("pms_disable: command error\n"); - pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0); - sc->sc_state = newstate; + pms_dev_disable(sc); + sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0; break; } + sc->sc_state = newstate; return 0; } int -pms_enable(v) - void *v; +pms_enable(void *vsc) { - struct pms_softc *sc = v; + struct pms_softc *sc = vsc; return pms_change_state(sc, PMS_STATE_ENABLED); } void -pms_disable(v) - void *v; +pms_disable(void *vsc) { - struct pms_softc *sc = v; + struct pms_softc *sc = vsc; pms_change_state(sc, PMS_STATE_DISABLED); } int -pms_ioctl(v, cmd, data, flag, p) - void *v; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; +pms_ioctl(void *vsc, u_long cmd, caddr_t data, int flag, struct proc *p) { - struct pms_softc *sc = v; - u_char kbcmd[2]; + struct pms_softc *sc = vsc; int i; switch (cmd) { case WSMOUSEIO_GTYPE: *(u_int *)data = WSMOUSE_TYPE_PS2; break; - case WSMOUSEIO_SRES: - i = ((int) *(u_int *)data - 12) / 25; + i = ((int) *(u_int *)data - 12) / 25; /* valid values are {0,1,2,3} */ if (i < 0) i = 0; if (i > 3) i = 3; - - kbcmd[0] = PMS_SET_RES; - kbcmd[1] = (unsigned char) i; - i = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, kbcmd, - 2, 0, 1, 0); - - if (i) - printf("pms_ioctl: SET_RES command error\n"); + + if (pms_set_resolution(sc, i)) { + DPRINTF("%s: ioctl: set resolution error\n", + DEVNAME(sc)); + } break; - default: - return (-1); + return -1; } - return (0); + return 0; } -/* Masks for the first byte of a packet */ -#define PS2LBUTMASK 0x01 -#define PS2RBUTMASK 0x02 -#define PS2MBUTMASK 0x04 +int +pms_sync_generic(struct pms_softc *sc, int data) +{ + if ((sc->inputstate == 0) && + ((data & sc->protocol.syncmask) != sc->protocol.syncval)) { + return -1; + } + return 0; +} -void pmsinput(vsc, data) -void *vsc; -int data; +void +pms_proc_generic(struct pms_softc *sc, int *dx, int *dy, int *dz, u_int *buttons) +{ + static const u_int butmap[8] = { + 0, + PMS_BUTTON1DOWN, + PMS_BUTTON3DOWN, + PMS_BUTTON1DOWN | PMS_BUTTON3DOWN, + PMS_BUTTON2DOWN, + PMS_BUTTON1DOWN | PMS_BUTTON2DOWN, + PMS_BUTTON2DOWN | PMS_BUTTON3DOWN, + PMS_BUTTON1DOWN | PMS_BUTTON2DOWN | PMS_BUTTON3DOWN + }; + + *buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; + *dx = (sc->packet[0] & PMS_PS2_XNEG) ? + sc->packet[1] - 256 : sc->packet[1]; + *dy = (sc->packet[0] & PMS_PS2_YNEG) ? + sc->packet[2] - 256 : sc->packet[2]; + + switch (sc->protocol.type) { + case PMS_STANDARD: + *dz = 0; + break; + case PMS_INTELLI: + *dz = (char)sc->packet[3]; + break; + } +} + +void pmsinput(void *vsc, int data) { struct pms_softc *sc = vsc; - signed char dz = 0; - u_int changed; + u_int changed, newbuttons; + int dx, dy, dz; if (sc->sc_state != PMS_STATE_ENABLED) { /* Interrupts are not expected. Discard the byte. */ return; } - switch (sc->inputstate) { + if (sc->protocol.sync(sc, data)) { + DPRINTF("%s: not in sync yet, discard input\n", DEVNAME(sc)); + sc->inputstate = 0; + return; + } - case 0: - if ((data & 0xc0) == 0) { /* no ovfl, bit 3 == 1 too? */ - sc->buttons = ((data & PS2LBUTMASK) ? 0x1 : 0) | - ((data & PS2MBUTMASK) ? 0x2 : 0) | - ((data & PS2RBUTMASK) ? 0x4 : 0); - ++sc->inputstate; - } - break; + if (sc->inputstate < sc->protocol.packetsize) { + sc->packet[sc->inputstate++] = data & 0xff; + if (sc->inputstate != sc->protocol.packetsize) + return; + } - case 1: - sc->dx = data; - /* Bounding at -127 avoids a bug in XFree86. */ - sc->dx = (sc->dx == -128) ? -127 : sc->dx; - ++sc->inputstate; - break; + sc->protocol.proc(sc, &dx, &dy, &dz, &newbuttons); - case 2: - sc->dy = data; - sc->dy = (sc->dy == -128) ? -127 : sc->dy; - ++sc->inputstate; - break; + changed = (sc->buttons ^ newbuttons); + sc->buttons = newbuttons; + sc->inputstate = 0; - case 3: - dz = data; - dz = (dz == -128) ? -127 : dz; - ++sc->inputstate; - break; - } +#ifdef PMS_DEBUG + int i; - if ((sc->inputstate == 3 && sc->intelli == 0) || sc->inputstate == 4) { - sc->inputstate = 0; + DPRINTFN(3, "%s: packet 0x", DEVNAME(sc)); + for (i = 0; i < sc->protocol.packetsize; i++) + DPRINTFN(3, "%02x", sc->packet[i]); + DPRINTFN(3, "\n"); - changed = (sc->buttons ^ sc->oldbuttons); - sc->oldbuttons = sc->buttons; + DPRINTFN(2, "%s: dx %+03d dy %+03d dz %+03d buttons 0x%02x\n", + DEVNAME(sc), dx, dy, dz, newbuttons); +#endif - if (sc->dx || sc->dy || dz || changed) - wsmouse_input(sc->sc_wsmousedev, - sc->buttons, sc->dx, sc->dy, dz, 0, - WSMOUSE_INPUT_DELTA); + if (dx || dy || dz || changed) { + wsmouse_input(sc->sc_wsmousedev, + newbuttons, dx, dy, dz, 0, WSMOUSE_INPUT_DELTA); } - return; + memset(sc->packet, 0, sc->protocol.packetsize); } - -struct cfdriver pms_cd = { - NULL, "pms", DV_DULL -}; Index: pmsreg.h =================================================================== RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v retrieving revision 1.1 diff -u -p -r1.1 pmsreg.h --- pmsreg.h 1 Aug 2007 12:16:59 -0000 1.1 +++ pmsreg.h 29 Sep 2010 14:41:51 -0000 @@ -2,19 +2,21 @@ /* $NetBSD: psmreg.h,v 1.1 1998/03/22 15:41:28 drochner Exp $ */ /* mouse commands */ -#define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */ -#define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */ -#define PMS_SET_RES 0xe8 /* set resolution (0..3) */ -#define PMS_GET_SCALE 0xe9 /* get scaling factor */ -#define PMS_SEND_DEV_STATUS 0xe9 -#define PMS_SET_STREAM 0xea /* set streaming mode */ -#define PMS_SEND_DEV_DATA 0xeb +#define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */ +#define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */ +#define PMS_SET_RES 0xe8 /* set resolution (0..3) */ +#define PMS_SEND_DEV_STATUS 0xe9 /* status request */ +#define PMS_SET_STREAM_MODE 0xea +#define PMS_SEND_DEV_DATA 0xeb /* read data */ +#define PMS_RESET_WRAP_MODE 0xec +#define PMS_SET_WRAP_MODE 0xed #define PMS_SET_REMOTE_MODE 0xf0 -#define PMS_SEND_DEV_ID 0xf2 -#define PMS_SET_SAMPLE 0xf3 /* set sampling rate */ -#define PMS_DEV_ENABLE 0xf4 /* mouse on */ -#define PMS_DEV_DISABLE 0xf5 /* mouse off */ +#define PMS_SEND_DEV_ID 0xf2 /* read device type */ +#define PMS_SET_SAMPLE 0xf3 /* set sampling rate */ +#define PMS_DEV_ENABLE 0xf4 /* mouse on */ +#define PMS_DEV_DISABLE 0xf5 /* mouse off */ #define PMS_SET_DEFAULTS 0xf6 -#define PMS_RESET 0xff /* reset */ +#define PMS_RESEND 0xfe +#define PMS_RESET 0xff /* reset */ -#define PMS_RSTDONE 0xaa +#define PMS_RSTDONE 0xaa