|
|
@@ -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,15 +696,26 @@ 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,
|
|
|
.d_poll = psmpoll,
|
|
|
.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
|
|
|
|
|
|
|