GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/wsconsctl/mousecfg.c Lines: 0 116 0.0 %
Date: 2017-11-13 Branches: 0 96 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: mousecfg.c,v 1.1 2017/07/21 20:38:20 bru Exp $ */
2
3
/*
4
 * Copyright (c) 2017 Ulf Brosziewski
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
/*
20
 * Read/write wsmouse parameters for touchpad configuration.
21
 */
22
23
#include <sys/ioctl.h>
24
#include <sys/param.h>
25
#include <dev/wscons/wsconsio.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <err.h>
30
#include <errno.h>
31
#include "mousecfg.h"
32
33
#define BASE_FIRST		WSMOUSECFG_DX_SCALE
34
#define BASE_LAST		WSMOUSECFG_Y_INV
35
#define TP_FILTER_FIRST		WSMOUSECFG_DX_MAX
36
#define TP_FILTER_LAST		WSMOUSECFG_SMOOTHING
37
#define TP_FEATURES_FIRST	WSMOUSECFG_SOFTBUTTONS
38
#define TP_FEATURES_LAST	WSMOUSECFG_TAPPING
39
#define TP_SETUP_FIRST		WSMOUSECFG_LEFT_EDGE
40
#define TP_SETUP_LAST		WSMOUSECFG_TAP_LOCKTIME
41
42
#define BASESIZE (BASE_LAST - BASE_FIRST + 1)
43
44
#define BUFSIZE (BASESIZE \
45
    + (TP_FILTER_LAST - TP_FILTER_FIRST + 1) \
46
    + (TP_FEATURES_LAST - TP_FEATURES_FIRST + 1) \
47
    + (TP_SETUP_LAST - TP_SETUP_FIRST + 1))
