svn commit: r321060 - stable/11/sys/dev/atkbdc

Vladimir Kondratyev wulf at FreeBSD.org
Sun Jul 16 21:03:27 UTC 2017


Author: wulf
Date: Sun Jul 16 21:03:26 2017
New Revision: 321060
URL: https://svnweb.freebsd.org/changeset/base/321060

Log:
  MFC r319162:
  psm: add support for evdev protocol
  
  Approved by:	gonzo (mentor)

Modified:
  stable/11/sys/dev/atkbdc/psm.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/atkbdc/psm.c
==============================================================================
--- stable/11/sys/dev/atkbdc/psm.c	Sun Jul 16 20:56:41 2017	(r321059)
+++ stable/11/sys/dev/atkbdc/psm.c	Sun Jul 16 21:03:26 2017	(r321060)
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_isa.h"
 #include "opt_psm.h"
+#include "opt_evdev.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -90,6 +91,11 @@ __FBSDID("$FreeBSD$");
 #include <isa/isavar.h>
 #endif
 
+#ifdef EVDEV_SUPPORT
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/input.h>
+#endif
+
 #include <dev/atkbdc/atkbdcreg.h>
 #include <dev/atkbdc/psm.h>
 
@@ -325,8 +331,14 @@ typedef struct elantechhw {
 #define	ELANTECH_REG_RDWR	0x00
 #define	ELANTECH_CUSTOM_CMD	0xf8
 
+#ifdef EVDEV_SUPPORT
+#define	ELANTECH_MAX_FINGERS	5
+#else
 #define	ELANTECH_MAX_FINGERS	PSM_FINGERS
+#endif
 
+#define	ELANTECH_FINGER_MAX_P	255
+#define	ELANTECH_FINGER_MAX_W	15
 #define	ELANTECH_FINGER_SET_XYP(pb) (finger_t) {			\
     .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2],		\
     .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5],		\
@@ -418,6 +430,10 @@ struct psm_softc {		/* Driver status information */
 	int		cmdcount;
 	struct sigio	*async;		/* Processes waiting for SIGIO */
 	int		extended_buttons;
+#ifdef EVDEV_SUPPORT
+	struct evdev_dev *evdev_a;	/* Absolute reporting device */
+	struct evdev_dev *evdev_r;	/* Relative reporting device */
+#endif
 };
 static devclass_t psm_devclass;
 
@@ -427,6 +443,8 @@ static devclass_t psm_devclass;
 #define	PSM_ASLP		2	/* Waiting for mouse data */
 #define	PSM_SOFTARMED		4	/* Software interrupt armed */
 #define	PSM_NEED_SYNCBITS	8	/* Set syncbits using next data pkt */
+#define	PSM_EV_OPEN_R		0x10	/* Relative evdev device is open */
+#define	PSM_EV_OPEN_A		0x20	/* Absolute evdev device is open */
 
 /* driver configuration flags (config) */
 #define	PSM_CONFIG_RESOLUTION	0x000f	/* resolution */
@@ -532,13 +550,23 @@ static int	psmattach(device_t);
 static int	psmdetach(device_t);
 static int	psmresume(device_t);
 
-static d_open_t		psmopen;
-static d_close_t	psmclose;
+static d_open_t		psm_cdev_open;
+static d_close_t	psm_cdev_close;
 static d_read_t		psmread;
 static d_write_t	psmwrite;
 static d_ioctl_t	psmioctl;
 static d_poll_t		psmpoll;
 
+static int	psmopen(struct psm_softc *);
+static int	psmclose(struct psm_softc *);
+
+#ifdef EVDEV_SUPPORT
+static evdev_open_t	psm_ev_open_r;
+static evdev_close_t	psm_ev_close_r;
+static evdev_open_t	psm_ev_open_a;
+static evdev_close_t	psm_ev_close_a;
+#endif
+
 static int	enable_aux_dev(KBDC);
 static int	disable_aux_dev(KBDC);
 static int	get_mouse_status(KBDC, int *, int, int);
