#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <machine/autoconf.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <dev/hil/hilreg.h>
#include <dev/hil/hilvar.h>
#include <dev/hil/hildevs.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>
struct hilms_softc {
struct hildev_softc sc_hildev;
int sc_features;
u_int sc_buttons;
u_int sc_axes;
int sc_enabled;
int sc_buttonstate;
struct device *sc_wsmousedev;
};
int hilmsprobe(struct device *, void *, void *);
void hilmsattach(struct device *, struct device *, void *);
int hilmsdetach(struct device *, int);
struct cfdriver hilms_cd = {
NULL, "hilms", DV_DULL
};
const struct cfattach hilms_ca = {
sizeof(struct hilms_softc), hilmsprobe, hilmsattach, hilmsdetach,
};
int hilms_enable(void *);
int hilms_ioctl(void *, u_long, caddr_t, int, struct proc *);
void hilms_disable(void *);
const struct wsmouse_accessops hilms_accessops = {
hilms_enable,
hilms_ioctl,
hilms_disable,
};
void hilms_callback(struct hildev_softc *, u_int, u_int8_t *);
int
hilmsprobe(struct device *parent, void *match, void *aux)
{
struct hil_attach_args *ha = aux;
if (ha->ha_type != HIL_DEVICE_MOUSE)
return (0);
if (ha->ha_infolen > 1 && (ha->ha_info[1] & HIL_AXMASK) == 0)
return (0);
return (1);
}
void
hilmsattach(struct device *parent, struct device *self, void *aux)
{
struct hilms_softc *sc = (void *)self;
struct hil_attach_args *ha = aux;
struct wsmousedev_attach_args a;
int iob, rx, ry;
sc->hd_code = ha->ha_code;
sc->hd_type = ha->ha_type;
sc->hd_infolen = ha->ha_infolen;
bcopy(ha->ha_info, sc->hd_info, ha->ha_infolen);
sc->hd_fn = hilms_callback;
rx = ry = 0;
if (ha->ha_infolen > 1) {
sc->sc_features = ha->ha_info[1];
sc->sc_axes = sc->sc_features & HIL_AXMASK;
if (sc->sc_features & HIL_IOB) {
iob = 4;
if (sc->sc_features & HIL_ABSOLUTE) {
rx = ha->ha_info[4] | (ha->ha_info[5] << 8);
if (sc->sc_axes > 1)
ry = ha->ha_info[6] |
(ha->ha_info[7] << 8);
iob += 2 * sc->sc_axes;
}
if (iob >= ha->ha_infolen) {
sc->sc_features &= ~(HIL_IOB | HILIOB_PIO);
} else {
iob = ha->ha_info[iob];
sc->sc_buttons = iob & HILIOB_BMASK;
sc->sc_features |= (iob & HILIOB_PIO);
}
}
}
printf(", %d axes", sc->sc_axes);
if (sc->sc_buttons == 1)
printf(", 1 button");
else if (sc->sc_buttons > 1)
printf(", %d buttons", sc->sc_buttons);
if (sc->sc_features & HILIOB_PIO)
printf(", pressure sensor");
if (sc->sc_features & HIL_ABSOLUTE) {
printf ("\n%s: %d", self->dv_xname, rx);
if (ry != 0)
printf("x%d", ry);
else
printf(" linear");
printf(" fixed area");
}
printf("\n");
sc->sc_enabled = 0;
a.accessops = &hilms_accessops;
a.accesscookie = sc;
sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
}
int
hilmsdetach(struct device *self, int flags)
{
struct hilms_softc *sc = (void *)self;
if (sc->sc_wsmousedev != NULL)
return config_detach(sc->sc_wsmousedev, flags);
return (0);
}
int
hilms_enable(void *v)
{
struct hilms_softc *sc = v;
if (sc->sc_enabled)
return EBUSY;
sc->sc_enabled = 1;
sc->sc_buttonstate = 0;
return (0);
}
void
hilms_disable(void *v)
{
struct hilms_softc *sc = v;
sc->sc_enabled = 0;
}
int
hilms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
#if 0
struct hilms_softc *sc = v;
#endif
switch (cmd) {
case WSMOUSEIO_GTYPE:
*(int *)data = WSMOUSE_TYPE_HIL;
return 0;
}
return -1;
}
void
hilms_callback(struct hildev_softc *dev, u_int buflen, u_int8_t *buf)
{
struct hilms_softc *sc = (struct hilms_softc *)dev;
int type;
int dx, dy, dz, button;
#ifdef DIAGNOSTIC
int minlen;
#endif
if (sc->sc_enabled == 0)
return;
type = *buf++;
#ifdef DIAGNOSTIC
minlen = 1;
if (type & HIL_MOUSEMOTION) {
minlen += sc->sc_axes <<
(sc->sc_features & HIL_16_BITS) ? 1 : 0;
}
if (type & HIL_MOUSEBUTTON)
minlen++;
if (minlen > buflen)
return;
#endif
if (type & HIL_MOUSEMOTION) {
if (sc->sc_features & HIL_16_BITS) {
dx = *buf++;
dx |= (*buf++) << 8;
if (!(sc->sc_features & HIL_ABSOLUTE))
dx = (int16_t)dx;
} else {
dx = *buf++;
if (!(sc->sc_features & HIL_ABSOLUTE))
dx = (int8_t)dx;
}
if (sc->sc_axes > 1) {
if (sc->sc_features & HIL_16_BITS) {
dy = *buf++;
dy |= (*buf++) << 8;
if (!(sc->sc_features & HIL_ABSOLUTE))
dy = (int16_t)dy;
} else {
dy = *buf++;
if (!(sc->sc_features & HIL_ABSOLUTE))
dy = (int8_t)dy;
}
if (sc->sc_axes > 2) {
if (sc->sc_features & HIL_16_BITS) {
dz = *buf++;
dz |= (*buf++) << 8;
if (!(sc->sc_features & HIL_ABSOLUTE))
dz = (int16_t)dz;
} else {
dz = *buf++;
if (!(sc->sc_features & HIL_ABSOLUTE))
dz = (int8_t)dz;
}
} else
dz = 0;
} else
dy = dz = 0;
if ((sc->sc_features & HIL_ABSOLUTE) == 0 &&
sc->sc_buttons == 0)
dy = -dy;
}
if (type & HIL_MOUSEBUTTON) {
button = *buf;
button = (button - 0x80) >> 1;
if (button > 4)
button = 4;
if (*buf & 1) {
sc->sc_buttonstate &= ~(1 << button);
} else {
sc->sc_buttonstate |= (1 << button);
}
}
if (sc->sc_wsmousedev == NULL)
return;
wsmouse_buttons(sc->sc_wsmousedev, sc->sc_buttonstate);
if (type & HIL_MOUSEMOTION) {
if ((sc->sc_features & HIL_ABSOLUTE) == 0) {
wsmouse_motion(sc->sc_wsmousedev, dx, dy, dz, 0);
} else {
wsmouse_position(sc->sc_wsmousedev, dx, dy);
if (sc->sc_axes > 2)
wsmouse_touch(sc->sc_wsmousedev, dz, 0);
}
}
wsmouse_input_sync(sc->sc_wsmousedev);
}