48
49
static const int range[][2] = {
50
	{ BASE_FIRST, BASE_LAST },
51
	{ TP_FILTER_FIRST, TP_FILTER_LAST },
52
	{ TP_FEATURES_FIRST, TP_FEATURES_LAST },
53
	{ TP_SETUP_FIRST, TP_SETUP_LAST },
54
};
55
56
static const int touchpad_types[] = {
57
	WSMOUSE_TYPE_SYNAPTICS,		/* Synaptics touchpad */
58
	WSMOUSE_TYPE_ALPS,		/* ALPS touchpad */
59
	WSMOUSE_TYPE_ELANTECH,		/* Elantech touchpad */
60
	WSMOUSE_TYPE_SYNAP_SBTN,	/* Synaptics soft buttons */
61
};
62
63
struct wsmouse_parameters cfg_tapping = {
64
	(struct wsmouse_param[]) {
65
	    { WSMOUSECFG_TAPPING, 0 }, },
66
	1
67
};
68
69
struct wsmouse_parameters cfg_scaling = {
70
	(struct wsmouse_param[]) {
71
	    { WSMOUSECFG_DX_SCALE, 0 },
72
	    { WSMOUSECFG_DY_SCALE, 0 } },
73
	2
74
};
75
76
struct wsmouse_parameters cfg_swapsides = {
77
	(struct wsmouse_param[]) {
78
	    { WSMOUSECFG_SWAPSIDES, 0 }, },
79
	1
80
};
81
82
struct wsmouse_parameters cfg_disable = {
83
	(struct wsmouse_param[]) {
84
	    { WSMOUSECFG_DISABLE, 0 }, },
85
	1
86
};
87
88
struct wsmouse_parameters cfg_param = {
89
	(struct wsmouse_param[]) {
90
	    { -1, 0 },
91
	    { -1, 0 },
92
	    { -1, 0 },
93
	    { -1, 0 } },
94
	4
95
};
96
97
static int cfg_horiz_res;
98
static int cfg_vert_res;
99
static struct wsmouse_param cfg_buffer[BUFSIZE];
100
101
102
int
103
mousecfg_init(int dev_fd, const char **errstr)
104
{
105
	struct wsmouse_calibcoords coords;
106
	struct wsmouse_parameters parameters;
107
	struct wsmouse_param *param;
108
	enum wsmousecfg k;
109
	int i, err, type;
110
111
	*errstr = NULL;
112
113
	if ((err = ioctl(dev_fd, WSMOUSEIO_GTYPE, &type))) {
114
		*errstr = "WSMOUSEIO_GTYPE";
115
		return err;
116
	}
117
	for (i = 0; i < nitems(touchpad_types)
118
	    && type != touchpad_types[i]; i++) {}
119
120
	/*
121
	 * If the device is not a touchpad, return an error without
122
	 * setting the error string.  The caller shouldn't print a
123
	 * warning in this case.
124
	 */
125
	if (i == nitems(touchpad_types))
126
		return (-1);
127
128
	if ((err = ioctl(dev_fd, WSMOUSEIO_GCALIBCOORDS, &coords))) {
129
		*errstr = "WSMOUSEIO_GCALIBCOORDS";
130
		return err;
131
	}
132
	cfg_horiz_res = coords.resx;
133
	cfg_vert_res = coords.resy;
134
135
	param = cfg_buffer;
136
	for (i = 0; i < nitems(range); i++)
137
		for (k = range[i][0]; k <= range[i][1]; k++, param++) {
138
			param->key = k;
139
			param->value = 0;
140
		}
141
142
	/*
143
	 * Not all touchpad drivers configure wsmouse for compat mode yet.
144
	 * In those cases the first ioctl call may be successful but the
145
	 * second one will fail because it includes wstpad parameters:
146
	 */
147
	parameters.params = cfg_buffer;
148
	parameters.nparams = BASESIZE;
149
	if ((err = ioctl(dev_fd, WSMOUSEIO_GETPARAMS, &parameters))) {
150
		*errstr = "WSMOUSEIO_GETPARAMS";
151
		return (err);
152
	}
153
	parameters.params = cfg_buffer + BASESIZE;
154
	parameters.nparams = BUFSIZE - BASESIZE;
155
	if ((err = ioctl(dev_fd, WSMOUSEIO_GETPARAMS, &parameters))) {
156
		if (err != EINVAL)
157
			*errstr = "WSMOUSEIO_GETPARAMS";
158
		return (err);
159
	}
160
161
	return (0);
162
}
163
164
/* Map a key to its buffer index. */
165
static int
166
index_of(enum wsmousecfg key)
167
{
168
	int i, n;
169
170
	for (i = 0, n = 0; i < nitems(range); i++)
171
		if (key <= range[i][1] && key >= range[i][0])
172
			return (key - range[i][0] + n);
173
		else
174
			n += range[i][1] - range[i][0] + 1;
175
176
	return (-1);
177
}
178
179
int
180
mousecfg_get_field(struct wsmouse_parameters *field)
181
{
182
	int i, n;
183
184
	for (i = 0; i < field->nparams; i++) {
185
		if ((n = index_of(field->params[i].key)) >= 0)
186
			field->params[i].value = cfg_buffer[n].value;
187
		else
188
			return (-1);
189
	}
190
	return (0);
191
}
192
193
int
194
mousecfg_put_field(int fd, struct wsmouse_parameters *field)
195
{
196
	int i, n, d, err;
197
198
	d = 0;
199
	for (i = 0; i < field->nparams; i++)
200
		if ((n = index_of(field->params[i].key)) < 0)
201
			return (-1);
202
		else
203
			d |= (cfg_buffer[n].value != field->params[i].value);
204
205
	if (!d)
206
		return (0);
207
208
	/* Write and read back immediately, wsmouse may normalize values. */
209
	if ((err = ioctl(fd, WSMOUSEIO_SETPARAMS, field))
210
	    || (err = ioctl(fd, WSMOUSEIO_GETPARAMS, field)))
211
		return err;
212
213
	for (i = 0; i < field->nparams; i++)
214
		cfg_buffer[n].value = field->params[i].value;
215
216
	return (0);
217
}
218
219
static int
220
get_value(struct wsmouse_parameters *field, enum wsmousecfg key)
221
{
222
	int i;
223
224
	for (i = 0; i < field->nparams && key != field->params[i].key; i++) {}
225
226
	return (i < field->nparams ? field->params[i].value : 0);
227
}
228
229
static void
230
set_value(struct wsmouse_parameters *field, enum wsmousecfg key, int value)
231
{
232
	int i;
233
234
	for (i = 0; i < field->nparams && key != field->params[i].key; i++) {}
235
236
	field->params[i].value = (i < field->nparams ? value : 0);
237
}
238
239
/*
240
 * Read or write up to four raw parameter values.  In this case
241
 * reading is a 'put' operation that writes back a value from the
242
 * buffer.
243
 */