@@ -668,8 +696,8 @@ static driver_t psm_driver = {
 static struct cdevsw psm_cdevsw = {
 	.d_version =	D_VERSION,
 	.d_flags =	D_NEEDGIANT,
-	.d_open =	psmopen,
-	.d_close =	psmclose,
+	.d_open =	psm_cdev_open,
+	.d_close =	psm_cdev_close,
 	.d_read =	psmread,
 	.d_write =	psmwrite,
 	.d_ioctl =	psmioctl,
@@ -677,6 +705,17 @@ static struct cdevsw psm_cdevsw = {
 	.d_name =	PSM_DRIVER_NAME,
 };
 
+#ifdef EVDEV_SUPPORT
+static const struct evdev_methods psm_ev_methods_r = {
+	.ev_open = psm_ev_open_r,
+	.ev_close = psm_ev_close_r,
+};
+static const struct evdev_methods psm_ev_methods_a = {
+	.ev_open = psm_ev_open_a,
+	.ev_close = psm_ev_close_a,
+};
+#endif
+
 /* device I/O routines */
 static int
 enable_aux_dev(KBDC kbdc)
@@ -1197,7 +1236,8 @@ reinitialize(struct psm_softc *sc, int doinit)
 	splx(s);
 
 	/* restore the driver state */
-	if ((sc->state & PSM_OPEN) && (err == 0)) {
+	if ((sc->state & (PSM_OPEN | PSM_EV_OPEN_R | PSM_EV_OPEN_A)) &&
+	    (err == 0)) {
 		/* enable the aux device and the port again */
 		err = doopen(sc, c);
 		if (err != 0)
@@ -1578,7 +1618,271 @@ psmprobe(device_t dev)
 	return (0);
 }
 
+#ifdef EVDEV_SUPPORT
+/* Values are taken from Linux drivers for userland software compatibility */
+#define	PS2_MOUSE_VENDOR		0x0002
+#define	PS2_MOUSE_GENERIC_PRODUCT	0x0001
+#define	PS2_MOUSE_SYNAPTICS_NAME	"SynPS/2 Synaptics TouchPad"
+#define	PS2_MOUSE_SYNAPTICS_PRODUCT	0x0007
+#define	PS2_MOUSE_TRACKPOINT_NAME	"TPPS/2 IBM TrackPoint"
+#define	PS2_MOUSE_TRACKPOINT_PRODUCT	0x000A
+#define	PS2_MOUSE_ELANTECH_NAME		"ETPS/2 Elantech Touchpad"
+#define	PS2_MOUSE_ELANTECH_ST_NAME	"ETPS/2 Elantech TrackPoint"
+#define	PS2_MOUSE_ELANTECH_PRODUCT	0x000E
+
+#define	ABSINFO_END	{ ABS_CNT, 0, 0, 0 }
+
+static void
+psm_support_abs_bulk(struct evdev_dev *evdev, const uint16_t info[][4])
+{
+	size_t i;
+
+	for (i = 0; info[i][0] != ABS_CNT; i++)
+		evdev_support_abs(evdev, info[i][0], 0, info[i][1], info[i][2],
+		    0, 0, info[i][3]);
+}
+
+static void
+psm_push_mt_finger(struct psm_softc *sc, int id, const finger_t *f)
+{
+	int y = sc->synhw.minimumYCoord + sc->synhw.maximumYCoord - f->y;
+
+	evdev_push_abs(sc->evdev_a, ABS_MT_SLOT, id);
+	evdev_push_abs(sc->evdev_a, ABS_MT_TRACKING_ID, id);
+	evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_X, f->x);
+	evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_Y, y);
+	evdev_push_abs(sc->evdev_a, ABS_MT_PRESSURE, f->p);
+}
+
+static void
+psm_push_st_finger(struct psm_softc *sc, const finger_t *f)
+{
+	int y = sc->synhw.minimumYCoord + sc->synhw.maximumYCoord - f->y;
+
+	evdev_push_abs(sc->evdev_a, ABS_X, f->x);
+	evdev_push_abs(sc->evdev_a, ABS_Y, y);
+	evdev_push_abs(sc->evdev_a, ABS_PRESSURE, f->p);
+	if (sc->synhw.capPalmDetect)
+		evdev_push_abs(sc->evdev_a, ABS_TOOL_WIDTH, f->w);
+}
+
+static void
+psm_release_mt_slot(struct evdev_dev *evdev, int32_t slot)
+{
+
+	evdev_push_abs(evdev, ABS_MT_SLOT, slot);
+	evdev_push_abs(evdev, ABS_MT_TRACKING_ID, -1);
+}
+
 static int
+psm_register(device_t dev, int model_code)
+{
+	struct psm_softc *sc = device_get_softc(dev);
+	struct evdev_dev *evdev_r;
+	int error, i, nbuttons, nwheels, product;
+	bool is_pointing_stick;
+	const char *name;
+
+	name = model_name(model_code);
+	nbuttons = sc->hw.buttons;
+	product = PS2_MOUSE_GENERIC_PRODUCT;
+	nwheels = 0;
+	is_pointing_stick = false;
+
+	switch (model_code) {
+	case MOUSE_MODEL_TRACKPOINT:
+		name = PS2_MOUSE_TRACKPOINT_NAME;
+		product = PS2_MOUSE_TRACKPOINT_PRODUCT;
+		nbuttons = 3;
+		is_pointing_stick = true;
+		break;
+
+	case MOUSE_MODEL_ELANTECH:
+		name = PS2_MOUSE_ELANTECH_ST_NAME;
+		product = PS2_MOUSE_ELANTECH_PRODUCT;
+		nbuttons = 3;
+		is_pointing_stick = true;
+		break;
+
+	case MOUSE_MODEL_MOUSEMANPLUS:
+	case MOUSE_MODEL_4D:
+		nwheels = 2;
+		break;
+
+	case MOUSE_MODEL_EXPLORER:
+	case MOUSE_MODEL_INTELLI:
+	case MOUSE_MODEL_NET:
+	case MOUSE_MODEL_NETSCROLL:
+	case MOUSE_MODEL_4DPLUS:
+		nwheels = 1;
+		break;
+	}
+
+	evdev_r = evdev_alloc();
+	evdev_set_name(evdev_r, name);
+	evdev_set_phys(evdev_r, device_get_nameunit(dev));
+	evdev_set_id(evdev_r, BUS_I8042, PS2_MOUSE_VENDOR, product, 0);
+	evdev_set_methods(evdev_r, sc, &psm_ev_methods_r);
+
+	evdev_support_prop(evdev_r, INPUT_PROP_POINTER);
+	if (is_pointing_stick)
+		evdev_support_prop(evdev_r, INPUT_PROP_POINTING_STICK);
+	evdev_support_event(evdev_r, EV_SYN);
+	evdev_support_event(evdev_r, EV_KEY);
+	evdev_support_event(evdev_r, EV_REL);
+	evdev_support_rel(evdev_r, REL_X);
+	evdev_support_rel(evdev_r, REL_Y);
+	switch (nwheels) {
+	case 2:
+		evdev_support_rel(evdev_r, REL_HWHEEL);
+		/* FALLTHROUGH */
+	case 1:
+		evdev_support_rel(evdev_r, REL_WHEEL);
+	}
+	for (i = 0; i < nbuttons; i++)
+		evdev_support_key(evdev_r, BTN_MOUSE + i);
+
+	error = evdev_register_mtx(evdev_r, &Giant);
+	if (error)
+		evdev_free(evdev_r);
+	else
+		sc->evdev_r = evdev_r;
+	return (error);
+}
+
+static int
+psm_register_synaptics(device_t dev)
+{
+	struct psm_softc *sc = device_get_softc(dev);
+	const uint16_t synaptics_absinfo_st[][4] = {
+		{ ABS_X,		sc->synhw.minimumXCoord,
+		    sc->synhw.maximumXCoord, sc->synhw.infoXupmm },
+		{ ABS_Y,		sc->synhw.minimumYCoord,
+		    sc->synhw.maximumYCoord, sc->synhw.infoYupmm },
+		{ ABS_PRESSURE,		0, ELANTECH_FINGER_MAX_P, 0 },
+		ABSINFO_END,
+	};
+	const uint16_t synaptics_absinfo_mt[][4] = {
+		{ ABS_MT_SLOT,		0, PSM_FINGERS-1, 0},
+		{ ABS_MT_TRACKING_ID,	-1, PSM_FINGERS-1, 0},
+		{ ABS_MT_POSITION_X,	sc->synhw.minimumXCoord,
+		    sc->synhw.maximumXCoord, sc->synhw.infoXupmm },
+		{ ABS_MT_POSITION_Y,	sc->synhw.minimumYCoord,
+		    sc->synhw.maximumYCoord, sc->synhw.infoYupmm },
+		{ ABS_MT_PRESSURE,	0, ELANTECH_FINGER_MAX_P, 0 },
+		ABSINFO_END,
+	};
+	struct evdev_dev *evdev_a;
+	int error, i, guest_model;
+
+	evdev_a = evdev_alloc();
+	evdev_set_name(evdev_a, PS2_MOUSE_SYNAPTICS_NAME);
+	evdev_set_phys(evdev_a, device_get_nameunit(dev));
+	evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR,
+	    PS2_MOUSE_SYNAPTICS_PRODUCT, 0);
+	evdev_set_methods(evdev_a, sc, &psm_ev_methods_a);
+
+	evdev_support_event(evdev_a, EV_SYN);
+	evdev_support_event(evdev_a, EV_KEY);
+	evdev_support_event(evdev_a, EV_ABS);
+	evdev_support_prop(evdev_a, INPUT_PROP_POINTER);
+	if (sc->synhw.capAdvancedGestures)
+		evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT);
+	if (sc->synhw.capClickPad)
+		evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD);
+	evdev_support_key(evdev_a, BTN_TOUCH);
+	evdev_support_nfingers(evdev_a, 3);
+	psm_support_abs_bulk(evdev_a, synaptics_absinfo_st);
+	if (sc->synhw.capAdvancedGestures || sc->synhw.capReportsV)
+		psm_support_abs_bulk(evdev_a, synaptics_absinfo_mt);
+	if (sc->synhw.capPalmDetect)
+		evdev_support_abs(evdev_a, ABS_TOOL_WIDTH, 0, 0, 15, 0, 0, 0);
+	evdev_support_key(evdev_a, BTN_LEFT);
+	if (!sc->synhw.capClickPad) {
+		evdev_support_key(evdev_a, BTN_RIGHT);
+		if (sc->synhw.capExtended && sc->synhw.capMiddle)
+			evdev_support_key(evdev_a, BTN_MIDDLE);
+	}
+	if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
+		evdev_support_key(evdev_a, BTN_BACK);
+		evdev_support_key(evdev_a, BTN_FORWARD);
+	}
+	if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0))
+		for (i = 0; i < sc->synhw.nExtendedButtons; i++)
+			evdev_support_key(evdev_a, BTN_0 + i);
+
+	error = evdev_register_mtx(evdev_a, &Giant);
+	if (!error && sc->synhw.capPassthrough) {
+		guest_model = sc->tpinfo.sysctl_tree != NULL ?
+		    MOUSE_MODEL_TRACKPOINT : MOUSE_MODEL_GENERIC;
+		error = psm_register(dev, guest_model);
+	}
+	if (error)
+		evdev_free(evdev_a);
+	else
+		sc->evdev_a = evdev_a;
+	return (error);
+}
+
+static int
+psm_register_elantech(device_t dev)
+{
+	struct psm_softc *sc = device_get_softc(dev);
+	const uint16_t elantech_absinfo[][4] = {
+		{ ABS_X,		0, sc->elanhw.sizex,
+					   sc->elanhw.dpmmx },
+		{ ABS_Y,		0, sc->elanhw.sizey,
+					   sc->elanhw.dpmmy },
+		{ ABS_PRESSURE,		0, ELANTECH_FINGER_MAX_P, 0 },
+		{ ABS_TOOL_WIDTH,	0, ELANTECH_FINGER_MAX_W, 0 },
+		{ ABS_MT_SLOT,		0, ELANTECH_MAX_FINGERS - 1, 0 },
+		{ ABS_MT_TRACKING_ID,	-1, ELANTECH_MAX_FINGERS - 1, 0 },
+		{ ABS_MT_POSITION_X,	0, sc->elanhw.sizex,
+					   sc->elanhw.dpmmx },
+		{ ABS_MT_POSITION_Y,	0, sc->elanhw.sizey,
+					   sc->elanhw.dpmmy },
+		{ ABS_MT_PRESSURE,	0, ELANTECH_FINGER_MAX_P, 0 },
+		{ ABS_MT_TOUCH_MAJOR,	0, ELANTECH_FINGER_MAX_W *
+					   sc->elanhw.dptracex, 0 },
+		ABSINFO_END,
+	};
+	struct evdev_dev *evdev_a;
+	int error;
+
+	evdev_a = evdev_alloc();
+	evdev_set_name(evdev_a, PS2_MOUSE_ELANTECH_NAME);
+	evdev_set_phys(evdev_a, device_get_nameunit(dev));
+	evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR,
+	    PS2_MOUSE_ELANTECH_PRODUCT, 0);
+	evdev_set_methods(evdev_a, sc, &psm_ev_methods_a);
+
+	evdev_support_event(evdev_a, EV_SYN);
+	evdev_support_event(evdev_a, EV_KEY);
+	evdev_support_event(evdev_a, EV_ABS);
+	evdev_support_prop(evdev_a, INPUT_PROP_POINTER);
+	if (sc->elanhw.issemimt)
+		evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT);
+	if (sc->elanhw.isclickpad)
+		evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD);
+	evdev_support_key(evdev_a, BTN_TOUCH);
+	evdev_support_nfingers(evdev_a, ELANTECH_MAX_FINGERS);
+	evdev_support_key(evdev_a, BTN_LEFT);
+	if (!sc->elanhw.isclickpad)
+		evdev_support_key(evdev_a, BTN_RIGHT);
+	psm_support_abs_bulk(evdev_a, elantech_absinfo);
+
+	error = evdev_register_mtx(evdev_a, &Giant);
+	if (!error && sc->elanhw.hastrackpoint)
+		error = psm_register(dev, MOUSE_MODEL_ELANTECH);
+	if (error)
+		evdev_free(evdev_a);
+	else
+		sc->evdev_a = evdev_a;
+	return (error);
+}
+#endif
+
+static int
 psmattach(device_t dev)
 {
 	int unit = device_get_unit(dev);
@@ -1609,6 +1913,24 @@ psmattach(device_t dev)
 	sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit);
 	sc->bdev->si_drv1 = sc;
 
