1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 2009 NONAKA Kimihiro <nonaka@netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "boot.h"
29#include "bootinfo.h"
30#include "unixdev.h"
31
32#include "compat_linux.h"
33#include "termios.h"
34
35struct btinfo_console bi_cons;
36
37static int iodev = CONSDEV_GLASS;
38static int infd = 0;
39static int outfd = 1;
40
41static const char *comdevname[] = {
42	"/dev/ttyS0",
43};
44
45static void common_putc(int fd, int c);
46static int common_getc(int fd, int timo);
47
48void
49consinit(int dev, int speed)
50{
51	struct linux_termios termios;
52	int fd;
53
54	switch (dev) {
55	case CONSDEV_COM0:
56		iodev = dev;
57		break;
58
59	case CONSDEV_GLASS:
60	default:
61 glass_console:
62		iodev = CONSDEV_GLASS;
63		break;
64	}
65
66	if (infd >= 0 && infd == outfd) {
67		uclose(infd);
68		infd = 0;
69		outfd = 1;
70	}
71
72	if (iodev == CONSDEV_GLASS) {
73		infd = 0;
74		outfd = 1;
75
76		strlcpy(bi_cons.devname, "glass", sizeof(bi_cons.devname));
77		bi_cons.addr = -1;
78		bi_cons.speed = -1;
79	} else {
80		fd = uopen(comdevname[iodev - CONSDEV_COM0], LINUX_O_RDWR);
81		if (fd < 0)
82			goto glass_console;
83		infd = outfd = fd;
84
85		/* set speed */
86		linux_tcgetattr(fd, &termios);
87		if (linux_cfsetspeed(&termios, speed) < 0) {
88			speed = 9600;
89			if (linux_cfsetspeed(&termios, speed) < 0)
90				goto glass_console;
91		}
92		if (linux_tcsetattr(fd, LINUX_TCSETS, &termios) < 0)
93			goto glass_console;
94
95		snprintf(bi_cons.devname, sizeof(bi_cons.devname), "com%d",
96		    iodev - CONSDEV_COM0);
97		bi_cons.addr = -1;
98		bi_cons.speed = speed;
99	}
100	BI_ADD(&bi_cons, BTINFO_CONSDEV, sizeof(bi_cons));
101}
102
103void
104putchar(int c)
105{
106
107	common_putc(outfd, c);
108}
109
110int
111getchar(void)
112{
113
114	return common_getc(infd, 1);
115}
116
117static void
118common_putc(int fd, int c)
119{
120
121	(void)uwrite(fd, &c, 1);
122}
123
124static int
125common_getc(int fd, int timo)
126{
127	struct linux_timeval tv;
128	fd_set fdset;
129	int nfds, n;
130	char c;
131
132	for (; timo < 0 || timo > 0; --timo) {
133		tv.tv_sec = 1;
134		tv.tv_usec = 0;
135		FD_ZERO(&fdset);
136
137		nfds = 1;
138		FD_SET(fd, &fdset);
139
140		n = uselect(nfds, &fdset, NULL, NULL, &tv);
141		if (n > 0)
142			break;
143	}
144
145	if (timo > 0) {
146		for (fd = 0; fd < nfds; fd++) {
147			if (FD_ISSET(fd, &fdset)) {
148				return (uread(fd, &c, 1) < 1 ? -1 : c);
149			}
150		}
151	}
152	return -1;
153}
154
155int
156awaitkey(int timeout, int tell)
157{
158	struct linux_termios orig_termios, raw_termios;
159	int c = 0;
160	int i;
161
162	/* set raw mode */
163	linux_tcgetattr(infd, &orig_termios);
164	raw_termios = orig_termios;
165	linux_cfmakeraw(&raw_termios);
166	linux_tcsetattr(infd, LINUX_TCSETS, &raw_termios);
167
168	for (i = timeout; i > 0; i--) {
169		if (tell) {
170			char numbuf[20];
171			int len, j;
172
173			sprintf(numbuf, "%d ", i);
174			len = strlen(numbuf);
175			for (j = 0; j < len; j++)
176				numbuf[len + j] = '\b';
177			numbuf[len + j] = '\0';
178			printf(numbuf);
179		}
180		c = common_getc(infd, 1);
181		if (c == 0)
182			c = -1;
183		if (c >= 0)
184			break;
185	}
186	if (i == 0)
187		c = '\0';
188
189	/* set original mode */
190	linux_tcsetattr(infd, LINUX_TCSETS, &orig_termios);
191
192	if (tell)
193		printf("0 \n");
194
195	return c;
196}
197
198void dummycall2(void);
199void
200dummycall2(void)
201{
202
203	(void)linux_termio_to_bsd_termios;
204	(void)bsd_termios_to_linux_termio;
205	(void)linux_termios_to_bsd_termios;
206	(void)bsd_termios_to_linux_termios;
207}
208