summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorAlexandr Shadchin <shadchin@cvs.openbsd.org>2010-12-23 20:04:10 +0000
committerAlexandr Shadchin <shadchin@cvs.openbsd.org>2010-12-23 20:04:10 +0000
commitdc9e6cb7b12837ee36fba9caa2c5682760e4a98c (patch)
tree2c7abe922b08e872d217ea5feebd45bd8154ed16 /sys/dev
parent526fca27576e5b1c8f34aad521748e41c88aa1bf (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.c251
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;
}