+#ifdef EVDEV_SUPPORT
+	switch (sc->hw.model) {
+	case MOUSE_MODEL_SYNAPTICS:
+		error = psm_register_synaptics(dev);
+		break;
+
+	case MOUSE_MODEL_ELANTECH:
+		error = psm_register_elantech(dev);
+		break;
+
+	default:
+		error = psm_register(dev, sc->hw.model);
+	}
+
+	if (error)
+		return (error);
+#endif
+
 	/* Some touchpad devices need full reinitialization after suspend. */
 	switch (sc->hw.model) {
 	case MOUSE_MODEL_SYNAPTICS:
@@ -1657,6 +1979,11 @@ psmdetach(device_t dev)
 	if (sc->state & PSM_OPEN)
 		return (EBUSY);
 
+#ifdef EVDEV_SUPPORT
+	evdev_free(sc->evdev_r);
+	evdev_free(sc->evdev_a);
+#endif
+
 	rid = KBDC_RID_AUX;
 	bus_teardown_intr(dev, sc->intr, sc->ih);
 	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
@@ -1670,13 +1997,83 @@ psmdetach(device_t dev)
 	return (0);
 }
 
+#ifdef EVDEV_SUPPORT
 static int
-psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
+psm_ev_open_r(struct evdev_dev *evdev, void *ev_softc)
 {
+	struct psm_softc *sc = (struct psm_softc *)ev_softc;
+	int err = 0;
+
+	/* Get device data */
+	if ((sc->state & PSM_VALID) == 0) {
+		/* the device is no longer valid/functioning */
+		return (ENXIO);
+	}
+
+	if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_A)))
+		err = psmopen(sc);
+
+	if (err == 0)
+		sc->state |= PSM_EV_OPEN_R;
+
+	return (err);
+}
+
+static void
+psm_ev_close_r(struct evdev_dev *evdev, void *ev_softc)
+{
+	struct psm_softc *sc = (struct psm_softc *)ev_softc;
+
+	sc->state &= ~PSM_EV_OPEN_R;
+
+	if (sc->state & (PSM_OPEN | PSM_EV_OPEN_A))
+		return;
+
+	if (sc->state & PSM_VALID)
+		psmclose(sc);
+}
+
+static int
+psm_ev_open_a(struct evdev_dev *evdev, void *ev_softc)
+{
+	struct psm_softc *sc = (struct psm_softc *)ev_softc;
+	int err = 0;
+
+	/* Get device data */
+	if ((sc->state & PSM_VALID) == 0) {
+		/* the device is no longer valid/functioning */
+		return (ENXIO);
+	}
+
+	if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_R)))
+		err = psmopen(sc);
+
+	if (err == 0)
+		sc->state |= PSM_EV_OPEN_A;
+
+	return (err);
+}
+
+static void
+psm_ev_close_a(struct evdev_dev *evdev, void *ev_softc)
+{
+	struct psm_softc *sc = (struct psm_softc *)ev_softc;
+
+	sc->state &= ~PSM_EV_OPEN_A;
+
+	if (sc->state & (PSM_OPEN | PSM_EV_OPEN_R))
+		return;
+
+	if (sc->state & PSM_VALID)
+		psmclose(sc);
+}
+#endif
+
+static int
+psm_cdev_open(struct cdev *dev, int flag, int fmt, struct thread *td)
+{
 	struct psm_softc *sc;
-	int command_byte;
-	int err;
-	int s;
+	int err = 0;
 
 	/* Get device data */
 	sc = dev->si_drv1;
@@ -1691,6 +2088,59 @@ psmopen(struct cdev *dev, int flag, int fmt, struct th
 
 	device_busy(devclass_get_device(psm_devclass, sc->unit));
 
+#ifdef EVDEV_SUPPORT
+	/* Already opened by evdev */
+	if (!(sc->state & (PSM_EV_OPEN_R | PSM_EV_OPEN_A)))
+#endif
+		err = psmopen(sc);
+
+	if (err == 0)
+		sc->state |= PSM_OPEN;
+	else
+		device_unbusy(devclass_get_device(psm_devclass, sc->unit));
+
+	return (err);
+}
+
+static int
+psm_cdev_close(struct cdev *dev, int flag, int fmt, struct thread *td)
+{
+	struct psm_softc *sc;
+	int err = 0;
+
+	/* Get device data */
+	sc = dev->si_drv1;
+	if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
+		/* the device is no longer valid/functioning */
+		return (ENXIO);
+	}
+
+#ifdef EVDEV_SUPPORT
+	/* Still opened by evdev */
+	if (!(sc->state & (PSM_EV_OPEN_R | PSM_EV_OPEN_A)))
+#endif
+		err = psmclose(sc);
+
+	if (err == 0) {
+		sc->state &= ~PSM_OPEN;
+		/* clean up and sigio requests */
+		if (sc->async != NULL) {
+			funsetown(&sc->async);
+			sc->async = NULL;
+		}
+		device_unbusy(devclass_get_device(psm_devclass, sc->unit));
+	}
+
+	return (err);
+}
+
+static int
+psmopen(struct psm_softc *sc)
+{
+	int command_byte;
+	int err;
+	int s;
+
 	/* Initialize state */
 	sc->mode.level = sc->dflt_mode.level;
 	sc->mode.protocol = sc->dflt_mode.protocol;
@@ -1750,16 +2200,13 @@ psmopen(struct cdev *dev, int flag, int fmt, struct th
 	err = doopen(sc, command_byte);
 
 	/* done */
-	if (err == 0)
-		sc->state |= PSM_OPEN;
 	kbdc_lock(sc->kbdc, FALSE);
 	return (err);
 }
 
 static int
-psmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
+psmclose(struct psm_softc *sc)
 {
-	struct psm_softc *sc = dev->si_drv1;
 	int stat[3];
 	int command_byte;
 	int s;
@@ -1836,16 +2283,8 @@ psmclose(struct cdev *dev, int flag, int fmt, struct t
 	/* remove anything left in the output buffer */
 	empty_aux_buffer(sc->kbdc, 10);
 
-	/* clean up and sigio requests */
-	if (sc->async != NULL) {
-		funsetown(&sc->async);
-		sc->async = NULL;
-	}
-
 	/* close is almost always successful */
-	sc->state &= ~PSM_OPEN;
 	kbdc_lock(sc->kbdc, FALSE);
-	device_unbusy(devclass_get_device(psm_devclass, sc->unit));
 	return (0);
 }
 
@@ -2496,7 +2935,7 @@ psmintr(void *arg)
 		pb = &sc->pqueue[sc->pqueue_end];
 
 		/* discard the byte if the device is not open */
-		if ((sc->state & PSM_OPEN) == 0)
+		if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_R | PSM_EV_OPEN_A)))
 			continue;
 
 		getmicrouptime(&now);
