xref: /netbsd-src/usr.sbin/tpctl/main.c (revision e9a311137ca129332f5064d45a7e2e44418fcfb6)
1*e9a31113Sandvar /*	$NetBSD: main.c,v 1.8 2024/07/12 22:31:40 andvar Exp $	*/
2b8ce6e82Stakemura 
3b8ce6e82Stakemura /*-
4b8ce6e82Stakemura  * Copyright (c) 2002 TAKEMRUA Shin
5b8ce6e82Stakemura  * All rights reserved.
6b8ce6e82Stakemura  *
7b8ce6e82Stakemura  * Redistribution and use in source and binary forms, with or without
8b8ce6e82Stakemura  * modification, are permitted provided that the following conditions
9b8ce6e82Stakemura  * are met:
10b8ce6e82Stakemura  * 1. Redistributions of source code must retain the above copyright
11b8ce6e82Stakemura  *    notice, this list of conditions and the following disclaimer.
12b8ce6e82Stakemura  * 2. Redistributions in binary form must reproduce the above copyright
13b8ce6e82Stakemura  *    notice, this list of conditions and the following disclaimer in the
14b8ce6e82Stakemura  *    documentation and/or other materials provided with the distribution.
155d1469bdSmartin  * 3. Neither the name of The NetBSD Foundation nor the names of its
165d1469bdSmartin  *    contributors may be used to endorse or promote products derived
175d1469bdSmartin  *    from this software without specific prior written permission.
18b8ce6e82Stakemura  *
19b8ce6e82Stakemura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20b8ce6e82Stakemura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21b8ce6e82Stakemura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22b8ce6e82Stakemura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23b8ce6e82Stakemura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24b8ce6e82Stakemura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25b8ce6e82Stakemura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26b8ce6e82Stakemura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27b8ce6e82Stakemura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28b8ce6e82Stakemura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29b8ce6e82Stakemura  * POSSIBILITY OF SUCH DAMAGE.
30b8ce6e82Stakemura  */
31b8ce6e82Stakemura 
32b8ce6e82Stakemura #include <stdio.h>
33b8ce6e82Stakemura #include <strings.h>
34b8ce6e82Stakemura #include <stdlib.h>
35b8ce6e82Stakemura #include <unistd.h>
36b8ce6e82Stakemura #include <err.h>
37b8ce6e82Stakemura #include <errno.h>
38b8ce6e82Stakemura #include <time.h>
39b8ce6e82Stakemura #include <termios.h>
40b8ce6e82Stakemura #include <sys/fcntl.h>
41b8ce6e82Stakemura #include <sys/mman.h>
42b8ce6e82Stakemura #ifdef __STDC__
43b8ce6e82Stakemura #include <stdarg.h>
44b8ce6e82Stakemura #else
45b8ce6e82Stakemura #include <varargs.h>
46b8ce6e82Stakemura #endif
47b8ce6e82Stakemura 
48b8ce6e82Stakemura #include "tpctl.h"
49b8ce6e82Stakemura 
50b8ce6e82Stakemura #ifndef lint
51b8ce6e82Stakemura #include <sys/cdefs.h>
52*e9a31113Sandvar __RCSID("$NetBSD: main.c,v 1.8 2024/07/12 22:31:40 andvar Exp $");
53b8ce6e82Stakemura #endif /* not lint */
54b8ce6e82Stakemura 
5550010e74Snonaka void load_data(const char *, struct tpctl_data *);
5650010e74Snonaka void save_data(const char *, struct tpctl_data *);
5750010e74Snonaka int do_calibration(const char *, struct tp *, struct wsmouse_calibcoords *);
58b8ce6e82Stakemura void drawcross(struct fb *, int, int, int, fb_pixel_t);
59b8ce6e82Stakemura int check_esc(void *);
60b8ce6e82Stakemura 
61b8ce6e82Stakemura int opt_verbose;
62b8ce6e82Stakemura int opt_noupdate;
63b8ce6e82Stakemura int opt_forceupdate;
64b8ce6e82Stakemura 
65ed478d13Sjoerg static __dead void
usage(void)66b8ce6e82Stakemura usage(void)
67b8ce6e82Stakemura {
68b8ce6e82Stakemura 
69b8ce6e82Stakemura 	fprintf(stderr, "usage: %s [-D dispdev] [-d dev] [-f file] [-hnuv]\n",
70b8ce6e82Stakemura 	    getprogname());
71b8ce6e82Stakemura 	exit(EXIT_FAILURE);
72b8ce6e82Stakemura 	/* NOTREACHED */
73b8ce6e82Stakemura }
74b8ce6e82Stakemura 
75b8ce6e82Stakemura int
main(int argc,char * argv[])76b8ce6e82Stakemura main(int argc, char *argv[])
77b8ce6e82Stakemura {
78b8ce6e82Stakemura 	int tpfd, ch;
79b8ce6e82Stakemura 	struct tp tp;
80b8ce6e82Stakemura 	struct wsmouse_calibcoords *pref;
81b8ce6e82Stakemura 	struct tpctl_data data;
8250010e74Snonaka 	const char *data_file;
8350010e74Snonaka 	const char *dev_name;
8450010e74Snonaka 	const char *dispdev_name;
85b8ce6e82Stakemura 
86b8ce6e82Stakemura 	/* set default values */
87b8ce6e82Stakemura 	opt_verbose = 0;
88b8ce6e82Stakemura 	opt_noupdate = 0;
89b8ce6e82Stakemura 	opt_forceupdate = 0;
90b8ce6e82Stakemura 	dev_name = TPCTL_TP_DEVICE;
91b8ce6e82Stakemura 	dispdev_name = TPCTL_FB_DEVICE;
92b8ce6e82Stakemura 	data_file = TPCTL_DB_FILENAME;
93b8ce6e82Stakemura 
94b8ce6e82Stakemura 	/* parse command line */
95b8ce6e82Stakemura 	while ((ch = getopt(argc, argv, "d:D:f:hnuv")) != -1) {
96b8ce6e82Stakemura 		switch (ch) {
97b8ce6e82Stakemura 		case 'D':
98b8ce6e82Stakemura 			dispdev_name = optarg;
99b8ce6e82Stakemura 			break;
100b8ce6e82Stakemura 		case 'd':
101b8ce6e82Stakemura 			dev_name = optarg;
102b8ce6e82Stakemura 			break;
103b8ce6e82Stakemura 		case 'f':
104b8ce6e82Stakemura 			data_file = optarg;
105b8ce6e82Stakemura 			break;
106b8ce6e82Stakemura 		case 'h':
107b8ce6e82Stakemura 			usage();
108b8ce6e82Stakemura 			/* NOTREACHED */
109b8ce6e82Stakemura 		case 'n':
110b8ce6e82Stakemura 			opt_noupdate = 1;
111b8ce6e82Stakemura 			break;
112b8ce6e82Stakemura 		case 'u':
113b8ce6e82Stakemura 			opt_forceupdate = 1;
114b8ce6e82Stakemura 			break;
115b8ce6e82Stakemura 		case 'v':
116b8ce6e82Stakemura 			opt_verbose = 1;
117b8ce6e82Stakemura 			break;
118b8ce6e82Stakemura 		default:
119b8ce6e82Stakemura 			usage();
120b8ce6e82Stakemura 			/* NOTREACHED */
121b8ce6e82Stakemura 		}
122b8ce6e82Stakemura 	}
123b8ce6e82Stakemura 	if (argv[optind] != NULL) {
124b8ce6e82Stakemura 		usage();
125b8ce6e82Stakemura 		/* NOTREACHED */
126b8ce6e82Stakemura 	}
127b8ce6e82Stakemura 
128*e9a31113Sandvar 	/* load calibration parameters from specified file */
129b8ce6e82Stakemura 	load_data(data_file, &data);
130b8ce6e82Stakemura 
131b8ce6e82Stakemura 	/* open touch panel device and initialize touch panel routines */
132b8ce6e82Stakemura 	if ((tpfd = open(dev_name, O_RDWR)) < 0)
133b8ce6e82Stakemura 		errx(EXIT_FAILURE, "can't open touch panel");
134b8ce6e82Stakemura 	if (tp_init(&tp, tpfd) < 0)
135b8ce6e82Stakemura 		errx(EXIT_FAILURE, "can't initialize touch panel");
136b8ce6e82Stakemura 
137b8ce6e82Stakemura 	/* find out saved parameters for the touch panel */
138b8ce6e82Stakemura 	pref = search_data(&data, tp.id);
139b8ce6e82Stakemura 	if (opt_forceupdate || pref == NULL) {
140b8ce6e82Stakemura 		/* if the parameters wasn't found or '-f' options was
141*e9a31113Sandvar 		   specified, do 'calibration' */
142b8ce6e82Stakemura 		struct wsmouse_calibcoords coords;
143b8ce6e82Stakemura 
144b8ce6e82Stakemura 		/* draw cursors and collect samples */
145b8ce6e82Stakemura 		if (do_calibration(dispdev_name, &tp, &coords) < 0) {
146b8ce6e82Stakemura 			/* ESC key was pressed to abort */
147b8ce6e82Stakemura 			exit(EXIT_FAILURE);
148b8ce6e82Stakemura 		}
149b8ce6e82Stakemura 		/* update parameters with new one */
150b8ce6e82Stakemura 		replace_data(&data, tp.id, &coords);
151b8ce6e82Stakemura 		pref = search_data(&data, tp.id);
152b8ce6e82Stakemura 	} else {
153b8ce6e82Stakemura 		/* nothing is updated,
154b8ce6e82Stakemura 		   so you don't have to write back the data */
155b8ce6e82Stakemura 		opt_noupdate = 1;
156b8ce6e82Stakemura 	}
157b8ce6e82Stakemura 
158b8ce6e82Stakemura 	if (opt_verbose)
159b8ce6e82Stakemura 		write_coords(stdout, tp.id, pref);
160b8ce6e82Stakemura 
161b8ce6e82Stakemura 	/* set calibration parameters into touch panel device */
162b8ce6e82Stakemura 	if (tp_setcalibcoords(&tp, pref) < 0)
163b8ce6e82Stakemura 		errx(EXIT_FAILURE, "can't set samples");
164b8ce6e82Stakemura 
165*e9a31113Sandvar 	/* save calibration parameters from specified file */
166b8ce6e82Stakemura 	if (!opt_noupdate)
167b8ce6e82Stakemura 		save_data(data_file, &data);
168b8ce6e82Stakemura 	/* dispose data */
169b8ce6e82Stakemura 	free_data(&data);
170b8ce6e82Stakemura 
171b8ce6e82Stakemura 	exit(EXIT_SUCCESS);
172b8ce6e82Stakemura 	/* NOTREACHED */
173b8ce6e82Stakemura }
174b8ce6e82Stakemura 
175b8ce6e82Stakemura /*
176*e9a31113Sandvar  * load calibration parameters from specified file
177b8ce6e82Stakemura  *
178b8ce6e82Stakemura  * return:	none (it won't return if some error occurs)
179b8ce6e82Stakemura  */
180b8ce6e82Stakemura void
load_data(const char * data_file,struct tpctl_data * data)18150010e74Snonaka load_data(const char *data_file, struct tpctl_data *data)
182b8ce6e82Stakemura {
18350010e74Snonaka 	int error;
184b8ce6e82Stakemura 
185b8ce6e82Stakemura 	init_data(data);
18650010e74Snonaka 	error = read_data(data_file, data);
18750010e74Snonaka 	switch (error) {
188b8ce6e82Stakemura 	case ERR_NONE:
189b8ce6e82Stakemura 		break;
190b8ce6e82Stakemura 	case ERR_NOFILE:
191b8ce6e82Stakemura 		fprintf(stderr, "%s: can't open %s\n", getprogname(),
192b8ce6e82Stakemura 		    data_file);
193b8ce6e82Stakemura 		/* it might be OK... */
194b8ce6e82Stakemura 		break;
195b8ce6e82Stakemura 	case ERR_IO:
196b8ce6e82Stakemura 		fprintf(stderr, "%s: I/O error on %s\n", getprogname(),
197b8ce6e82Stakemura 		    data_file);
198b8ce6e82Stakemura 		exit(EXIT_FAILURE);
199b8ce6e82Stakemura 		break;
200b8ce6e82Stakemura 	case ERR_SYNTAX:
201b8ce6e82Stakemura 		fprintf(stderr, "%s: format error at %s, line %d\n",
202b8ce6e82Stakemura 		    getprogname(), data_file, data->lineno);
203b8ce6e82Stakemura 		exit(EXIT_FAILURE);
204b8ce6e82Stakemura 		break;
205b8ce6e82Stakemura 	case ERR_DUPNAME:
206b8ce6e82Stakemura 		fprintf(stderr, "%s: duplicate entry at %s, line %d\n",
207b8ce6e82Stakemura 		    getprogname(), data_file, data->lineno);
208b8ce6e82Stakemura 		exit(EXIT_FAILURE);
209b8ce6e82Stakemura 		break;
210b8ce6e82Stakemura 	default:
211b8ce6e82Stakemura 		fprintf(stderr, "%s: internal error\n", getprogname());
212b8ce6e82Stakemura 		exit(EXIT_FAILURE);
213b8ce6e82Stakemura 		break;
214b8ce6e82Stakemura 	}
215b8ce6e82Stakemura }
216b8ce6e82Stakemura 
217b8ce6e82Stakemura /*
218*e9a31113Sandvar  * save calibration parameters to specified file
219b8ce6e82Stakemura  *
220b8ce6e82Stakemura  * return:	none (it won't return if some error occurs)
221b8ce6e82Stakemura  */
222b8ce6e82Stakemura void
save_data(const char * data_file,struct tpctl_data * data)22350010e74Snonaka save_data(const char *data_file, struct tpctl_data *data)
224b8ce6e82Stakemura {
22550010e74Snonaka 	int error;
226b8ce6e82Stakemura 
22750010e74Snonaka 	error = write_data(data_file, data);
22850010e74Snonaka 	switch (error) {
229b8ce6e82Stakemura 	case ERR_NONE:
230b8ce6e82Stakemura 		break;
231b8ce6e82Stakemura 	case ERR_NOFILE:
232b8ce6e82Stakemura 		fprintf(stderr, "%s: can't open %s\n", getprogname(),
233b8ce6e82Stakemura 		    data_file);
234b8ce6e82Stakemura 		exit(EXIT_FAILURE);
235b8ce6e82Stakemura 		break;
236b8ce6e82Stakemura 	case ERR_IO:
237b8ce6e82Stakemura 		fprintf(stderr, "%s: I/O error on %s\n", getprogname(),
238b8ce6e82Stakemura 		    data_file);
239b8ce6e82Stakemura 		exit(EXIT_FAILURE);
240b8ce6e82Stakemura 		break;
241b8ce6e82Stakemura 	default:
242b8ce6e82Stakemura 		fprintf(stderr, "%s: internal error\n", getprogname());
243b8ce6e82Stakemura 		exit(EXIT_FAILURE);
244b8ce6e82Stakemura 		break;
245b8ce6e82Stakemura 	}
246b8ce6e82Stakemura }
247b8ce6e82Stakemura 
248b8ce6e82Stakemura /*
249b8ce6e82Stakemura  * draw cursors on frame buffer and collect samples in
250b8ce6e82Stakemura  * wamouse_calibcoords structure.
251b8ce6e82Stakemura  *
252b8ce6e82Stakemura  * return:	0	succeeded
253b8ce6e82Stakemura  *		-1	aborted by user (ESC key was pressed)
254b8ce6e82Stakemura  *		(it won't return if some error occurs)
255b8ce6e82Stakemura  */
256b8ce6e82Stakemura int
do_calibration(const char * dev,struct tp * tp,struct wsmouse_calibcoords * coords)25750010e74Snonaka do_calibration(const char *dev, struct tp *tp,
25850010e74Snonaka     struct wsmouse_calibcoords *coords)
259b8ce6e82Stakemura {
260b8ce6e82Stakemura 	int fbfd;
261b8ce6e82Stakemura 	struct fb fb;
26250010e74Snonaka 	int i, x, y, xm, ym, cursize, error, res;
263b8ce6e82Stakemura 
264b8ce6e82Stakemura 	/* open frame buffer device and initialize frame buffer routine */
265b8ce6e82Stakemura 	if ((fbfd = open(dev, O_RDWR)) < 0)
266b8ce6e82Stakemura 		errx(EXIT_FAILURE, "can't open frame buffer");
267b8ce6e82Stakemura 	if (fb_init(&fb, fbfd) < 0)
268b8ce6e82Stakemura 		errx(EXIT_FAILURE, "can't map frame buffer");
269b8ce6e82Stakemura 
270b8ce6e82Stakemura 	memset(coords, 0, sizeof(*coords));
271b8ce6e82Stakemura 	coords->minx = 0;
272b8ce6e82Stakemura 	coords->miny = 0;
273b8ce6e82Stakemura 	coords->maxx = fb.conf.hf_width - 1;
274b8ce6e82Stakemura 	coords->maxy = fb.conf.hf_height - 1;
275b8ce6e82Stakemura 	coords->samplelen = 5;
276b8ce6e82Stakemura 
277b8ce6e82Stakemura 	cursize = 20;
278b8ce6e82Stakemura 	xm = fb.conf.hf_width/10;
279b8ce6e82Stakemura 	ym = fb.conf.hf_height/10;
280b8ce6e82Stakemura 
281b8ce6e82Stakemura 	/* center */
282b8ce6e82Stakemura 	coords->samples[0].x = fb.conf.hf_width/2;
283b8ce6e82Stakemura 	coords->samples[0].y = fb.conf.hf_height/2;
284b8ce6e82Stakemura 
285b8ce6e82Stakemura 	/* top left */
286b8ce6e82Stakemura 	coords->samples[1].x = xm;
287b8ce6e82Stakemura 	coords->samples[1].y = ym;
288b8ce6e82Stakemura 
289b8ce6e82Stakemura 	/* bottom left */
290b8ce6e82Stakemura 	coords->samples[2].x = xm;
291b8ce6e82Stakemura 	coords->samples[2].y = fb.conf.hf_height - ym;
292b8ce6e82Stakemura 
293b8ce6e82Stakemura 	/* bottom right */
294b8ce6e82Stakemura 	coords->samples[3].x = fb.conf.hf_width - xm;
295b8ce6e82Stakemura 	coords->samples[3].y = fb.conf.hf_height - ym;
296b8ce6e82Stakemura 
297b8ce6e82Stakemura 	/* top right */
298b8ce6e82Stakemura 	coords->samples[4].x = fb.conf.hf_width - xm;
299b8ce6e82Stakemura 	coords->samples[4].y = ym;
300b8ce6e82Stakemura 
301b8ce6e82Stakemura 	tp_setrawmode(tp);
30250010e74Snonaka 	error = 0;
303b8ce6e82Stakemura 	for (i = 0; i < coords->samplelen; i++) {
304b8ce6e82Stakemura 		drawcross(&fb,
305b8ce6e82Stakemura 		    coords->samples[i].x,
306b8ce6e82Stakemura 		    coords->samples[i].y,
307b8ce6e82Stakemura 		    cursize, fb.white);
308b8ce6e82Stakemura 		fb_flush(&fb);
309b8ce6e82Stakemura 		tp_flush(tp);
310b8ce6e82Stakemura 		res = tp_get(tp, &x, &y, check_esc, 0 /* stdin */);
311b8ce6e82Stakemura 		if (res < 0) {
31250010e74Snonaka 			error = errno;
313b8ce6e82Stakemura 			break;
314b8ce6e82Stakemura 		}
315b8ce6e82Stakemura 		if (0 < res) {
316b8ce6e82Stakemura 			fb_dispmode(&fb, WSDISPLAYIO_MODE_EMUL);
317b8ce6e82Stakemura 			return (-1); /* aborted by user */
318b8ce6e82Stakemura 		}
319b8ce6e82Stakemura 		coords->samples[i].rawx = x;
320b8ce6e82Stakemura 		coords->samples[i].rawy = y;
321b8ce6e82Stakemura 		drawcross(&fb,
322b8ce6e82Stakemura 		    coords->samples[i].x,
323b8ce6e82Stakemura 		    coords->samples[i].y,
324b8ce6e82Stakemura 		    cursize, fb.black);
325b8ce6e82Stakemura 		fb_flush(&fb);
326b8ce6e82Stakemura 		tp_waitup(tp, 200, check_esc, 0 /* stdin */);
327b8ce6e82Stakemura 	}
328b8ce6e82Stakemura 
329b8ce6e82Stakemura 	fb_dispmode(&fb, WSDISPLAYIO_MODE_EMUL);
330b8ce6e82Stakemura 	close(fbfd);
331b8ce6e82Stakemura 
332b8ce6e82Stakemura 	if (opt_verbose) {
333b8ce6e82Stakemura 		printf("%s: %dx%d (%dbytes/line) %dbit offset=0x%lx\n",
334b8ce6e82Stakemura 		    getprogname(),
335b8ce6e82Stakemura 		    fb.conf.hf_width,
336b8ce6e82Stakemura 		    fb.conf.hf_height,
337b8ce6e82Stakemura 		    fb.conf.hf_bytes_per_line,
338b8ce6e82Stakemura 		    fb.conf.hf_pixel_width,
339b8ce6e82Stakemura 		    fb.conf.hf_offset);
340b8ce6e82Stakemura 	}
341b8ce6e82Stakemura 
34250010e74Snonaka 	if (error) {
34350010e74Snonaka 		errno = error;
344b8ce6e82Stakemura 		errx(EXIT_FAILURE, "can't get samples");
345b8ce6e82Stakemura 	}
346b8ce6e82Stakemura 
347b8ce6e82Stakemura 	return (0);
348b8ce6e82Stakemura }
349b8ce6e82Stakemura 
350b8ce6e82Stakemura /*
351d5d52b45Swiz  * draw cross cursor on frame buffer
352b8ce6e82Stakemura  *
353b8ce6e82Stakemura  * return:	none
354b8ce6e82Stakemura  */
355b8ce6e82Stakemura void
drawcross(struct fb * fb,int x,int y,int size,fb_pixel_t pixel)356b8ce6e82Stakemura drawcross(struct fb *fb, int x, int y, int size, fb_pixel_t pixel)
357b8ce6e82Stakemura {
358b8ce6e82Stakemura 	size /= 2;
359b8ce6e82Stakemura 
360b8ce6e82Stakemura 	fb_drawline(fb, x,     y - size + 1, x,     y - 1,    pixel);
361b8ce6e82Stakemura 	fb_drawline(fb, x + 1, y - size + 1, x + 1, y - 1,    pixel);
362b8ce6e82Stakemura 	fb_drawline(fb, x,     y + 2,        x,     y + size, pixel);
363b8ce6e82Stakemura 	fb_drawline(fb, x + 1, y + 2,        x + 1, y + size, pixel);
364b8ce6e82Stakemura 
365b8ce6e82Stakemura 	fb_drawline(fb, x - size + 1, y,     x - 1,    y,     pixel);
366b8ce6e82Stakemura 	fb_drawline(fb, x - size + 1, y + 1, x - 1,    y + 1, pixel);
367b8ce6e82Stakemura 	fb_drawline(fb, x + 2,        y,     x + size, y,     pixel);
368b8ce6e82Stakemura 	fb_drawline(fb, x + 2,        y + 1, x + size, y + 1, pixel);
369b8ce6e82Stakemura }
370b8ce6e82Stakemura 
371b8ce6e82Stakemura /*
372b8ce6e82Stakemura  * check ESC key
373b8ce6e82Stakemura  *
374b8ce6e82Stakemura  * date:	input file descriptor
375b8ce6e82Stakemura  *
376d5d52b45Swiz  * return:	0	nothing has occurred
377b8ce6e82Stakemura  *		1	ESC key was pressed
378b8ce6e82Stakemura  *		-1	error
379b8ce6e82Stakemura  */
380b8ce6e82Stakemura int
check_esc(void * data)381b8ce6e82Stakemura check_esc(void *data)
382b8ce6e82Stakemura {
383413e9419Schristos 	int fd = (int)(intptr_t)data;
38450010e74Snonaka 	int flg, n, error;
385b8ce6e82Stakemura 	char buf[1];
386b8ce6e82Stakemura 	struct termios tm, raw;
387b8ce6e82Stakemura 
388b8ce6e82Stakemura 	if (tcgetattr(fd, &tm) < 0)
389b8ce6e82Stakemura 		return (-1);
390b8ce6e82Stakemura 	raw = tm;
391b8ce6e82Stakemura 	cfmakeraw(&raw);
392b8ce6e82Stakemura 	if (tcsetattr(fd, TCSANOW, &raw) < 0)
393b8ce6e82Stakemura 		return (-1);
394b8ce6e82Stakemura 	if ((flg = fcntl(fd, F_GETFL)) == -1)
395b8ce6e82Stakemura 		return (-1);
396b8ce6e82Stakemura 	if (fcntl(fd, F_SETFL, flg | O_NONBLOCK) == -1)
397b8ce6e82Stakemura 		return (-1);
398b8ce6e82Stakemura 	n = read(fd, buf, 1);
39950010e74Snonaka 	error = errno;
400b8ce6e82Stakemura 	fcntl(fd, F_SETFL, flg);
401b8ce6e82Stakemura 	tcsetattr(fd, TCSANOW, &tm);
402b8ce6e82Stakemura 	if (n < 0)
40350010e74Snonaka 		return (error == EWOULDBLOCK ? 0 : -1);
404b8ce6e82Stakemura 	if (n == 0)
405b8ce6e82Stakemura 		return (0); /* EOF */
406b8ce6e82Stakemura 	if (*buf == 0x1b)
407b8ce6e82Stakemura 		return (1); /* ESC */
408b8ce6e82Stakemura 
409b8ce6e82Stakemura 	return (0);
410b8ce6e82Stakemura }
411