Subject: kern/25977: Implement WSMOUSEIO_SSCALE as software scaling
To: None <gnats-bugs@gnats.NetBSD.org>
From: Paul Ripke <stix@stix-amd.stix.org.au>
List: netbsd-bugs
Date: 06/20/2004 14:30:49
>Number:         25977
>Category:       kern
>Synopsis:       Implement WSMOUSEIO_SSCALE as software scaling
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Jun 20 04:58:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Paul Ripke
>Release:        NetBSD 2.0_BETA
>Organization:
>Environment:
System: NetBSD stix-amd.stix.org.au 2.0_BETA NetBSD 2.0_BETA (STIX-AMD) #5: Sun Jun 20 13:57:36 EST 2004 stix@stix-amd.stix.org.au:/export/build/netbsd-2-0/obj.i386/export/build/netbsd-2-0/src/sys/arch/i386/compile/STIX-AMD i386
Architecture: i386
Machine: i386
>Description:
I have a USB mouse with an annoying feature - the smallest delta the mouse
returns is 4 in either the x or y axis.  No matter what settings are used
in X, jumpy behaviour results.  Seeing WSMOUSEIO_SSCALE in the kernel
source, I implemented it as generic software scaling in the wscons layer.
I've run the following patch on i386 for some time with no problems.

>How-To-Repeat:
>Fix:
Index: sbin/wsconsctl/mouse.c
===================================================================
RCS file: /cvsroot/src/sbin/wsconsctl/mouse.c,v
retrieving revision 1.3
diff -u -d -b -w -r1.3 mouse.c
--- sbin/wsconsctl/mouse.c	15 Nov 1999 13:47:30 -0000	1.3
+++ sbin/wsconsctl/mouse.c	20 Jun 2004 03:59:22 -0000
@@ -45,10 +45,12 @@
 static int mstype;
 static int resolution;
 static int samplerate;
+static int scaling[2];
 
 struct field mouse_field_tab[] = {
     { "resolution",		&resolution,	FMT_UINT,	FLG_WRONLY },
     { "samplerate",		&samplerate,	FMT_UINT,	FLG_WRONLY },
+    { "scaling",		&scaling,	FMT_SCALE,	FLG_WRONLY },
     { "type",			&mstype,	FMT_MSTYPE,	FLG_RDONLY },
 };
 
