Subject: kern/12132: wsmouse emulate3button patch
To: None <gnats-bugs@gnats.netbsd.org>
From: None <takashi.yamamoto@bigfoot.com>
List: netbsd-bugs
Date: 02/04/2001 06:50:28
>Number: 12132
>Category: kern
>Synopsis: wsmouse emulate3button patch
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Feb 04 06:53:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: YAMAMOTO Takashi
>Release: current
>Organization:
>Environment:
NetBSD capybara 1.5R NetBSD 1.5R (535) #86: Sun Feb 4 21:26:14 JST 2001 takashi@capybara:/usr/src/sys/arch/i386/compile/535 i386
>Description:
I'm using trackpoint on my thinkpad, which has 2 buttons, and usb mouse, which has 3 buttons.
I want to use Emulation3Button for trackpoint and not for usb one.
I tried XInput additional mouse feature, but not happy because it
needs to reboot xserver after hot-plug a usb mouse.
so I want wsmouse to emulate 3buttons.
>How-To-Repeat:
>Fix:
apply following patches and
# wsconsctl -mw emu3btn_mask=5
5 means combination of buttons.(101b, left & right)
Index: wsmouse.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.12
diff -u -r1.12 wsmouse.c
--- wsmouse.c 2000/05/01 07:36:58 1.12
+++ wsmouse.c 2001/02/04 14:40:41
@@ -80,6 +80,15 @@
/*
* Mouse driver.
*/
+#if 1
+#define WSMOUSE_EMULATE3BUTTON
+#endif
+
+#ifdef WSMOUSE_DEBUG
+#define DPRINTF(a) printf a
+#else
+#define DPRINTF(a)
+#endif
#include <sys/param.h>
#include <sys/conf.h>
@@ -93,6 +102,9 @@
#include <sys/signalvar.h>
#include <sys/device.h>
#include <sys/vnode.h>
+#ifdef WSMOUSE_EMULATE3BUTTON
+#include <sys/callout.h>
+#endif
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>
@@ -135,6 +147,15 @@
#if NWSMUX > 0
struct wsmux_softc *sc_mux;
#endif
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ struct callout sc_emu3btn_callout;
+ u_int sc_delayed_event;
+ u_int sc_emu3btn_mask;
+ u_int sc_emu3btn_btn;
+ u_int sc_emu3btn_timeout;
+ u_char sc_emulating;
+#endif
};
int wsmouse_match __P((struct device *, struct cfdata *, void *));
@@ -149,6 +170,8 @@
int wsmousedoioctl __P((struct device *, u_long, caddr_t, int,
struct proc *));
+static int wsmouse_input_button(struct wsmouse_softc* sc, u_int mb);
+
struct cfattach wsmouse_ca = {
sizeof (struct wsmouse_softc), wsmouse_match, wsmouse_attach,
wsmouse_detach, wsmouse_activate
@@ -166,6 +189,29 @@
};
#endif
+#ifdef WSMOUSE_EMULATE3BUTTON
+static void
+establish_delayed_event(struct wsmouse_softc* sc)
+{
+ u_int d, mb;
+
+ d = sc->sc_delayed_event;
+ sc->sc_delayed_event = 0;
+ mb = sc->sc_ub ^ d;
+ wsmouse_input_button(sc, mb);
+}
+
+static void
+wsmouse_emu3btn_callout(void* arg)
+{
+ int s;
+
+ s = spltty();
+ establish_delayed_event((struct wsmouse_softc*)arg);
+ splx(s);
+}
+#endif
+
/*
* Print function (for parent devices).
*/
@@ -204,6 +250,15 @@
sc->sc_accesscookie = ap->accesscookie;
sc->sc_ready = 0; /* sanity */
+#ifdef WSMOUSE_EMULATE3BUTTON
+ sc->sc_delayed_event = 0;
+ sc->sc_emu3btn_mask = WSMOUSE_EMU3BTN_MASK_DEFAULT;
+ sc->sc_emu3btn_btn = WSMOUSE_EMU3BTN_BTN_DEFAULT;
+ sc->sc_emu3btn_timeout = WSMOUSE_EMU3BTN_TIMEOUT_DEFAULT;
+ sc->sc_emulating = 0;
+ callout_init(&sc->sc_emu3btn_callout);
+#endif
+
#if NWSMUX > 0
mux = sc->sc_dv.dv_cfdata->wsmousedevcf_mux;
if (mux != WSMOUSEDEVCF_MUX_DEFAULT) {
@@ -290,10 +345,15 @@
u_int flags;
{
struct wsmouse_softc *sc = (struct wsmouse_softc *)wsmousedev;
- struct wscons_event *ev;
struct wseventvar *evar;
- int mb, ub, d, get, put, any;
-
+ u_int mb;
+ int any;
+#ifdef WSMOUSE_EMULATE3BUTTON
+ int emu3btn_mask;
+ int emu3btn_btn;
+ u_int ub;
+ u_int d;
+#endif
/*
* Discard input if not ready.
*/
@@ -323,116 +383,175 @@
* mark them `unchanged'.
*/
any = 0;
- get = evar->get;
- put = evar->put;
- ev = &evar->q[put];
-
- /* NEXT prepares to put the next event, backing off if necessary */
-#define NEXT \
- if ((++put) % WSEVENT_QSIZE == get) { \
- put--; \
- goto out; \
- }
- /* ADVANCE completes the `put' of the event */
-#define ADVANCE \
- ev++; \
- if (put >= WSEVENT_QSIZE) { \
- put = 0; \
- ev = &evar->q[0]; \
- } \
- any = 1
- /* TIMESTAMP sets `time' field of the event to the current time */
-#define TIMESTAMP \
- do { \
- int s; \
- s = splhigh(); \
- TIMEVAL_TO_TIMESPEC(&time, &ev->time); \
- splx(s); \
- } while (0)
if (flags & WSMOUSE_INPUT_ABSOLUTE_X) {
if (sc->sc_x != x) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_X;
- ev->value = x;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_ABSOLUTE_X, x)) {
+ goto out;
+ }
+ any = 1;
sc->sc_x = x;
}
} else {
if (sc->sc_dx) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_DELTA_X;
- ev->value = sc->sc_dx;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DELTA_X, sc->sc_dx)) {
+ goto out;
+ }
+ any = 1;
sc->sc_dx = 0;
}
}
if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) {
if (sc->sc_y != y) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y;
- ev->value = y;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_ABSOLUTE_Y, y)) {
+ goto out;
+ }
+ any = 1;
sc->sc_y = y;
}
} else {
if (sc->sc_dy) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_DELTA_Y;
- ev->value = sc->sc_dy;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DELTA_Y, sc->sc_dy)) {
+ goto out;
+ }
+ any = 1;
sc->sc_dy = 0;
}
}
if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) {
if (sc->sc_z != z) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z;
- ev->value = z;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_ABSOLUTE_Z, z)) {
+ goto out;
+ }
+ any = 1;
sc->sc_z = z;
}
} else {
if (sc->sc_dz) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_DELTA_Z;
- ev->value = sc->sc_dz;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DELTA_Z, sc->sc_dz)) {
+ goto out;
+ }
+ any = 1;
sc->sc_dz = 0;
}
}
mb = sc->sc_mb;
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ ub = sc->sc_ub ^ sc->sc_delayed_event;
+ emu3btn_mask = sc->sc_emu3btn_mask;
+ emu3btn_btn = sc->sc_emu3btn_btn;
+ if ((d = (mb ^ ub) & emu3btn_mask) != 0) {
+ if ((mb & emu3btn_mask) == emu3btn_mask
+ && (sc->sc_delayed_event || sc->sc_emulating || d == emu3btn_mask)) {
+ /* emulate press */
+ sc->sc_delayed_event = 0; /* clear delayed event */
+ sc->sc_emulating = 1; /* start emulating */
+ DPRINTF(("wsmouse: start emulating\n"));
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DOWN, emu3btn_btn)) {
+ goto out;
+ }
+ any = 1;
+ DPRINTF(("wsmouse: emu3btn down\n"));
+ }
+ else if ((ub & emu3btn_mask) == emu3btn_mask && sc->sc_emulating) {
+ /* emulate release */
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_UP, emu3btn_btn)) {
+ goto out;
+ }
+ any = 1;
+ DPRINTF(("wsmouse: emu3btn up\n"));
+ }
+ else {
+ establish_delayed_event(sc);
+
+ /*
+ * if emulating == 0, press event is delayed.
+ */
+ if (sc->sc_emulating == 0 && d & mb) {
+ /*
+ * delay event
+ */
+ sc->sc_delayed_event ^= d;
+ DPRINTF(("wsmouse: set callout delay_ev= %u ub=%u mb=%u\n", d, ub, mb));
+ callout_reset(&sc->sc_emu3btn_callout, hz*sc->sc_emu3btn_timeout/1000,
+ wsmouse_emu3btn_callout, (void*)sc);
+ }
+ }
+ }
+
+ mb ^= sc->sc_delayed_event; /* restrict button events for delayed event */
+
+#endif
+
+ if (wsmouse_input_button(sc, mb) > 0) {
+ any = 1;
+ }
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ if (sc->sc_emulating && (sc->sc_ub & sc->sc_emu3btn_mask) == 0) {
+ sc->sc_emulating = 0;
+ DPRINTF(("wsmouse: end emulating\n"));
+ }
+#endif
+out:
+ if (any) {
+ WSEVENT_WAKEUP(evar);
+ }
+}
+
+/*
+ * return num of enqueued events
+ */
+static int
+wsmouse_input_button(struct wsmouse_softc* sc, u_int mb)
+{
+ struct wseventvar* evar;
+ u_int d;
+ u_int ub;
+ int count = 0;
+
+#if NWSMUX > 0
+ if (sc->sc_mux)
+ evar = &sc->sc_mux->sc_events;
+ else
+#endif
+ evar = &sc->sc_events;
+
ub = sc->sc_ub;
+
while ((d = mb ^ ub) != 0) {
/*
* Mouse button change. Find the first change and drop
* it into the event queue.
*/
- NEXT;
- ev->value = ffs(d) - 1;
+ u_int type;
+ int value;
- KASSERT(ev->value >= 0);
+ type = (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
+ value = ffs(d) - 1;
+ KASSERT(value >= 0);
+ d = 1 << value;
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ if (sc->sc_emulating == 0 || (d & sc->sc_emu3btn_mask) == 0) {
+#endif
+ if (wsevent_write(evar, type, value)) {
+ break;
+ }
+ count ++;
+ DPRINTF(("wsmouse: event: ub %u->%u\n", ub, ub^d));
+#ifdef WSMOUSE_EMULATE3BUTTON
+ }
+#endif
- d = 1 << ev->value;
- ev->type =
- (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
- TIMESTAMP;
- ADVANCE;
ub ^= d;
- }
-out:
- if (any) {
- sc->sc_ub = ub;
- evar->put = put;
- WSEVENT_WAKEUP(evar);
}
+
+ sc->sc_ub = ub;
+
+ return count;
}
int
@@ -594,6 +713,10 @@
{
int error;
+#ifdef WSMOUSE_EMULATE3BUTTON
+ u_int count, t;
+#endif
+
if (sc->sc_dying)
return (EIO);
@@ -612,6 +735,57 @@
if (*(int *)data != sc->sc_events.io->p_pgid)
return (EPERM);
return (0);
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ /*
+ * do emulate 3 button things
+ */
+ case WSMOUSEIO_SEMU3BTN_MASK:
+ t = (uint)*(int*)data;
+ if (t > WSMOUSE_EMU3BTN_MASK_MAX)
+ return (EINVAL);
+
+ /*
+ * count bits
+ */
+ count = 0;
+ for (; t; t &= t-1) {
+ count++;
+ }
+ /*
+ * more than 2 buttons are not supported.
+ */
+ if (count > 2) {
+ return (EINVAL);
+ }
+
+ sc->sc_emu3btn_mask = *(int*)data;
+ return (0);
+
+ case WSMOUSEIO_GEMU3BTN_MASK:
+ *(int*)data = sc->sc_emu3btn_mask;
+ return (0);
+
+ case WSMOUSEIO_SEMU3BTN_BTN:
+ if ((u_int)*(int*)data > WSMOUSE_EMU3BTN_BTN_MAX)
+ return (EINVAL);
+ sc->sc_emu3btn_btn = *(int*)data;
+ return (0);
+
+ case WSMOUSEIO_GEMU3BTN_BTN:
+ *(int*)data = sc->sc_emu3btn_btn;
+ return (0);
+
+ case WSMOUSEIO_SEMU3BTN_TIMEOUT:
+ if ((u_int)*(int*)data > WSMOUSE_EMU3BTN_TIMEOUT_MAX)
+ return (EINVAL);
+ sc->sc_emu3btn_timeout = *(int*)data;
+ return (0);
+
+ case WSMOUSEIO_GEMU3BTN_TIMEOUT:
+ *(int*)data = sc->sc_emu3btn_timeout;
+ return (0);
+#endif
}
/*
Index: wsevent.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wsevent.c,v
retrieving revision 1.5
diff -u -r1.5 wsevent.c
--- wsevent.c 2000/03/30 12:45:44 1.5
+++ wsevent.c 2001/02/04 14:40:41
@@ -89,6 +89,8 @@
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/poll.h>
+#include <sys/syslog.h>
+#include <sys/kernel.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wseventvar.h>
@@ -199,3 +201,36 @@
splx(s);
return (revents);
}
+
+/*
+ * return -1 if can't enqueue (full of queue)
+ */
+int
+wsevent_write(struct wseventvar* evar, u_int type, int value)
+{
+ int put;
+ struct wscons_event* ev;
+ int s;
+
+ put = evar->put;
+ ev = &evar->q[put];
+
+ put = (++put) % WSEVENT_QSIZE;
+ if (put == evar->get) {
+ log(LOG_WARNING, "wscons event queue overflow\n");
+ return -1;
+ }
+
+ ev->type = type;
+ ev->value = value;
+
+ s = splhigh();
+ TIMEVAL_TO_TIMESPEC(&time, &ev->time);
+ splx(s);
+
+ evar->put = put;
+
+ return 0;
+}
+
+
Index: wsconsio.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wsconsio.h,v
retrieving revision 1.37
diff -u -r1.37 wsconsio.h
--- wsconsio.h 2001/02/02 05:58:04 1.37
+++ wsconsio.h 2001/02/04 14:40:45
@@ -194,6 +194,27 @@
#define WSMOUSEIO_SCALIBCOORDS _IOW('W', 36, struct wsmouse_calibcoords)
#define WSMOUSEIO_GCALIBCOORDS _IOR('W', 37, struct wsmouse_calibcoords)
+/* set/get emulate3button mask. 0 means no emulation */
+#define WSMOUSEIO_SEMU3BTN_MASK _IOW('W', 38, u_int)
+#define WSMOUSEIO_GEMU3BTN_MASK _IOR('W', 39, u_int)
+#define WSMOUSE_EMU3BTN_MASK_MIN 0
+#define WSMOUSE_EMU3BTN_MASK_DEFAULT 0
+#define WSMOUSE_EMU3BTN_MASK_MAX 0xffff
+
+/* set/get emulate3button button. */
+#define WSMOUSEIO_SEMU3BTN_BTN _IOW('W', 40, u_int)
+#define WSMOUSEIO_GEMU3BTN_BTN _IOR('W', 41, u_int)
+#define WSMOUSE_EMU3BTN_BTN_MIN 0
+#define WSMOUSE_EMU3BTN_BTN_DEFAULT 1 /* middle button */
+#define WSMOUSE_EMU3BTN_BTN_MAX 31
+
+/* set/get emulate3button timeout. */
+#define WSMOUSEIO_SEMU3BTN_TIMEOUT _IOW('W', 42, u_int)
+#define WSMOUSEIO_GEMU3BTN_TIMEOUT _IOR('W', 43, u_int)
+#define WSMOUSE_EMU3BTN_TIMEOUT_MIN 0
+#define WSMOUSE_EMU3BTN_TIMEOUT_DEFAULT 100
+#define WSMOUSE_EMU3BTN_TIMEOUT_MAX 500
+
/*
* Display ioctls (64 - 95)
*/
Index: mouse.c
===================================================================
RCS file: /cvsroot/basesrc/sbin/wsconsctl/mouse.c,v
retrieving revision 1.3
diff -u -r1.3 mouse.c
--- mouse.c 1999/11/15 13:47:30 1.3
+++ mouse.c 2001/02/04 14:41:51
@@ -45,11 +45,17 @@
static int mstype;
static int resolution;
static int samplerate;
+static int emu3btn_mask;
+static int emu3btn_btn;
+static int emu3btn_timeout;
struct field mouse_field_tab[] = {
{ "resolution", &resolution, FMT_UINT, FLG_WRONLY },
{ "samplerate", &samplerate, FMT_UINT, FLG_WRONLY },
{ "type", &mstype, FMT_MSTYPE, FLG_RDONLY },
+ { "emu3btn_mask", &emu3btn_mask, FMT_UINT, 0 },
+ { "emu3btn_btn", &emu3btn_btn, FMT_UINT, 0 },
+ { "emu3btn_timeout", &emu3btn_timeout, FMT_UINT, 0 },
};
int mouse_field_tab_len = sizeof(mouse_field_tab)/
@@ -62,6 +68,15 @@
if (field_by_value(&mstype)->flags & FLG_GET)
if (ioctl(fd, WSMOUSEIO_GTYPE, &mstype) < 0)
err(1, "WSMOUSEIO_GTYPE");
+ if (field_by_value(&emu3btn_mask)->flags & FLG_GET)
+ if (ioctl(fd, WSMOUSEIO_GEMU3BTN_MASK, &emu3btn_mask) < 0)
+ err(1, "WSMOUSEIO_GEMU3BTN_MASK");
+ if (field_by_value(&emu3btn_btn)->flags & FLG_GET)
+ if (ioctl(fd, WSMOUSEIO_GEMU3BTN_BTN, &emu3btn_btn) < 0)
+ err(1, "WSMOUSEIO_GEMU3BTN_BTN");
+ if (field_by_value(&emu3btn_timeout)->flags & FLG_GET)
+ if (ioctl(fd, WSMOUSEIO_GEMU3BTN_TIMEOUT, &emu3btn_timeout) < 0)
+ err(1, "WSMOUSEIO_GEMU3BTN_TIMEOUT");
}
void
@@ -80,6 +95,24 @@
tmp = samplerate;
if (ioctl(fd, WSMOUSEIO_SRATE, &tmp) < 0)
err(1, "WSMOUSEIO_SRES");
- pr_field(field_by_value(&tmp), " -> ");
+ pr_field(field_by_value(&samplerate), " -> ");
+ }
+ if (field_by_value(&emu3btn_mask)->flags & FLG_SET) {
+ tmp = emu3btn_mask;
+ if (ioctl(fd, WSMOUSEIO_SEMU3BTN_MASK, &tmp) < 0)
+ err(1, "WSMOUSEIO_SEMU3BTN_MASK");
+ pr_field(field_by_value(&emu3btn_mask), " -> ");
+ }
+ if (field_by_value(&emu3btn_btn)->flags & FLG_SET) {
+ tmp = emu3btn_btn;
+ if (ioctl(fd, WSMOUSEIO_SEMU3BTN_BTN, &tmp) < 0)
+ err(1, "WSMOUSEIO_SEMU3BTN_BTN");
+ pr_field(field_by_value(&emu3btn_btn), " -> ");
+ }
+ if (field_by_value(&emu3btn_timeout)->flags & FLG_SET) {
+ tmp = emu3btn_timeout;
+ if (ioctl(fd, WSMOUSEIO_SEMU3BTN_TIMEOUT, &tmp) < 0)
+ err(1, "WSMOUSEIO_SEMU3BTN_TIMEOUT");
+ pr_field(field_by_value(&emu3btn_timeout), " -> ");
}
}
>Release-Note:
>Audit-Trail:
>Unformatted: