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