1/*	$NetBSD: mouse.c,v 1.8 2008/04/28 20:23:09 martin Exp $ */
2
3/*-
4 * Copyright (c) 1998, 2006, 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Juergen Hannken-Illjes and Julio M. Merino Vidal.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/ioctl.h>
33#include <sys/time.h>
34#include <dev/wscons/wsconsio.h>
35
36#include <err.h>
37#include <errno.h>
38#include <limits.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "wsconsctl.h"
44
45static int mstype;
46static int resolution;
47static int samplerate;
48static struct wsmouse_calibcoords calibration;
49static char *calibration_samples;
50static struct wsmouse_repeat repeat;
51
52static void mouse_get_calibration(int);
53static void mouse_put_calibration(int);
54
55static void mouse_get_repeat(int);
56static void mouse_put_repeat(int);
57
58struct field mouse_field_tab[] = {
59    { "resolution",		&resolution,	FMT_UINT,	FLG_WRONLY },
60    { "samplerate",		&samplerate,	FMT_UINT,	FLG_WRONLY },
61    { "type",			&mstype,	FMT_MSTYPE,	FLG_RDONLY },
62    { "calibration.minx",	&calibration.minx,
63    						FMT_INT,	FLG_MODIFY },
64    { "calibration.miny",	&calibration.miny,
65    						FMT_INT,	FLG_MODIFY },
66    { "calibration.maxx",	&calibration.maxx,
67    						FMT_INT,	FLG_MODIFY },
68    { "calibration.maxy",	&calibration.maxy,
69    						FMT_INT,	FLG_MODIFY },
70    { "calibration.samples",	&calibration_samples,
71	    					FMT_STRING,	FLG_MODIFY },
72    { "repeat.buttons",		&repeat.wr_buttons,
73    						FMT_BITFIELD, FLG_MODIFY },
74    { "repeat.delay.first",	&repeat.wr_delay_first,
75    						FMT_UINT, FLG_MODIFY },
76    { "repeat.delay.decrement",	&repeat.wr_delay_decrement,
77    						FMT_UINT, FLG_MODIFY },
78    { "repeat.delay.minimum",	&repeat.wr_delay_minimum,
79 		   				FMT_UINT, FLG_MODIFY },
80};
81
82int mouse_field_tab_len = sizeof(mouse_field_tab)/
83			   sizeof(mouse_field_tab[0]);
84
85void
86mouse_get_values(int fd)
87{
88
89	if (field_by_value(&mstype)->flags & FLG_GET)
90		if (ioctl(fd, WSMOUSEIO_GTYPE, &mstype) < 0)
91			err(EXIT_FAILURE, "WSMOUSEIO_GTYPE");
92
93	if (field_by_value(&calibration.minx)->flags & FLG_GET ||
94	    field_by_value(&calibration.miny)->flags & FLG_GET ||
95	    field_by_value(&calibration.maxx)->flags & FLG_GET ||
96	    field_by_value(&calibration.maxy)->flags & FLG_GET ||
97	    field_by_value(&calibration_samples)->flags & FLG_GET)
98		mouse_get_calibration(fd);
99
100	if (field_by_value(&repeat.wr_buttons)->flags & FLG_GET ||
101	    field_by_value(&repeat.wr_delay_first)->flags & FLG_GET ||
102	    field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET ||
103	    field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
104		mouse_get_repeat(fd);
105}
106
107static void
108mouse_get_calibration(int fd)
109{
110	struct wsmouse_calibcoords tmp;
111	char *samples;
112	char buf[48];
113	int i;
114
115	if (ioctl(fd, WSMOUSEIO_GCALIBCOORDS, &tmp) < 0) {
116		field_disable_by_value(&calibration.minx);
117		field_disable_by_value(&calibration.miny);
118		field_disable_by_value(&calibration.maxx);
119		field_disable_by_value(&calibration.maxy);
120		field_disable_by_value(&calibration_samples);
121		return;
122	}
123
124	if (field_by_value(&calibration.minx)->flags & FLG_GET)
125		calibration.minx = tmp.minx;
126	if (field_by_value(&calibration.miny)->flags & FLG_GET)
127		calibration.miny = tmp.miny;
128	if (field_by_value(&calibration.maxx)->flags & FLG_GET)
129		calibration.maxx = tmp.maxx;
130	if (field_by_value(&calibration.maxy)->flags & FLG_GET)
131		calibration.maxy = tmp.maxy;
132	if (field_by_value(&calibration_samples)->flags & FLG_GET) {
133		free(calibration_samples);
134		if (tmp.samplelen <= 0) {
135			calibration_samples = strdup("");
136			if (calibration_samples == NULL)
137				err(EXIT_FAILURE, "could not list calibration"
138						" samples");
139		} else {
140			samples = malloc(tmp.samplelen * sizeof(buf));
141			if (samples == NULL)
142				err(EXIT_FAILURE, "could not list calibration"
143						" samples");
144			samples[0] = '\0';
145			for (i = 0; i < tmp.samplelen; i++) {
146				snprintf(buf, sizeof(buf), "%s%d,%d,%d,%d",
147						(i == 0) ? "" : ":",
148						tmp.samples[i].rawx,
149						tmp.samples[i].rawy,
150						tmp.samples[i].x,
151						tmp.samples[i].y);
152				strcat(samples, buf);
153			}
154			calibration_samples = samples;
155		}
156	}
157}
158
159static void
160mouse_get_repeat(int fd)
161{
162	struct wsmouse_repeat tmp;
163
164	if (ioctl(fd, WSMOUSEIO_GETREPEAT, &tmp) < 0)
165		err(EXIT_FAILURE, "WSMOUSEIO_GETREPEAT");
166
167	if (field_by_value(&repeat.wr_buttons)->flags & FLG_GET)
168		repeat.wr_buttons = tmp.wr_buttons;
169	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_GET)
170		repeat.wr_delay_first = tmp.wr_delay_first;
171	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET)
172		repeat.wr_delay_decrement = tmp.wr_delay_decrement;
173	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
174		repeat.wr_delay_minimum = tmp.wr_delay_minimum;
175}
176
177void
178mouse_put_values(int fd)
179{
180	int tmp;
181
182	if (field_by_value(&resolution)->flags & FLG_SET) {
183		tmp = resolution;
184		if (ioctl(fd, WSMOUSEIO_SRES, &tmp) < 0)
185			err(EXIT_FAILURE, "WSMOUSEIO_SRES");
186		pr_field(field_by_value(&resolution), " -> ");
187	}
188
189	if (field_by_value(&samplerate)->flags & FLG_SET) {
190		tmp = samplerate;
191		if (ioctl(fd, WSMOUSEIO_SRATE, &tmp) < 0)
192			err(EXIT_FAILURE, "WSMOUSEIO_SRATE");
193		pr_field(field_by_value(&samplerate), " -> ");
194	}
195
196	if (field_by_value(&calibration.minx)->flags & FLG_SET ||
197	    field_by_value(&calibration.miny)->flags & FLG_SET ||
198	    field_by_value(&calibration.maxx)->flags & FLG_SET ||
199	    field_by_value(&calibration.maxy)->flags & FLG_SET ||
200	    field_by_value(&calibration_samples)->flags & FLG_SET)
201		mouse_put_calibration(fd);
202
203	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET ||
204	    field_by_value(&repeat.wr_delay_first)->flags & FLG_SET ||
205	    field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET ||
206	    field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
207		mouse_put_repeat(fd);
208}
209
210static void
211mouse_put_calibration(int fd)
212{
213	struct wsmouse_calibcoords tmp;
214	int i;
215	const char *p;
216	char *q;
217
218	/* Fetch current values into the temporary structure. */
219	if (ioctl(fd, WSMOUSEIO_GCALIBCOORDS, &tmp) < 0)
220		err(EXIT_FAILURE, "WSMOUSEIO_GCALIBCOORDS");
221
222	/* Overwrite the desired values in the temporary structure. */
223	if (field_by_value(&calibration.minx)->flags & FLG_SET)
224		tmp.minx = calibration.minx;
225	if (field_by_value(&calibration.miny)->flags & FLG_SET)
226		tmp.miny = calibration.miny;
227	if (field_by_value(&calibration.maxx)->flags & FLG_SET)
228		tmp.maxx = calibration.maxx;
229	if (field_by_value(&calibration.maxy)->flags & FLG_SET)
230		tmp.maxy = calibration.maxy;
231	if (field_by_value(&calibration_samples)->flags & FLG_SET) {
232		p = calibration_samples;
233		for (i = 0; p[0] != '\0' && i < WSMOUSE_CALIBCOORDS_MAX; i++) {
234			tmp.samples[i].rawx = strtol(p, &q, 0);
235			if (*q != ',')
236				break;
237			p = q + 1;
238			tmp.samples[i].rawy = strtol(p, &q, 0);
239			if (*q != ',')
240				break;
241			p = q + 1;
242			tmp.samples[i].x = strtol(p, &q, 0);
243			if (*q != ',')
244				break;
245			p = q + 1;
246			tmp.samples[i].y = strtol(p, &q, 0);
247			p = q + 1;
248			if (*q != '\0' && *q != ':')
249				break;
250		}
251		if (p[0] != '\0')
252			errx(EXIT_FAILURE, "%s: invalid calibration data",
253					calibration_samples);
254		tmp.samplelen = i;
255	}
256
257	/* Set new values for calibrating events. */
258	if (ioctl(fd, WSMOUSEIO_SCALIBCOORDS, &tmp) < 0)
259		err(EXIT_FAILURE, "WSMOUSEIO_SCALIBCOORDS");
260
261	/* Now print what changed. */
262	if (field_by_value(&calibration.minx)->flags & FLG_SET)
263		pr_field(field_by_value(&calibration.minx), " -> ");
264	if (field_by_value(&calibration.miny)->flags & FLG_SET)
265		pr_field(field_by_value(&calibration.miny), " -> ");
266	if (field_by_value(&calibration.maxx)->flags & FLG_SET)
267		pr_field(field_by_value(&calibration.maxx), " -> ");
268	if (field_by_value(&calibration.maxy)->flags & FLG_SET)
269		pr_field(field_by_value(&calibration.maxy), " -> ");
270	if (field_by_value(&calibration_samples)->flags & FLG_SET)
271		pr_field(field_by_value(&calibration_samples), " -> ");
272}
273
274static void
275mouse_put_repeat(int fd)
276{
277	struct wsmouse_repeat tmp;
278
279	/* Fetch current values into the temporary structure. */
280	if (ioctl(fd, WSMOUSEIO_GETREPEAT, &tmp) < 0)
281		err(EXIT_FAILURE, "WSMOUSEIO_GETREPEAT");
282
283	/* Overwrite the desired values in the temporary structure. */
284	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET)
285		tmp.wr_buttons = repeat.wr_buttons;
286	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_SET)
287		tmp.wr_delay_first = repeat.wr_delay_first;
288	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET)
289		tmp.wr_delay_decrement = repeat.wr_delay_decrement;
290	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
291		tmp.wr_delay_minimum = repeat.wr_delay_minimum;
292
293	/* Set new values for repeating events. */
294	if (ioctl(fd, WSMOUSEIO_SETREPEAT, &tmp) < 0)
295		err(EXIT_FAILURE, "WSMOUSEIO_SETREPEAT");
296
297	/* Now print what changed. */
298	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET)
299		pr_field(field_by_value(&repeat.wr_buttons), " -> ");
300	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_SET)
301		pr_field(field_by_value(&repeat.wr_delay_first), " -> ");
302	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET)
303		pr_field(field_by_value(&repeat.wr_delay_decrement), " -> ");
304	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
305		pr_field(field_by_value(&repeat.wr_delay_minimum), " -> ");
306}
307