NetBSD Problem Report #12132

Received: (qmail 27853 invoked from network); 4 Feb 2001 14:52:51 -0000
Message-Id: <200102041452.GAA22391@nbwww.isc.org>
Date: Sun, 4 Feb 2001 06:52:50 -0800 (PST)
From: takashi.yamamoto@bigfoot.com
Reply-To: takashi.yamamoto@bigfoot.com
To: gnats-bugs@gnats.netbsd.org
Subject: wsmouse emulate3button patch
X-Send-Pr-Version: www-1.0

>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 14:53:00 +0000 2001
>Closed-Date:    
>Last-Modified:  Sat Jul 14 19:35:11 +0000 2012
>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:
Responsible-Changed-From-To: kern-bug-people->jmmv
Responsible-Changed-By: jmmv@netbsd.org
Responsible-Changed-When: Mon, 06 Feb 2006 22:31:02 +0000
Responsible-Changed-Why:
I will handle this one, as I was planning to implement this feature.


From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
To: gnats-bugs@netbsd.org
Cc: jmmv@netbsd.org, kern-bug-people@netbsd.org,
	netbsd-bugs@netbsd.org, gnats-admin@netbsd.org, jmmv@netbsd.org,
	takashi.yamamoto@bigfoot.com
Subject: Re: kern/12132 (wsmouse emulate3button patch)
Date: Tue, 07 Feb 2006 07:57:10 +0900

 --NextPart-20060207075223-0364900
 Content-Type: Text/Plain; charset=us-ascii

 > Synopsis: wsmouse emulate3button patch

 i digged a patch which seems newer than the one in the PR.  (attached)
 no idea which is better, tho. :-)

 YAMAMOTO Takashi

 --NextPart-20060207075223-0364900
 Content-Type: Text/Plain; charset=us-ascii
 Content-Disposition: attachment; filename="emu3btn.diff"

 Index: wsconsio.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/wscons/wsconsio.h,v
 retrieving revision 1.76
 diff -u -p -r1.76 wsconsio.h
 --- wsconsio.h	23 Nov 2005 09:38:02 -0000	1.76
 +++ wsconsio.h	27 Nov 2005 23:14:45 -0000
 @@ -241,6 +241,27 @@ struct wsmouse_id {
  };
  #define	WSMOUSEIO_GETID		_IOWR('W', 38, struct wsmouse_id)

 +/* set/get emulate3button mask. 0 means no emulation */
 +#define	WSMOUSEIO_SEMU3BTN_MASK		_IOW('W', 58, u_int)
 +#define	WSMOUSEIO_GEMU3BTN_MASK		_IOR('W', 59, 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', 60, u_int)
 +#define	WSMOUSEIO_GEMU3BTN_BTN		_IOR('W', 61, 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', 62, u_int)
 +#define	WSMOUSEIO_GEMU3BTN_TIMEOUT		_IOR('W', 63, 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: wsevent.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/wscons/wsevent.c,v
 retrieving revision 1.16
 diff -u -p -r1.16 wsevent.c
 --- wsevent.c	7 Aug 2003 16:31:29 -0000	1.16
 +++ wsevent.c	27 Nov 2005 23:14:45 -0000
 @@ -85,6 +85,9 @@ __KERNEL_RCSID(0, "$NetBSD: wsevent.c,v 
  #include <sys/vnode.h>
  #include <sys/select.h>
  #include <sys/poll.h>
 +#include <sys/syslog.h>
 +#include <sys/kernel.h>
 +#include <sys/time.h>

  #include <dev/wscons/wsconsio.h>
  #include <dev/wscons/wseventvar.h>
 @@ -199,6 +202,40 @@ wsevent_poll(struct wseventvar *ev, int 
  	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 + 1) % WSEVENT_QSIZE;
 +    if (put == evar->get) {
 +		static struct timeval last;
 +		struct timeval interval = {5, 0};
 +		if (ratecheck(&last, &interval))
 +			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;
 +}
 +
  static void
  filt_wseventrdetach(struct knote *kn)
  {
 Index: wseventvar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/wscons/wseventvar.h,v
 retrieving revision 1.8
 diff -u -p -r1.8 wseventvar.h
 --- wseventvar.h	7 Aug 2003 16:31:29 -0000	1.8
 +++ wseventvar.h	27 Nov 2005 23:14:45 -0000
 @@ -105,6 +105,7 @@ void	wsevent_init(struct wseventvar *);
  void	wsevent_fini(struct wseventvar *);
  int	wsevent_read(struct wseventvar *, struct uio *, int);
  int	wsevent_poll(struct wseventvar *, int, struct proc *);
 +int	wsevent_write(struct wseventvar *, u_int, int);
  int	wsevent_kqfilter(struct wseventvar *ev, struct knote *kn);

  /*
 Index: wsmouse.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/wscons/wsmouse.c,v
 retrieving revision 1.37
 diff -u -p -r1.37 wsmouse.c
 --- wsmouse.c	23 Nov 2005 09:38:02 -0000	1.37
 +++ wsmouse.c	27 Nov 2005 23:14:46 -0000
 @@ -73,6 +73,10 @@
  /*
   * Mouse driver.
   */
 +#if 1
 +#define WSMOUSE_EMULATE3BUTTON
 +/*#define WSMOUSE_DEBUG*/
 +#endif

  #include <sys/cdefs.h>
  __KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v 1.37 2005/11/23 09:38:02 augustss Exp $");
 @@ -94,6 +98,9 @@ __KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v 
  #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>
 @@ -132,6 +139,15 @@ struct wsmouse_softc {

  	int		sc_refcnt;
  	u_char		sc_dying;	/* device is being detached */
 +
 +#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
  };

  static int  wsmouse_match(struct device *, struct cfdata *, void *);
 @@ -149,6 +165,11 @@ static int  wsmouse_mux_close(struct wse

  static int  wsmousedoioctl(struct device *, u_long, caddr_t, int, struct proc *);

 +static int wsmouse_input_button(struct wsmouse_softc *, u_int);
 +#ifdef WSMOUSE_EMULATE3BUTTON
 +static void establish_delayed_event(struct wsmouse_softc *);
 +static void wsmouse_emu3btn_callout(void *);
 +#endif
  static int  wsmousedoopen(struct wsmouse_softc *, struct wseventvar *);

  CFATTACH_DECL(wsmouse, sizeof (struct wsmouse_softc),
 @@ -175,6 +196,39 @@ struct wssrcops wsmouse_srcops = {
  };
  #endif

 +#ifdef WSMOUSE_EMULATE3BUTTON
 +static void
 +establish_delayed_event(struct wsmouse_softc* sc)
 +{
 +	u_int d, mb;
 +/*
 +	if (sc->sc_delayed_event == 0) {
 +		DPRINTF(("wsmouse: no delayed events to establish\n"));
 +	}
 +	else {
 +*/
 +		DPRINTF(("wsmouse: establish delayed event(%x)\n", sc->sc_delayed_event));
 +		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;
 +
 +	DPRINTF(("wsmouse: callout\n"));
 +	s = spltty();
 +	establish_delayed_event((struct wsmouse_softc*)arg);
 +	splx(s);
 +}
 +#endif
 +
  /*
   * Print function (for parent devices).
   */
 @@ -205,6 +259,15 @@ wsmouse_attach(struct device *parent, st
  	sc->sc_accessops = ap->accessops;
  	sc->sc_accesscookie = ap->accesscookie;

 +#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
  	sc->sc_base.me_ops = &wsmouse_srcops;
  	mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux;
 @@ -289,10 +352,15 @@ wsmouse_input_xyzw(struct device *wsmous
  	int x, int y, int z, int w, 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;
 +	int any;
 +	u_int mb;

 +#ifdef WSMOUSE_EMULATE3BUTTON
 +	u_int d, ub;
 +	int emu3btn_mask;
 +	int emu3btn_btn;
 +#endif
          /*
           * Discard input if not open.
           */
 @@ -329,89 +397,56 @@ wsmouse_input_xyzw(struct device *wsmous
  	 * of changes or out of room.  As events get delivered,
  	 * mark them `unchanged'.
  	 */
 -	ub = sc->sc_ub;
  	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;
  		}
  	}
 @@ -436,27 +471,67 @@ wsmouse_input_xyzw(struct device *wsmous
  	}

  	mb = sc->sc_mb;
 -	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;

 -		KASSERT(ev->value >= 0);
 +#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);

 -		d = 1 << ev->value;
 -		ev->type =
 -		    (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
 -		TIMESTAMP;
 -		ADVANCE;
 -		ub ^= d;
 +			/*
 +			 * 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) {
 -		sc->sc_ub = ub;
 -		evar->put = put;
  		WSEVENT_WAKEUP(evar);
  #if NWSMUX > 0
  		DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n",
 @@ -465,6 +540,54 @@ out:
  	}
  }

 +/*
 + * 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;
 +
 +	evar = sc->sc_base.me_evp;
 +
 +	ub = sc->sc_ub;
 +
 +	while ((d = mb ^ ub) != 0) {
 +		/*
 +		 * Mouse button change.  Find the first change and drop
 +		 * it into the event queue.
 +		 */
 +		u_int type;
 +		int value;
 +
 +		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
 +
 +		ub ^= d;
 +	}
 +
 +	sc->sc_ub = ub;
 +
 +	return count;
 +}
 +
  int
  wsmouseopen(dev_t dev, int flags, int mode, struct proc *p)
  {
 @@ -589,6 +712,10 @@ wsmouse_do_ioctl(struct wsmouse_softc *s
  {
  	int error;

 +#ifdef WSMOUSE_EMULATE3BUTTON
 +	u_int count, t;
 +#endif
 +
  	if (sc->sc_dying)
  		return (EIO);

 @@ -619,6 +746,57 @@ wsmouse_do_ioctl(struct wsmouse_softc *s
  		if (*(int *)data != sc->sc_base.me_evp->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
  	}

  	/*

 --NextPart-20060207075223-0364900--

Responsible-Changed-From-To: jmmv->kern-bug-people
Responsible-Changed-By: jmmv@NetBSD.org
Responsible-Changed-When: Sat, 14 Jul 2012 19:35:11 +0000
Responsible-Changed-Why:
I have no interest nor time any more to look at this.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.