#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mms.c,v 1.19 2021/08/07 16:18:48 thorpej Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include "wsmouse.h"
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>
#include <dreamcast/dev/maple/maple.h>
#include <dreamcast/dev/maple/mapleconf.h>
struct mms_condition {
uint32_t func_code;
uint32_t buttons;
uint16_t axis1;
uint16_t axis2;
uint16_t axis3;
uint16_t axis4;
uint16_t axis5;
uint16_t axis6;
uint16_t axis7;
uint16_t axis8;
};
#define MMS_BUTTON_C 0x01
#define MMS_BUTTON_B 0x02
#define MMS_BUTTON_A 0x04
#define MMS_BUTTON_START 0x08
#define MMS_BUTTON_MASK 0x0f
#define MMS_MOVEMENT_BASE 0x200
#define MMS_MOVEMENT_MAX 0x3ff
#define MMS_FUNCDATA_AXIS1 0x001
#define MMS_FUNCDATA_AXIS2 0x002
#define MMS_FUNCDATA_AXIS3 0x004
#define MMS_FUNCDATA_AXIS4 0x008
#define MMS_FUNCDATA_AXIS5 0x010
#define MMS_FUNCDATA_AXIS6 0x020
#define MMS_FUNCDATA_AXIS7 0x040
#define MMS_FUNCDATA_AXIS8 0x080
#define MMS_FUNCDATA_C 0x100
#define MMS_FUNCDATA_B 0x200
#define MMS_FUNCDATA_A 0x400
#define MMS_FUNCDATA_START 0x800
struct mms_softc {
device_t sc_dev;
device_t sc_parent;
struct maple_unit *sc_unit;
uint32_t sc_oldbuttons;
device_t sc_wsmousedev;
};
static int mms_match(device_t, cfdata_t, void *);
static void mms_attach(device_t, device_t, void *);
static int mms_detach(device_t, int);
CFATTACH_DECL_NEW(mms, sizeof(struct mms_softc),
mms_match, mms_attach, mms_detach, NULL);
static int mms_enable(void *);
static int mms_ioctl(void *, u_long, void *, int, struct lwp *);
static void mms_disable(void *);
const struct wsmouse_accessops mms_accessops = {
mms_enable,
mms_ioctl,
mms_disable,
};
static void mms_intr(void *, struct maple_response *, int, int);
static int
mms_match(device_t parent, cfdata_t cf, void *aux)
{
struct maple_attach_args *ma = aux;
return ma->ma_function == MAPLE_FN_MOUSE ? MAPLE_MATCH_FUNC : 0;
}
static void
mms_attach(device_t parent, device_t self, void *aux)
{
struct mms_softc *sc = device_private(self);
struct maple_attach_args *ma = aux;
struct wsmousedev_attach_args a;
uint32_t data;
printf(": SEGA Dreamcast Mouse\n");
sc->sc_dev = self;
sc->sc_parent = parent;
sc->sc_unit = ma->ma_unit;
data = maple_get_function_data(ma->ma_devinfo,
MAPLE_FN_MOUSE);
printf("%s: buttons:", device_xname(self));
if (data & MMS_FUNCDATA_A)
printf(" left");
if (data & MMS_FUNCDATA_C)
printf(" middle");
if (data & MMS_FUNCDATA_B)
printf(" right");
if (data & MMS_FUNCDATA_START)
printf(" thumb");
printf("\n");
sc->sc_oldbuttons = 0;
a.accessops = &mms_accessops;
a.accesscookie = sc;
sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE);
if (sc->sc_wsmousedev == NULL) {
return;
}
maple_set_callback(parent, sc->sc_unit, MAPLE_FN_MOUSE, mms_intr, sc);
}
static int
mms_detach(device_t self, int flags)
{
struct mms_softc *sc = device_private(self);
int rv = 0;
if (sc->sc_wsmousedev != NULL)
rv = config_detach(sc->sc_wsmousedev, flags);
return rv;
}
static int
mms_enable(void *v)
{
struct mms_softc *sc = v;
maple_enable_periodic(sc->sc_parent, sc->sc_unit, MAPLE_FN_MOUSE, 1);
return 0;
}
static void
mms_disable(void *v)
{
struct mms_softc *sc = v;
maple_enable_periodic(sc->sc_parent, sc->sc_unit, MAPLE_FN_MOUSE, 0);
}
static int
mms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
{
switch (cmd) {
case WSMOUSEIO_GTYPE:
*(u_int *) data = WSMOUSE_TYPE_MAPLE;
break;
case WSMOUSEIO_SRES:
return EOPNOTSUPP;
default:
return EPASSTHROUGH;
}
return 0;
}
static void
mms_intr(void *arg, struct maple_response *response, int size, int flags)
{
struct mms_softc *sc = arg;
struct mms_condition *data = (void *) response->data;
int dx = 0, dy = 0, dz = 0, buttons = 0;
uint32_t buttonchg;
if ((flags & MAPLE_FLAG_PERIODIC) == 0 ||
size < sizeof(*data))
return;
data->buttons &= MMS_BUTTON_MASK;
buttonchg = sc->sc_oldbuttons ^ data->buttons;
sc->sc_oldbuttons = data->buttons;
dx = (data->axis1 & MMS_MOVEMENT_MAX) - MMS_MOVEMENT_BASE;
dy = (data->axis2 & MMS_MOVEMENT_MAX) - MMS_MOVEMENT_BASE;
dz = (data->axis3 & MMS_MOVEMENT_MAX) - MMS_MOVEMENT_BASE;
if (dx || dy || dz || buttonchg) {
if ((data->buttons & MMS_BUTTON_A) == 0)
buttons |= 0x01;
if ((data->buttons & MMS_BUTTON_C) == 0)
buttons |= 0x02;
if ((data->buttons & MMS_BUTTON_B) == 0)
buttons |= 0x04;
if ((data->buttons & MMS_BUTTON_START) == 0)
buttons |= 0x08;
wsmouse_input(sc->sc_wsmousedev,
buttons,
dx, -dy, dz, 0,
WSMOUSE_INPUT_DELTA);
}
}