@@ -2854,7 +3293,15 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
 				guest_buttons |= MOUSE_BUTTON2DOWN;
 				if (pb->ipacket[1] & 0x02)
 				guest_buttons |= MOUSE_BUTTON3DOWN;
-
+#ifdef EVDEV_SUPPORT
+			if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
+				evdev_push_rel(sc->evdev_r, REL_X, *x);
+				evdev_push_rel(sc->evdev_r, REL_Y, -*y);
+				evdev_push_mouse_btn(sc->evdev_r,
+				    guest_buttons);
+				evdev_sync(sc->evdev_r);
+			}
+#endif
 			ms->button = touchpad_buttons | guest_buttons |
 			    sc->extended_buttons;
 		}
@@ -2965,6 +3412,24 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
 			int mask = 0;
 			maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
 			mask = (1 << maskedbits) - 1;
+#ifdef EVDEV_SUPPORT
+			int i;
+			if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
+				if (sc->synhw.capPassthrough) {
+					evdev_push_mouse_btn(sc->evdev_r,
+						extended_buttons);
+					evdev_sync(sc->evdev_r);
+				}
+				for (i = 0; i < maskedbits; i++) {
+					evdev_push_key(sc->evdev_a,
+					    BTN_0 + i * 2,
+					    pb->ipacket[4] & (1 << i));
+					evdev_push_key(sc->evdev_a,
+					    BTN_0 + i * 2 + 1,
+					    pb->ipacket[5] & (1 << i));
+				}
+			}
+#endif
 			pb->ipacket[4] &= ~(mask);
 			pb->ipacket[5] &= ~(mask);
 		} else	if (!sc->syninfo.directional_scrolls &&
@@ -3016,6 +3481,31 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
 		if (id >= nfingers)
 			PSM_FINGER_RESET(f[id]);
 
+#ifdef EVDEV_SUPPORT
+	if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
+		for (id = 0; id < PSM_FINGERS; id++) {
+			if (PSM_FINGER_IS_SET(f[id]))
+				psm_push_mt_finger(sc, id, &f[id]);
+			else
+				psm_release_mt_slot(sc->evdev_a, id);
+		}
+		evdev_push_key(sc->evdev_a, BTN_TOUCH, nfingers > 0);
+		evdev_push_nfingers(sc->evdev_a, nfingers);
+		if (nfingers > 0)
+			psm_push_st_finger(sc, &f[0]);
+		else
+			evdev_push_abs(sc->evdev_a, ABS_PRESSURE, 0);
+		evdev_push_mouse_btn(sc->evdev_a, touchpad_buttons);
+		if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
+			evdev_push_key(sc->evdev_a, BTN_FORWARD,
+			    touchpad_buttons & MOUSE_BUTTON4DOWN);
+			evdev_push_key(sc->evdev_a, BTN_BACK,
+			    touchpad_buttons & MOUSE_BUTTON5DOWN);
+		}
+		evdev_sync(sc->evdev_a);
+	}
+#endif
+
 	ms->button = touchpad_buttons;
 
 	psmgestures(sc, &f[0], nfingers, ms);
