Index: sys/dev/wscons/wsconsio.h =================================================================== RCS file: /cvsroot/src/sys/dev/wscons/wsconsio.h,v retrieving revision 1.77 diff -u -p -r1.77 wsconsio.h --- sys/dev/wscons/wsconsio.h 29 Dec 2005 15:24:51 -0000 1.77 +++ sys/dev/wscons/wsconsio.h 3 Feb 2006 17:20:42 -0000 @@ -242,6 +242,18 @@ struct wsmouse_id { }; #define WSMOUSEIO_GETID _IOWR('W', 38, struct wsmouse_id) +/* Get/set emulation scrolling data. */ +struct wsmouse_emul_scroll { + unsigned int wes_repeat; /* Should be a boolean type. */ +#define WSMOUSE_BUTTON_NOVAL -1 + int wes_up; + int wes_down; + int wes_left; + int wes_right; +}; +#define WSMOUSEIO_GETEMULSCROLL _IOR('W', 39, struct wsmouse_emul_scroll) +#define WSMOUSEIO_SETEMULSCROLL _IOW('W', 40, struct wsmouse_emul_scroll) + /* * Display ioctls (64 - 95) */ Index: sys/dev/wscons/wsmouse.c =================================================================== RCS file: /cvsroot/src/sys/dev/wscons/wsmouse.c,v retrieving revision 1.38 diff -u -p -r1.38 wsmouse.c --- sys/dev/wscons/wsmouse.c 11 Dec 2005 12:24:12 -0000 1.38 +++ sys/dev/wscons/wsmouse.c 3 Feb 2006 17:20:42 -0000 @@ -1,5 +1,41 @@ /* $NetBSD: wsmouse.c,v 1.38 2005/12/11 12:24:12 christos Exp $ */ +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Julio M. Merino Vidal. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. * @@ -94,6 +130,8 @@ __KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v #include #include #include +#include +#include #include #include @@ -132,6 +170,14 @@ struct wsmouse_softc { int sc_refcnt; u_char sc_dying; /* device is being detached */ + + struct wsmouse_emul_scroll sc_es; + unsigned int sc_es_mask; + int sc_es_current; + int sc_es_delay; + struct callout sc_es_callout; + + size_t sc_nbuttons; }; static int wsmouse_match(struct device *, struct cfdata *, void *); @@ -154,6 +200,11 @@ static int wsmousedoopen(struct wsmouse CFATTACH_DECL(wsmouse, sizeof (struct wsmouse_softc), wsmouse_match, wsmouse_attach, wsmouse_detach, wsmouse_activate); +#define WSMOUSE_EMUL_SCROLL_DELAY_FIRST ((hz * 200) / 1000) +#define WSMOUSE_EMUL_SCROLL_DELAY_DEC ((hz * 25) / 1000) +#define WSMOUSE_EMUL_SCROLL_DELAY_MIN ((hz * 50) / 1000) +static void wsmouse_emul_scroll(void *v); + extern struct cfdriver wsmouse_cd; dev_type_open(wsmouseopen); @@ -205,6 +256,20 @@ wsmouse_attach(struct device *parent, st sc->sc_accessops = ap->accessops; sc->sc_accesscookie = ap->accesscookie; + /* TODO: Should ask the driver. */ + sc->sc_nbuttons = 32; + + /* Initialize scrolling emulation; disabled by default. */ + sc->sc_es.wes_repeat = FALSE; + sc->sc_es.wes_up = sc->sc_nbuttons >= 5 ? 3 : WSMOUSE_BUTTON_NOVAL; + sc->sc_es.wes_down = sc->sc_nbuttons >= 5 ? 4 : WSMOUSE_BUTTON_NOVAL; + sc->sc_es.wes_left = sc->sc_nbuttons >= 7 ? 5 : WSMOUSE_BUTTON_NOVAL; + sc->sc_es.wes_right = sc->sc_nbuttons >= 7 ? 6 : WSMOUSE_BUTTON_NOVAL; + sc->sc_es_mask = 0; + sc->sc_es_current = 0; + sc->sc_es_delay = 0; + callout_init(&sc->sc_es_callout); + #if NWSMUX > 0 sc->sc_base.me_ops = &wsmouse_srcops; mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux; @@ -437,21 +502,47 @@ wsmouse_input_xyzw(struct device *wsmous mb = sc->sc_mb; while ((d = mb ^ ub) != 0) { + int btnno; + + /* + * Cancel scrolling emulation if button status changed. + */ + if (sc->sc_es_current != 0) { + KASSERT(sc->sc_es.wes_repeat); + KASSERT(sc->sc_es_mask & + (1 << (sc->sc_es_current - 1))); + ub &= ~(1 << (sc->sc_es_current - 1)); + sc->sc_es_current = 0; + callout_stop(&sc->sc_es_callout); + } + /* * Mouse button change. Find the first change and drop * it into the event queue. */ NEXT; - ev->value = ffs(d) - 1; - - KASSERT(ev->value >= 0); + btnno = ffs(d) - 1; + KASSERT(btnno >= 0 && btnno < sc->sc_nbuttons); + ev->value = btnno; d = 1 << ev->value; ev->type = (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP; TIMESTAMP; ADVANCE; ub ^= d; + + /* + * Program repeating for scrolling buttons if this feature + * was requested and the clicked button needs repeating. + */ + if (sc->sc_es.wes_repeat && (mb & d) && + (sc->sc_es_mask & (1 << btnno))) { + sc->sc_es_current = btnno + 1; + sc->sc_es_delay = WSMOUSE_EMUL_SCROLL_DELAY_FIRST; + callout_reset(&sc->sc_es_callout, sc->sc_es_delay, + wsmouse_emul_scroll, sc); + } } out: if (any) { @@ -465,6 +556,77 @@ out: } } +static void +wsmouse_emul_scroll(void *v) +{ + int btnno, delay, oldspl; + struct wsmouse_softc *sc; + struct wseventvar *evar; + + oldspl = spltty(); + sc = (struct wsmouse_softc *)v; + + KASSERT(sc->sc_es.wes_repeat); + + if (sc->sc_es_current == 0) { + /* Race condition: a "button up" event came in when + * this function was already called but did not do + * spltty() yet. */ + splx(oldspl); + return; + } + + btnno = sc->sc_es_current - 1; + + KASSERT(btnno > 0 && btnno < sc->sc_nbuttons); + KASSERT(sc->sc_es_mask & (1 << btnno)); + + delay = sc->sc_es_delay; + + evar = sc->sc_base.me_evp; + if ((evar->put + 1) % WSEVENT_QSIZE != evar->get && + (evar->put + 2) % WSEVENT_QSIZE != evar->get) { + /* Queue has room for at least two more events. */ + int oldspl2; + struct wscons_event *ev; + + /* Construct and inject new button up event. */ + ev = &evar->q[evar->put]; + ev->value = btnno; + ev->type = WSCONS_EVENT_MOUSE_UP; + oldspl2 = splhigh(); + TIMEVAL_TO_TIMESPEC(&time, &ev->time); + splx(oldspl2); + evar->put = (evar->put + 1) % WSEVENT_QSIZE; + + /* Construct and inject new button down event. */ + ev = &evar->q[evar->put]; + ev->value = btnno; + ev->type = WSCONS_EVENT_MOUSE_DOWN; + oldspl2 = splhigh(); + TIMEVAL_TO_TIMESPEC(&time, &ev->time); + splx(oldspl2); + evar->put = (evar->put + 1) % WSEVENT_QSIZE; + + sc->sc_ub = 1 << btnno; + + WSEVENT_WAKEUP(evar); + + if (delay != WSMOUSE_EMUL_SCROLL_DELAY_MIN) + delay -= WSMOUSE_EMUL_SCROLL_DELAY_DEC; + if (delay < WSMOUSE_EMUL_SCROLL_DELAY_MIN) + delay = WSMOUSE_EMUL_SCROLL_DELAY_MIN; + } + + /* + * Reprogram the repeating event. + */ + sc->sc_es_delay = delay; + callout_reset(&sc->sc_es_callout, delay, wsmouse_emul_scroll, sc); + + splx(oldspl); +} + int wsmouseopen(dev_t dev, int flags, int mode, struct lwp *l) { @@ -532,6 +694,13 @@ wsmousedoopen(struct wsmouse_softc *sc, sc->sc_y = INVALID_Y; sc->sc_z = INVALID_Z; + /* Stop scrolling emulation when messing with the device. */ + if (sc->sc_es_current != 0) { + KASSERT(sc->sc_es.wes_repeat); + sc->sc_es_current = 0; + callout_stop(&sc->sc_es_callout); + } + /* enable the device, and punt if that's not possible */ return (*sc->sc_accessops->enable)(sc->sc_accesscookie); } @@ -588,6 +757,7 @@ wsmouse_do_ioctl(struct wsmouse_softc *s int flag, struct lwp *l) { int error; + struct wsmouse_emul_scroll *wes; if (sc->sc_dying) return (EIO); @@ -622,6 +792,47 @@ wsmouse_do_ioctl(struct wsmouse_softc *s } /* + * Try the wsmouse specific ioctls. + */ + switch (cmd) { + case WSMOUSEIO_GETEMULSCROLL: + wes = (struct wsmouse_emul_scroll *)data; + memcpy(wes, &sc->sc_es, sizeof(sc->sc_es)); + return 0; + + case WSMOUSEIO_SETEMULSCROLL: + if ((flag & FWRITE) == 0) + return EACCES; + + /* Validate input data. */ + wes = (struct wsmouse_emul_scroll *)data; + if (wes->wes_up >= sc->sc_nbuttons || (wes->wes_up < 0 && + wes->wes_up != WSMOUSE_BUTTON_NOVAL) || + wes->wes_down >= sc->sc_nbuttons || (wes->wes_down < 0 && + wes->wes_down != WSMOUSE_BUTTON_NOVAL) || + wes->wes_left >= sc->sc_nbuttons || (wes->wes_left < 0 && + wes->wes_left != WSMOUSE_BUTTON_NOVAL) || + wes->wes_right >= sc->sc_nbuttons || (wes->wes_right < 0 && + wes->wes_right != WSMOUSE_BUTTON_NOVAL)) + return EINVAL; + + /* Set new data. */ + memcpy(&sc->sc_es, wes, sizeof(sc->sc_es)); + sc->sc_es_mask = 0; + if (wes->wes_repeat && wes->wes_up != WSMOUSE_BUTTON_NOVAL) + sc->sc_es_mask |= (1 << wes->wes_up); + if (wes->wes_repeat && wes->wes_down != WSMOUSE_BUTTON_NOVAL) + sc->sc_es_mask |= (1 << wes->wes_down); + if (wes->wes_repeat && wes->wes_left != WSMOUSE_BUTTON_NOVAL) + sc->sc_es_mask |= (1 << wes->wes_left); + if (wes->wes_repeat && wes->wes_right != WSMOUSE_BUTTON_NOVAL) + sc->sc_es_mask |= (1 << wes->wes_right); + KASSERT(wes->wes_repeat || sc->sc_es_mask == 0); + + return 0; + } + + /* * Try the mouse driver for WSMOUSEIO ioctls. It returns -1 * if it didn't recognize the request. */ Index: sbin/wsconsctl/mouse.c =================================================================== RCS file: /cvsroot/src/sbin/wsconsctl/mouse.c,v retrieving revision 1.4 diff -u -p -r1.4 mouse.c --- sbin/wsconsctl/mouse.c 19 Jan 2005 20:37:52 -0000 1.4 +++ sbin/wsconsctl/mouse.c 3 Feb 2006 17:20:42 -0000 @@ -1,11 +1,11 @@ /* $NetBSD: mouse.c,v 1.4 2005/01/19 20:37:52 xtraeme Exp $ */ /*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. + * Copyright (c) 1998, 2006 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Juergen Hannken-Illjes. + * by Juergen Hannken-Illjes and Julio M. Merino Vidal. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,17 +39,32 @@ #include #include #include + #include +#include +#include +#include +#include +#include + #include "wsconsctl.h" +#define STRSIZE 255 + static int mstype; static int resolution; static int samplerate; +static struct wsmouse_emul_scroll scroll; struct field mouse_field_tab[] = { { "resolution", &resolution, FMT_UINT, FLG_WRONLY }, { "samplerate", &samplerate, FMT_UINT, FLG_WRONLY }, { "type", &mstype, FMT_MSTYPE, FLG_RDONLY }, + { "emul.scroll.repeat", &scroll.wes_repeat, FMT_BOOLEAN, FLG_MODIFY }, + { "emul.scroll.up", &scroll.wes_up, FMT_UINT, FLG_MODIFY }, + { "emul.scroll.down", &scroll.wes_down, FMT_UINT, FLG_MODIFY }, + { "emul.scroll.left", &scroll.wes_left, FMT_UINT, FLG_MODIFY }, + { "emul.scroll.right", &scroll.wes_right, FMT_UINT, FLG_MODIFY }, }; int mouse_field_tab_len = sizeof(mouse_field_tab)/ @@ -61,23 +76,95 @@ mouse_get_values(int fd) if (field_by_value(&mstype)->flags & FLG_GET) if (ioctl(fd, WSMOUSEIO_GTYPE, &mstype) < 0) err(1, "WSMOUSEIO_GTYPE"); + + /* + * Handle gets from the 'emul.scroll' node. + */ + if (field_by_value(&scroll.wes_repeat)->flags & FLG_GET || + field_by_value(&scroll.wes_up)->flags & FLG_GET || + field_by_value(&scroll.wes_down)->flags & FLG_GET || + field_by_value(&scroll.wes_left)->flags & FLG_GET || + field_by_value(&scroll.wes_right)->flags & FLG_GET) { + struct wsmouse_emul_scroll tmp; + + if (ioctl(fd, WSMOUSEIO_GETEMULSCROLL, &tmp) == -1) + err(1, "WSMOUSEIO_GETEMULSCROLL"); + + if (field_by_value(&scroll.wes_repeat)->flags & FLG_GET) + scroll.wes_repeat = tmp.wes_repeat; + if (field_by_value(&scroll.wes_up)->flags & FLG_GET) + scroll.wes_up = tmp.wes_up; + if (field_by_value(&scroll.wes_down)->flags & FLG_GET) + scroll.wes_down = tmp.wes_down; + if (field_by_value(&scroll.wes_left)->flags & FLG_GET) + scroll.wes_left = tmp.wes_left; + if (field_by_value(&scroll.wes_right)->flags & FLG_GET) + scroll.wes_right = tmp.wes_right; + } } void mouse_put_values(int fd) { - int tmp; if (field_by_value(&resolution)->flags & FLG_SET) { + int tmp; + tmp = resolution; if (ioctl(fd, WSMOUSEIO_SRES, &tmp) < 0) err(1, "WSMOUSEIO_SRES"); pr_field(field_by_value(&resolution), " -> "); } + if (field_by_value(&samplerate)->flags & FLG_SET) { + int tmp; + tmp = samplerate; if (ioctl(fd, WSMOUSEIO_SRATE, &tmp) < 0) err(1, "WSMOUSEIO_SRES"); pr_field(field_by_value(&tmp), " -> "); } + + /* + * Handle sets on the 'emul.scroll' node. + */ + if (field_by_value(&scroll.wes_repeat)->flags & FLG_SET || + field_by_value(&scroll.wes_up)->flags & FLG_SET || + field_by_value(&scroll.wes_down)->flags & FLG_SET || + field_by_value(&scroll.wes_left)->flags & FLG_SET || + field_by_value(&scroll.wes_right)->flags & FLG_SET) { + struct wsmouse_emul_scroll tmp; + + /* Fetch current values into the temporary structure. */ + if (ioctl(fd, WSMOUSEIO_GETEMULSCROLL, &tmp) == -1) + err(1, "WSMOUSEIO_GETEMULSCROLL"); + + /* Overwrite the desired values in the temporary structure. */ + if (field_by_value(&scroll.wes_repeat)->flags & FLG_SET) + tmp.wes_repeat = scroll.wes_repeat; + if (field_by_value(&scroll.wes_up)->flags & FLG_SET) + tmp.wes_up = scroll.wes_up; + if (field_by_value(&scroll.wes_down)->flags & FLG_SET) + tmp.wes_down = scroll.wes_down; + if (field_by_value(&scroll.wes_left)->flags & FLG_SET) + tmp.wes_left = scroll.wes_left; + if (field_by_value(&scroll.wes_right)->flags & FLG_SET) + tmp.wes_right = scroll.wes_right; + + /* Set new values for all scrolling buttons. */ + if (ioctl(fd, WSMOUSEIO_SETEMULSCROLL, &tmp) == -1) + err(1, "WSMOUSEIO_SETEMULSCROLL"); + + /* Now print what changed. */ + if (field_by_value(&scroll.wes_repeat)->flags & FLG_SET) + pr_field(field_by_value(&scroll.wes_repeat), " -> "); + if (field_by_value(&scroll.wes_up)->flags & FLG_SET) + pr_field(field_by_value(&scroll.wes_up), " -> "); + if (field_by_value(&scroll.wes_down)->flags & FLG_SET) + pr_field(field_by_value(&scroll.wes_down), " -> "); + if (field_by_value(&scroll.wes_left)->flags & FLG_SET) + pr_field(field_by_value(&scroll.wes_left), " -> "); + if (field_by_value(&scroll.wes_right)->flags & FLG_SET) + pr_field(field_by_value(&scroll.wes_right), " -> "); + } } Index: sbin/wsconsctl/util.c =================================================================== RCS file: /cvsroot/src/sbin/wsconsctl/util.c,v retrieving revision 1.23 diff -u -p -r1.23 util.c --- sbin/wsconsctl/util.c 26 Jun 2005 22:45:50 -0000 1.23 +++ sbin/wsconsctl/util.c 3 Feb 2006 17:20:43 -0000 @@ -1,11 +1,11 @@ /* $NetBSD: util.c,v 1.23 2005/06/26 22:45:50 christos Exp $ */ /*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. + * Copyright (c) 1998, 2006 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Juergen Hannken-Illjes. + * by Juergen Hannken-Illjes and Julio M. Merino Vidal. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -255,6 +255,9 @@ pr_field(struct field *f, const char *se case FMT_STRING: printf("\"%s\"", *((char **) f->valp)); break; + case FMT_BOOLEAN: + printf("%s", *((int *) f->valp) ? "true" : "false"); + break; case FMT_KBDTYPE: p = int2name(*((u_int *) f->valp), 1, kbtype_tab, TABLEN(kbtype_tab)); @@ -336,6 +339,18 @@ rd_field(struct field *f, char *val, int if ((*((char **) f->valp) = strdup(val)) == NULL) err(1, "strdup"); break; + case FMT_BOOLEAN: + if (strcasecmp(val, "true") == 0 || + strcasecmp(val, "yes") == 0 || + strcasecmp(val, "1") == 0) + *((int *) f->valp) = 1; + else if (strcasecmp(val, "false") == 0 || + strcasecmp(val, "no") == 0 || + strcasecmp(val, "0") == 0) + *((int *) f->valp) = 0; + else + errx(1, "%s: not a boolean value", val); + break; case FMT_KBDENC: p = strchr(val, '.'); if (p != NULL) Index: sbin/wsconsctl/wsconsctl.h =================================================================== RCS file: /cvsroot/src/sbin/wsconsctl/wsconsctl.h,v retrieving revision 1.8 diff -u -p -r1.8 wsconsctl.h --- sbin/wsconsctl/wsconsctl.h 26 Jun 2005 22:45:50 -0000 1.8 +++ sbin/wsconsctl/wsconsctl.h 3 Feb 2006 17:20:43 -0000 @@ -61,6 +61,7 @@ struct field { void *valp; #define FMT_UINT 1 /* unsigned integer */ #define FMT_STRING 2 /* zero terminated string */ +#define FMT_BOOLEAN 3 /* boolean */ #define FMT_KBDTYPE 101 /* keyboard type */ #define FMT_MSTYPE 102 /* mouse type */ #define FMT_DPYTYPE 103 /* display type */