diff options
author | Alexandr Shadchin <shadchin@cvs.openbsd.org> | 2010-12-23 20:04:10 +0000 |
---|---|---|
committer | Alexandr Shadchin <shadchin@cvs.openbsd.org> | 2010-12-23 20:04:10 +0000 |
commit | dc9e6cb7b12837ee36fba9caa2c5682760e4a98c (patch) | |
tree | 2c7abe922b08e872d217ea5feebd45bd8154ed16 /sys/dev | |
parent | 526fca27576e5b1c8f34aad521748e41c88aa1bf (diff) |
Add a common interface for various devices
This is to make it easier to add additional mice types in future
ok krw@, miod@, nicm@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pckbc/pms.c | 251 |
1 files changed, 167 insertions, 84 deletions
diff --git a/sys/dev/pckbc/pms.c b/sys/dev/pckbc/pms.c index 75828839749..e2fac33f4c2 100644 --- a/sys/dev/pckbc/pms.c +++ b/sys/dev/pckbc/pms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pms.c,v 1.14 2010/11/15 20:25:31 krw Exp $ */ +/* $OpenBSD: pms.c,v 1.15 2010/12/23 20:04:09 shadchin Exp $ */ /* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */ /*- @@ -40,6 +40,20 @@ #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) +struct pms_softc; + +struct pms_protocol { + int type; +#define PMS_STANDARD 0 +#define PMS_INTELLI 1 + u_int packetsize; + int (*enable)(struct pms_softc *); + int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *); + int (*sync)(struct pms_softc *, int); + void (*proc)(struct pms_softc *); + void (*disable)(struct pms_softc *); +}; + struct pms_softc { /* driver status information */ struct device sc_dev; @@ -52,14 +66,38 @@ struct pms_softc { /* driver status information */ #define PMS_STATE_SUSPENDED 2 int poll; - int intelli; int inputstate; - u_int buttons, oldbuttons; /* mouse button status */ - signed char dx, dy; + + const struct pms_protocol *protocol; + + u_char packet[8]; struct device *sc_wsmousedev; }; +#define PMS_BUTTON1DOWN 0x0001 /* left */ +#define PMS_BUTTON2DOWN 0x0002 /* middle */ +#define PMS_BUTTON3DOWN 0x0004 /* right */ + +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 +}; + +/* 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 + int pmsprobe(struct device *, void *, void *); void pmsattach(struct device *, struct device *, void *); int pmsactivate(struct device *, int); @@ -81,7 +119,11 @@ int pms_reset(struct pms_softc *); int pms_dev_enable(struct pms_softc *); int pms_dev_disable(struct pms_softc *); -int pms_setintellimode(struct pms_softc *sc); +int pms_enable_intelli(struct pms_softc *); + +int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *); +int pms_sync_mouse(struct pms_softc *, int); +void pms_proc_mouse(struct pms_softc *); struct cfattach pms_ca = { sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, @@ -98,6 +140,27 @@ const struct wsmouse_accessops pms_accessops = { pms_disable, }; +const struct pms_protocol pms_mouse[] = { + /* Generic PS/2 mouse */ + { + PMS_STANDARD, 3, + NULL, + pms_ioctl_mouse, + pms_sync_mouse, + pms_proc_mouse, + NULL + }, + /* Microsoft IntelliMouse */ + { + PMS_INTELLI, 4, + pms_enable_intelli, + pms_ioctl_mouse, + pms_sync_mouse, + pms_proc_mouse, + NULL + } +}; + int pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen) { @@ -208,7 +271,7 @@ pms_dev_disable(struct pms_softc *sc) } int -pms_setintellimode(struct pms_softc *sc) +pms_enable_intelli(struct pms_softc *sc) { static const int rates[] = {200, 100, 80}; u_char resp; @@ -224,6 +287,78 @@ pms_setintellimode(struct pms_softc *sc) } int +pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, + struct proc *p) +{ + int i; + + switch (cmd) { + case WSMOUSEIO_GTYPE: + *(u_int *)data = WSMOUSE_TYPE_PS2; + break; + case WSMOUSEIO_SRES: + i = ((int) *(u_int *)data - 12) / 25; + /* valid values are {0,1,2,3} */ + if (i < 0) + i = 0; + if (i > 3) + i = 3; + + if (pms_set_resolution(sc, i)) + printf("%s: SET_RES command error\n", DEVNAME(sc)); + break; + default: + return (-1); + } + return (0); +} + +int +pms_sync_mouse(struct pms_softc *sc, int data) +{ + if (sc->inputstate != 0) + return (0); + + switch (sc->protocol->type) { + case PMS_STANDARD: + if ((data & 0xc0) != 0) + return (-1); + break; + case PMS_INTELLI: + if ((data & 0x08) != 0x08) + return (-1); + break; + } + + return (0); +} + +void +pms_proc_mouse(struct pms_softc *sc) +{ + u_int buttons; + int dx, dy, dz; + + buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; + dx = (sc->packet[0] & PMS_PS2_XNEG) ? + (int)sc->packet[1] - 256 : sc->packet[1]; + dy = (sc->packet[0] & PMS_PS2_YNEG) ? + (int)sc->packet[2] - 256 : sc->packet[2]; + + switch (sc->protocol->type) { + case PMS_STANDARD: + dz = 0; + break; + case PMS_INTELLI: + dz = (signed char)sc->packet[3]; + break; + } + + wsmouse_input(sc->sc_wsmousedev, + buttons, dx, dy, dz, 0, WSMOUSE_INPUT_DELTA); +} + +int pmsprobe(struct device *parent, void *match, void *aux) { struct pckbc_attach_args *pa = aux; @@ -302,13 +437,14 @@ pmsactivate(struct device *self, int act) int pms_change_state(struct pms_softc *sc, int newstate) { + int i; + 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); @@ -317,13 +453,24 @@ pms_change_state(struct pms_softc *sc, int newstate) pms_reset(sc); - sc->intelli = pms_setintellimode(sc); + sc->protocol = &pms_mouse[0]; + for (i = 1; i < nitems(pms_mouse); i++) + if (pms_mouse[i].enable(sc)) + sc->protocol = &pms_mouse[i]; + +#ifdef DEBUG + printf("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type); +#endif pms_dev_enable(sc); break; case PMS_STATE_DISABLED: case PMS_STATE_SUSPENDED: pms_dev_disable(sc); + + if (sc->protocol && sc->protocol->disable) + sc->protocol->disable(sc); + pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0); break; } @@ -354,96 +501,32 @@ int pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { struct pms_softc *sc = v; - u_char kbcmd[2]; - int i; - switch (cmd) { - case WSMOUSEIO_GTYPE: - *(u_int *)data = WSMOUSE_TYPE_PS2; - break; - - case WSMOUSEIO_SRES: - 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"); - break; - - default: - return (-1); - } - return (0); + return (sc->protocol->ioctl(sc, cmd, data, flag, p)); } -/* Masks for the first byte of a packet */ -#define PS2LBUTMASK 0x01 -#define PS2RBUTMASK 0x02 -#define PS2MBUTMASK 0x04 - void pmsinput(void *vsc, int data) { struct pms_softc *sc = vsc; - signed char dz = 0; - u_int changed; if (sc->sc_state != PMS_STATE_ENABLED) { /* Interrupts are not expected. Discard the byte. */ return; } - switch (sc->inputstate) { - - 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; - - case 1: - sc->dx = data; - /* Bounding at -127 avoids a bug in XFree86. */ - sc->dx = (sc->dx == -128) ? -127 : sc->dx; - ++sc->inputstate; - break; - - case 2: - sc->dy = data; - sc->dy = (sc->dy == -128) ? -127 : sc->dy; - ++sc->inputstate; - break; - - case 3: - dz = data; - dz = (dz == -128) ? -127 : dz; - ++sc->inputstate; - break; - } - - if ((sc->inputstate == 3 && sc->intelli == 0) || sc->inputstate == 4) { + if (sc->protocol->sync(sc, data)) { +#ifdef DEBUG + printf("%s: not in sync yet, discard input\n", DEVNAME(sc)); +#endif sc->inputstate = 0; - - changed = (sc->buttons ^ sc->oldbuttons); - sc->oldbuttons = sc->buttons; - - if (sc->dx || sc->dy || dz || changed) - wsmouse_input(sc->sc_wsmousedev, - sc->buttons, sc->dx, sc->dy, dz, 0, - WSMOUSE_INPUT_DELTA); + return; } - return; + sc->packet[sc->inputstate++] = data; + if (sc->inputstate != sc->protocol->packetsize) + return; + + sc->protocol->proc(sc); + sc->inputstate = 0; } |