@@ -4015,7 +4505,12 @@ proc_elantech(struct psm_softc *sc, packetbuf_t *pb, m
 		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
 		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) |
 		    ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0);
-
+#ifdef EVDEV_SUPPORT
+		evdev_push_rel(sc->evdev_r, REL_X, *x);
+		evdev_push_rel(sc->evdev_r, REL_Y, -*y);
+		evdev_push_mouse_btn(sc->evdev_r, trackpoint_button);
+		evdev_sync(sc->evdev_r);
+#endif
 		ms->button = touchpad_button | trackpoint_button;
 		return (0);
 
@@ -4042,6 +4537,31 @@ proc_elantech(struct psm_softc *sc, packetbuf_t *pb, m
 		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0);
 	}
 
+#ifdef EVDEV_SUPPORT
+	if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
+		for (id = 0; id < ELANTECH_MAX_FINGERS; id++) {
+			if (PSM_FINGER_IS_SET(f[id])) {
+				psm_push_mt_finger(sc, id, &f[id]);
+				/* Convert touch width to surface units */
+				evdev_push_abs(sc->evdev_a, ABS_MT_TOUCH_MAJOR,
+				    f[id].w * sc->elanhw.dptracex);
+			}
+			if (sc->elanaction.mask & (1 << id) &&
+			    !(mask & (1 << id)))
+				psm_release_mt_slot(sc->evdev_a, id);
+		}
+		evdev_push_key(sc->evdev_a, BTN_TOUCH, nfingers > 0);
+		evdev_push_nfingers(sc->evdev_a, nfingers);
+		if (nfingers > 0) {
+			if (PSM_FINGER_IS_SET(f[0]))
+				psm_push_st_finger(sc, &f[0]);
+		} else
+			evdev_push_abs(sc->evdev_a, ABS_PRESSURE, 0);
+		evdev_push_mouse_btn(sc->evdev_a, touchpad_button);
+		evdev_sync(sc->evdev_a);
+	}
+#endif
+
 	ms->button = touchpad_button | trackpoint_button;
 
 	/* Send finger 1 position to gesture processor */