@@ -69,6 +71,7 @@
 	int fd;
 {
 	int tmp;
+	int scale[2];
 
 	if (field_by_value(&resolution)->flags & FLG_SET) {
 		tmp = resolution;
@@ -79,7 +82,14 @@
 	if (field_by_value(&samplerate)->flags & FLG_SET) {
 		tmp = samplerate;
 		if (ioctl(fd, WSMOUSEIO_SRATE, &tmp) < 0)
-			err(1, "WSMOUSEIO_SRES");
+			err(1, "WSMOUSEIO_SRATE");
 		pr_field(field_by_value(&tmp), " -> ");
 	}
+	if (field_by_value(&scaling)->flags & FLG_SET) {
+		scale[0] = scaling[0];
+		scale[1] = scaling[1];
+		if (ioctl(fd, WSMOUSEIO_SSCALE, &scale) < 0)
+			err(1, "WSMOUSEIO_SSCALE");
+		pr_field(field_by_value(&scaling), " -> ");
+	}
 }
Index: sbin/wsconsctl/util.c
===================================================================
RCS file: /cvsroot/src/sbin/wsconsctl/util.c,v
retrieving revision 1.17
diff -u -d -b -w -r1.17 util.c
--- sbin/wsconsctl/util.c	21 Jan 2004 15:39:34 -0000	1.17
+++ sbin/wsconsctl/util.c	20 Jun 2004 03:59:22 -0000
@@ -226,6 +226,10 @@
 	case FMT_UINT:
 		printf("%u", *((u_int *) f->valp));
 		break;
+	case FMT_SCALE:
+		printf("%d/%d", ((u_int *) f->valp)[0],
+		       ((int *) f->valp)[1]);
+		break;
 	case FMT_STRING:
 		printf("\"%s\"", *((char **) f->valp));
 		break;
@@ -289,6 +293,18 @@
 		else
 			*((u_int *) f->valp) = u;
 		break;
+	case FMT_SCALE:
+		p = strchr(val, '/');
+		if (p == NULL)
+			errx(1, "%s: not a valid scaling", val);
+		*p++ = '\0';
+		if (sscanf(val, "%d", &i) != 1)
+			errx(1, "%s: not a number", val);
+		((int *) f->valp)[0] = i;
+		if (sscanf(p, "%d", &i) != 1)
+			errx(1, "%s: not a number", p);
+		((int *) f->valp)[1] = i;
+		break;
 	case FMT_STRING:
 		if ((*((char **) f->valp) = strdup(val)) == NULL)
 			err(1, "strdup");
Index: sbin/wsconsctl/wsconsctl.h
===================================================================
RCS file: /cvsroot/src/sbin/wsconsctl/wsconsctl.h,v
retrieving revision 1.3
diff -u -d -b -w -r1.3 wsconsctl.h
--- sbin/wsconsctl/wsconsctl.h	7 Apr 2002 10:40:04 -0000	1.3
+++ sbin/wsconsctl/wsconsctl.h	20 Jun 2004 03:59:22 -0000
@@ -43,6 +43,7 @@
 	void *valp;
 #define FMT_UINT	1		/* unsigned integer */
 #define FMT_STRING	2		/* zero terminated string */
+#define FMT_SCALE	3		/* scaling in form 'num/den' */
 #define FMT_KBDTYPE	101		/* keyboard type */
 #define FMT_MSTYPE	102		/* mouse type */
 #define FMT_DPYTYPE	103		/* display type */
Index: sys/dev/wscons/wsconsio.h
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsconsio.h,v
retrieving revision 1.61.2.3
diff -u -d -b -w -r1.61.2.3 wsconsio.h
--- sys/dev/wscons/wsconsio.h	7 Jun 2004 09:54:21 -0000	1.61.2.3
+++ sys/dev/wscons/wsconsio.h	20 Jun 2004 03:59:23 -0000
@@ -200,8 +200,8 @@
 #define	WSMOUSE_RES_DEFAULT	75
 #define	WSMOUSE_RES_MAX		100
 
-/* Set scale factor (num / den).  Not applicable to all mouse types. */
-#define	WSMOUSEIO_SSCALE	_IOW('W', 34, u_int[2])
+/* Set software scale factor (num / den). */
+#define	WSMOUSEIO_SSCALE	_IOW('W', 34, int[2])
 
 /* Set sample rate.  Not applicable to all mouse types. */
 #define	WSMOUSEIO_SRATE		_IOW('W', 35, u_int)
Index: sys/dev/wscons/wsmouse.c
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.34
diff -u -d -b -w -r1.34 wsmouse.c
--- sys/dev/wscons/wsmouse.c	28 Nov 2003 13:19:46 -0000	1.34
+++ sys/dev/wscons/wsmouse.c	20 Jun 2004 03:59:24 -0000
@@ -129,6 +129,8 @@
 
 	int		sc_refcnt;
 	u_char		sc_dying;	/* device is being detached */
+	int		sc_scale_num;	/* x/y delta scaling numerator */
+	int		sc_scale_den;	/* x/y delta scaling denominator */
 };
 
 static int  wsmouse_match(struct device *, struct cfdata *, void *);
@@ -201,6 +203,8 @@
 
 	sc->sc_accessops = ap->accessops;
 	sc->sc_accesscookie = ap->accesscookie;
+	sc->sc_scale_num = 1;
+	sc->sc_scale_den = 1;
 
 #if NWSMUX > 0
 	sc->sc_base.me_ops = &wsmouse_srcops;
@@ -311,9 +315,9 @@
 
 	sc->sc_mb = btns;
 	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X))
-		sc->sc_dx += x;
+		sc->sc_dx += x * sc->sc_scale_num / sc->sc_scale_den;
 	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y))
-		sc->sc_dy += y;
+		sc->sc_dy += y * sc->sc_scale_num / sc->sc_scale_den;
 	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z))
 		sc->sc_dz += z;
 
@@ -595,6 +599,12 @@
 		if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
 			return (EPERM);
 		return (0);
+	case WSMOUSEIO_SSCALE:
+		if (((int *)data)[0] == 0 || ((int *)data)[1] == 0)
+			return EINVAL;
+		sc->sc_scale_num = ((int *)data)[0];
+		sc->sc_scale_den = ((int *)data)[1];
+		return (0);
 	}
 
 	/*
>Release-Note:
>Audit-Trail:
>Unformatted: