summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwulf <wulf@FreeBSD.org>2017-07-16 21:03:26 +0000
committerwulf <wulf@FreeBSD.org>2017-07-16 21:03:26 +0000
commit93da4ece66e1426d0a8b96412ddd06d3c52cfd7f (patch)
tree4b59a40b8347947c6723d3acb481ff16c7e205ec
parent40ddb165ec0d79e5828695fde93eed4343c8e8fe (diff)
downloadFreeBSD-src-93da4ece66e1426d0a8b96412ddd06d3c52cfd7f.zip
FreeBSD-src-93da4ece66e1426d0a8b96412ddd06d3c52cfd7f.tar.gz
MFC r319162:
psm: add support for evdev protocol Approved by: gonzo (mentor)
-rw-r--r--sys/dev/atkbdc/psm.c606
1 files changed, 582 insertions, 24 deletions
diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c
index fadbd45..fd57367 100644
--- a/sys/dev/atkbdc/psm.c
+++ b/sys/dev/atkbdc/psm.c
@@ -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,6 +1618,270 @@ 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)
{
@@ -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
+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
-psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
+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 thread *td)
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 thread *td)
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 thread *td)
/* 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, mousestatus_t *ms,
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, mousestatus_t *ms,
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, mousestatus_t *ms,
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, mousestatus_t *ms,
((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, mousestatus_t *ms,
((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
OpenPOWER on IntegriCloud