@@ -4382,6 +4902,41 @@ psmsoftintr(void *arg)
 			break;
 		}
 
+#ifdef EVDEV_SUPPORT
+	if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE &&
+	    sc->hw.model != MOUSE_MODEL_ELANTECH &&
+	    sc->hw.model != MOUSE_MODEL_SYNAPTICS) {
+		evdev_push_rel(sc->evdev_r, EV_REL, x);
+		evdev_push_rel(sc->evdev_r, EV_REL, -y);
+
+		switch (sc->hw.model) {
+		case MOUSE_MODEL_EXPLORER:
+		case MOUSE_MODEL_INTELLI:
+		case MOUSE_MODEL_NET:
+		case MOUSE_MODEL_NETSCROLL:
+		case MOUSE_MODEL_4DPLUS:
+			evdev_push_rel(sc->evdev_r, REL_WHEEL, -z);
+			break;
+		case MOUSE_MODEL_MOUSEMANPLUS:
+		case MOUSE_MODEL_4D:
+			switch (z) {
+			case 1:
+			case -1:
+				evdev_push_rel(sc->evdev_r, REL_WHEEL, -z);
+				break;
+			case 2:
+			case -2:
+				evdev_push_rel(sc->evdev_r, REL_HWHEEL, z / 2);
+				break;
+			}
+			break;
+		}
+
+		evdev_push_mouse_btn(sc->evdev_r, ms.button);
+		evdev_sync(sc->evdev_r);
+	}
+#endif
+
 	/* scale values */
 	if (sc->mode.accelfactor >= 1) {
 		if (x != 0) {
@@ -6494,6 +7049,9 @@ psmresume(device_t dev)
 }
 
 DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
+#ifdef EVDEV_SUPPORT
+MODULE_DEPEND(psm, evdev, 1, 1, 1);
+#endif
 
 #ifdef DEV_ISA
 


More information about the svn-src-all mailing list