···11+/* $OpenBSD: mousecfg.c,v 1.1 2017/07/21 20:38:20 bru Exp $ */
22+33+/*
44+ * Copyright (c) 2017 Ulf Brosziewski
55+ *
66+ * Permission to use, copy, modify, and distribute this software for any
77+ * purpose with or without fee is hereby granted, provided that the above
88+ * copyright notice and this permission notice appear in all copies.
99+ *
1010+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1111+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1212+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1313+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1414+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1515+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1616+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1717+ */
1818+1919+/*
2020+ * Read/write wsmouse parameters for touchpad configuration.
2121+ */
2222+2323+#include <sys/ioctl.h>
2424+#include <sys/param.h>
2525+#include <dev/wscons/wsconsio.h>
2626+#include <stdio.h>
2727+#include <stdlib.h>
2828+#include <string.h>
2929+#include <err.h>
3030+#include <errno.h>
3131+#include "mousecfg.h"
3232+3333+#define BASE_FIRST WSMOUSECFG_DX_SCALE
3434+#define BASE_LAST WSMOUSECFG_Y_INV
3535+#define TP_FILTER_FIRST WSMOUSECFG_DX_MAX
3636+#define TP_FILTER_LAST WSMOUSECFG_SMOOTHING
3737+#define TP_FEATURES_FIRST WSMOUSECFG_SOFTBUTTONS
3838+#define TP_FEATURES_LAST WSMOUSECFG_TAPPING
3939+#define TP_SETUP_FIRST WSMOUSECFG_LEFT_EDGE
4040+#define TP_SETUP_LAST WSMOUSECFG_TAP_LOCKTIME
4141+4242+#define BASESIZE (BASE_LAST - BASE_FIRST + 1)
4343+4444+#define BUFSIZE (BASESIZE \
4545+ + (TP_FILTER_LAST - TP_FILTER_FIRST + 1) \
4646+ + (TP_FEATURES_LAST - TP_FEATURES_FIRST + 1) \
4747+ + (TP_SETUP_LAST - TP_SETUP_FIRST + 1))
4848+4949+static const int range[][2] = {
5050+ { BASE_FIRST, BASE_LAST },
5151+ { TP_FILTER_FIRST, TP_FILTER_LAST },
5252+ { TP_FEATURES_FIRST, TP_FEATURES_LAST },
5353+ { TP_SETUP_FIRST, TP_SETUP_LAST },
5454+};
5555+5656+static const int touchpad_types[] = {
5757+ WSMOUSE_TYPE_SYNAPTICS, /* Synaptics touchpad */
5858+ WSMOUSE_TYPE_ALPS, /* ALPS touchpad */
5959+ WSMOUSE_TYPE_ELANTECH, /* Elantech touchpad */
6060+ WSMOUSE_TYPE_SYNAP_SBTN, /* Synaptics soft buttons */
6161+};
6262+6363+struct wsmouse_parameters cfg_tapping = {
6464+ (struct wsmouse_param[]) {
6565+ { WSMOUSECFG_TAPPING, 0 }, },
6666+ 1
6767+};
6868+6969+struct wsmouse_parameters cfg_scaling = {
7070+ (struct wsmouse_param[]) {
7171+ { WSMOUSECFG_DX_SCALE, 0 },
7272+ { WSMOUSECFG_DY_SCALE, 0 } },
7373+ 2
7474+};
7575+7676+struct wsmouse_parameters cfg_swapsides = {
7777+ (struct wsmouse_param[]) {
7878+ { WSMOUSECFG_SWAPSIDES, 0 }, },
7979+ 1
8080+};
8181+8282+struct wsmouse_parameters cfg_disable = {
8383+ (struct wsmouse_param[]) {
8484+ { WSMOUSECFG_DISABLE, 0 }, },
8585+ 1
8686+};
8787+8888+struct wsmouse_parameters cfg_param = {
8989+ (struct wsmouse_param[]) {
9090+ { -1, 0 },
9191+ { -1, 0 },
9292+ { -1, 0 },
9393+ { -1, 0 } },
9494+ 4
9595+};
9696+9797+static int cfg_horiz_res;
9898+static int cfg_vert_res;
9999+static struct wsmouse_param cfg_buffer[BUFSIZE];
100100+101101+102102+int
103103+mousecfg_init(int dev_fd, const char **errstr)
104104+{
105105+ struct wsmouse_calibcoords coords;
106106+ struct wsmouse_parameters parameters;
107107+ struct wsmouse_param *param;
108108+ enum wsmousecfg k;
109109+ int i, err, type;
110110+111111+ *errstr = NULL;
112112+113113+ if ((err = ioctl(dev_fd, WSMOUSEIO_GTYPE, &type))) {
114114+ *errstr = "WSMOUSEIO_GTYPE";
115115+ return err;
116116+ }
117117+ for (i = 0; i < nitems(touchpad_types)
118118+ && type != touchpad_types[i]; i++) {}
119119+120120+ /*
121121+ * If the device is not a touchpad, return an error without
122122+ * setting the error string. The caller shouldn't print a
123123+ * warning in this case.
124124+ */
125125+ if (i == nitems(touchpad_types))
126126+ return (-1);
127127+128128+ if ((err = ioctl(dev_fd, WSMOUSEIO_GCALIBCOORDS, &coords))) {
129129+ *errstr = "WSMOUSEIO_GCALIBCOORDS";
130130+ return err;
131131+ }
132132+ cfg_horiz_res = coords.resx;
133133+ cfg_vert_res = coords.resy;
134134+135135+ param = cfg_buffer;
136136+ for (i = 0; i < nitems(range); i++)
137137+ for (k = range[i][0]; k <= range[i][1]; k++, param++) {
138138+ param->key = k;
139139+ param->value = 0;
140140+ }
141141+142142+ /*
143143+ * Not all touchpad drivers configure wsmouse for compat mode yet.
144144+ * In those cases the first ioctl call may be successful but the
145145+ * second one will fail because it includes wstpad parameters:
146146+ */
147147+ parameters.params = cfg_buffer;
148148+ parameters.nparams = BASESIZE;
149149+ if ((err = ioctl(dev_fd, WSMOUSEIO_GETPARAMS, ¶meters))) {
150150+ *errstr = "WSMOUSEIO_GETPARAMS";
151151+ return (err);
152152+ }
153153+ parameters.params = cfg_buffer + BASESIZE;
154154+ parameters.nparams = BUFSIZE - BASESIZE;
155155+ if ((err = ioctl(dev_fd, WSMOUSEIO_GETPARAMS, ¶meters))) {
156156+ if (err != EINVAL)
157157+ *errstr = "WSMOUSEIO_GETPARAMS";
158158+ return (err);
159159+ }
160160+161161+ return (0);
162162+}
163163+164164+/* Map a key to its buffer index. */
165165+static int
166166+index_of(enum wsmousecfg key)
167167+{
168168+ int i, n;
169169+170170+ for (i = 0, n = 0; i < nitems(range); i++)
171171+ if (key <= range[i][1] && key >= range[i][0])
172172+ return (key - range[i][0] + n);
173173+ else
174174+ n += range[i][1] - range[i][0] + 1;
175175+176176+ return (-1);
177177+}
178178+179179+int
180180+mousecfg_get_field(struct wsmouse_parameters *field)
181181+{
182182+ int i, n;
183183+184184+ for (i = 0; i < field->nparams; i++) {
185185+ if ((n = index_of(field->params[i].key)) >= 0)
186186+ field->params[i].value = cfg_buffer[n].value;
187187+ else
188188+ return (-1);
189189+ }
190190+ return (0);
191191+}
192192+193193+int
194194+mousecfg_put_field(int fd, struct wsmouse_parameters *field)
195195+{
196196+ int i, n, d, err;
197197+198198+ d = 0;
199199+ for (i = 0; i < field->nparams; i++)
200200+ if ((n = index_of(field->params[i].key)) < 0)
201201+ return (-1);
202202+ else
203203+ d |= (cfg_buffer[n].value != field->params[i].value);
204204+205205+ if (!d)
206206+ return (0);
207207+208208+ /* Write and read back immediately, wsmouse may normalize values. */
209209+ if ((err = ioctl(fd, WSMOUSEIO_SETPARAMS, field))
210210+ || (err = ioctl(fd, WSMOUSEIO_GETPARAMS, field)))
211211+ return err;
212212+213213+ for (i = 0; i < field->nparams; i++)
214214+ cfg_buffer[n].value = field->params[i].value;
215215+216216+ return (0);
217217+}
218218+219219+static int
220220+get_value(struct wsmouse_parameters *field, enum wsmousecfg key)
221221+{
222222+ int i;
223223+224224+ for (i = 0; i < field->nparams && key != field->params[i].key; i++) {}
225225+226226+ return (i < field->nparams ? field->params[i].value : 0);
227227+}
228228+229229+static void
230230+set_value(struct wsmouse_parameters *field, enum wsmousecfg key, int value)
231231+{
232232+ int i;
233233+234234+ for (i = 0; i < field->nparams && key != field->params[i].key; i++) {}
235235+236236+ field->params[i].value = (i < field->nparams ? value : 0);
237237+}
238238+239239+/*
240240+ * Read or write up to four raw parameter values. In this case
241241+ * reading is a 'put' operation that writes back a value from the
242242+ * buffer.
243243+ */
244244+static int
245245+read_param(struct wsmouse_parameters *field, char *val)
246246+{
247247+ int i, j, n;
248248+249249+ n = sscanf(val, "%d:%d,%d:%d,%d:%d,%d:%d",
250250+ &field->params[0].key, &field->params[0].value,
251251+ &field->params[1].key, &field->params[1].value,
252252+ &field->params[2].key, &field->params[2].value,
253253+ &field->params[3].key, &field->params[3].value);
254254+ if (n > 0 && (n & 1) == 0) {
255255+ n /= 2;
256256+ for (i = 0; i < n; i++) {
257257+ if (index_of(field->params[i].key) < 0)
258258+ return (-1);
259259+ }
260260+ field->nparams = n;
261261+ return (0);
262262+ }
263263+ n = sscanf(val, "%d,%d,%d,%d",
264264+ &field->params[0].key, &field->params[1].key,
265265+ &field->params[2].key, &field->params[3].key);
266266+ if (n > 0) {
267267+ for (i = 0; i < n; i++) {
268268+ if ((j = index_of(field->params[i].key)) < 0)
269269+ return (-1);
270270+ field->params[i].value = cfg_buffer[j].value;
271271+ }
272272+ field->nparams = n;
273273+ return (0);
274274+ }
275275+ return (-1);
276276+}
277277+278278+void
279279+mousecfg_pr_field(struct wsmouse_parameters *field)
280280+{
281281+ int i, value;
282282+ float f;
283283+284284+ if (field == &cfg_param) {
285285+ for (i = 0; i < field->nparams; i++)
286286+ printf(i > 0 ? ",%d:%d" : "%d:%d",
287287+ field->params[i].key,
288288+ field->params[i].value);
289289+ return;
290290+ }
291291+292292+ if (field == &cfg_scaling) {
293293+ value = get_value(field, WSMOUSECFG_DX_SCALE);
294294+ f = (float) value / 4096;
295295+ printf("%.3f", f);
296296+ return;
297297+ }
298298+299299+ for (i = 0; i < field->nparams; i++)
300300+ printf(i > 0 ? ",%d" : "%d", field->params[i].value);
301301+}
302302+303303+void
304304+mousecfg_rd_field(struct wsmouse_parameters *field, char *val)
305305+{
306306+ enum wsmousecfg first = field->params[0].key;
307307+ int i, n;
308308+ const char *s;
309309+ float f;
310310+311311+ if (field == &cfg_param) {
312312+ if (read_param(field, val))
313313+ errx(1, "invalid input (param)");
314314+ return;
315315+ }
316316+317317+ if (field == &cfg_scaling) {
318318+ if (sscanf(val, "%f", &f) == 1) {
319319+ n = (int) (f * 4096);
320320+ set_value(field, WSMOUSECFG_DX_SCALE, n);
321321+ if (cfg_horiz_res && cfg_vert_res)
322322+ n = n * cfg_horiz_res / cfg_vert_res;
323323+ set_value(field, WSMOUSECFG_DY_SCALE, n);
324324+ } else {
325325+ errx(1, "invalid input (scaling)");
326326+ }
327327+ return;
328328+ }
329329+330330+ s = val;
331331+ for (i = 0; i < field->nparams; i++) {
332332+ if (sscanf(s, (i > 0 ? ",%d" : "%d"), &n) != 1)
333333+ break;
334334+ field->params[i].value = abs(n);
335335+ for (s++; *s != '\0' && *s != ','; s++) {}
336336+ }
337337+ if (i < field->nparams || *s != '\0')
338338+ errx(1, "invalid input '%s'", val);
339339+}
+29
sbin/wsconsctl/mousecfg.h
···11+/* $OpenBSD: mousecfg.h,v 1.1 2017/07/21 20:38:20 bru Exp $ */
22+33+/*
44+ * Copyright (c) 2017 Ulf Brosziewski
55+ *
66+ * Permission to use, copy, modify, and distribute this software for any
77+ * purpose with or without fee is hereby granted, provided that the above
88+ * copyright notice and this permission notice appear in all copies.
99+ *
1010+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1111+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1212+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1313+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1414+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1515+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1616+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1717+ */
1818+1919+extern struct wsmouse_parameters cfg_tapping;
2020+extern struct wsmouse_parameters cfg_scaling;
2121+extern struct wsmouse_parameters cfg_swapsides;
2222+extern struct wsmouse_parameters cfg_disable;
2323+extern struct wsmouse_parameters cfg_param;
2424+2525+int mousecfg_init(int, const char **);
2626+int mousecfg_get_field(struct wsmouse_parameters *);
2727+int mousecfg_put_field(int, struct wsmouse_parameters *);
2828+void mousecfg_pr_field(struct wsmouse_parameters *);
2929+void mousecfg_rd_field(struct wsmouse_parameters *, char *);