244
static int
245
read_param(struct wsmouse_parameters *field, char *val)
246
{
247
	int i, j, n;
248
249
	n = sscanf(val, "%d:%d,%d:%d,%d:%d,%d:%d",
250
		&field->params[0].key, &field->params[0].value,
251
		&field->params[1].key, &field->params[1].value,
252
		&field->params[2].key, &field->params[2].value,
253
		&field->params[3].key, &field->params[3].value);
254
	if (n > 0 && (n & 1) == 0) {
255
		n /= 2;
256
		for (i = 0; i < n; i++) {
257
			if (index_of(field->params[i].key) < 0)
258
				return (-1);
259
		}
260
		field->nparams = n;
261
		return (0);
262
	}
263
	n = sscanf(val, "%d,%d,%d,%d",
264
		&field->params[0].key, &field->params[1].key,
265
		&field->params[2].key, &field->params[3].key);
266
	if (n > 0) {
267
		for (i = 0; i < n; i++) {
268
			if ((j = index_of(field->params[i].key)) < 0)
269
				return (-1);
270
			field->params[i].value = cfg_buffer[j].value;
271
		}
272
		field->nparams = n;
273
		return (0);
274
	}
275
	return (-1);
276
}
277
278
void
279
mousecfg_pr_field(struct wsmouse_parameters *field)
280
{
281
	int i, value;
282
	float f;
283
284
	if (field == &cfg_param) {
285
		for (i = 0; i < field->nparams; i++)
286
			printf(i > 0 ? ",%d:%d" : "%d:%d",
287
			    field->params[i].key,
288
			    field->params[i].value);
289
		return;
290
	}
291
292
	if (field == &cfg_scaling) {
293
		value = get_value(field, WSMOUSECFG_DX_SCALE);
294
		f = (float) value / 4096;
295
		printf("%.3f", f);
296
		return;
297
	}
298
299
	for (i = 0; i < field->nparams; i++)
300
		printf(i > 0 ? ",%d" : "%d", field->params[i].value);
301
}
302
303
void
304
mousecfg_rd_field(struct wsmouse_parameters *field, char *val)
305
{
306
	enum wsmousecfg first = field->params[0].key;
307
	int i, n;
308
	const char *s;
309
	float f;
310
311
	if (field == &cfg_param) {
312
		if (read_param(field, val))
313
			errx(1, "invalid input (param)");
314
		return;
315
	}
316
317
	if (field == &cfg_scaling) {
318
		if (sscanf(val, "%f", &f) == 1) {
319
			n = (int) (f * 4096);
320
			set_value(field, WSMOUSECFG_DX_SCALE, n);
321
			if (cfg_horiz_res && cfg_vert_res)
322
				n = n * cfg_horiz_res / cfg_vert_res;
323
			set_value(field, WSMOUSECFG_DY_SCALE, n);
324
		} else {
325
			errx(1, "invalid input (scaling)");
326
		}
327
		return;
328
	}
329
330
	s = val;
331
	for (i = 0; i < field->nparams; i++) {
332
		if (sscanf(s, (i > 0 ? ",%d" : "%d"), &n) != 1)
333
			break;
334
		field->params[i].value = abs(n);
335
		for (s++; *s != '\0' && *s != ','; s++) {}
336
	}
337
	if (i < field->nparams || *s != '\0')
338
		errx(1, "invalid input '%s'", val);
339
}