Deleted Added
sdiff udiff text old ( 109921 ) new ( 110509 )
full compact
1/*
2 * Copyright (C) 2001 Benno Rice.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef lint
27static const char rcsid[] =
28 "$FreeBSD: head/sys/dev/ofw/ofw_console.c 109921 2003-01-27 04:42:17Z jake $";
29#endif /* not lint */
30
31#include <sys/param.h>
32#include <sys/kernel.h>
33#include <sys/systm.h>
34#include <sys/types.h>
35#include <sys/conf.h>
36#include <sys/cons.h>
37#include <sys/consio.h>
38#include <sys/tty.h>
39
40#include <dev/ofw/openfirm.h>
41
42#define OFW_POLL_HZ 4
43
44static d_open_t ofw_dev_open;
45static d_close_t ofw_dev_close;
46static d_ioctl_t ofw_dev_ioctl;
47
48#define CDEV_MAJOR 97
49
50static struct cdevsw ofw_cdevsw = {
51 /* open */ ofw_dev_open,
52 /* close */ ofw_dev_close,
53 /* read */ ttyread,
54 /* write */ ttywrite,
55 /* ioctl */ ofw_dev_ioctl,
56 /* poll */ ttypoll,
57 /* mmap */ nommap,
58 /* strategy */ nostrategy,
59 /* name */ "ofw",
60 /* major */ CDEV_MAJOR,
61 /* dump */ nodump,
62 /* psize */ nopsize,
63 /* flags */ 0,
64};
65
66static struct tty *ofw_tp = NULL;
67static int polltime;
68static struct callout_handle ofw_timeouthandle
69 = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
70
71static void ofw_tty_start(struct tty *);
72static int ofw_tty_param(struct tty *, struct termios *);
73static void ofw_tty_stop(struct tty *, int);
74static void ofw_timeout(void *);
75
76static cn_probe_t ofw_cons_probe;
77static cn_init_t ofw_cons_init;
78static cn_getc_t ofw_cons_getc;
79static cn_checkc_t ofw_cons_checkc;
80static cn_putc_t ofw_cons_putc;
81
82CONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
83 ofw_cons_checkc, ofw_cons_putc, NULL);
84
85static void
86cn_drvinit(void *unused)
87{
88 phandle_t options;
89 char output[32];
90
91 if (ofw_consdev.cn_dev != NULL) {
92 if ((options = OF_finddevice("/options")) == -1 ||
93 OF_getprop(options, "output-device", output,
94 sizeof(output)) == -1)
95 return;
96 make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
97 output);
98 make_dev_alias(ofw_consdev.cn_dev, "ofwcons");
99 }
100}
101
102SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + CDEV_MAJOR, cn_drvinit, NULL)
103
104static int stdin;
105static int stdout;
106
107static int
108ofw_dev_open(dev_t dev, int flag, int mode, struct thread *td)
109{
110 struct tty *tp;
111 int unit;
112 int error, setuptimeout;
113
114 error = 0;
115 setuptimeout = 0;
116 unit = minor(dev);
117
118 tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp);
119
120 tp->t_oproc = ofw_tty_start;
121 tp->t_param = ofw_tty_param;
122 tp->t_stop = ofw_tty_stop;
123 tp->t_dev = dev;
124
125 if ((tp->t_state & TS_ISOPEN) == 0) {
126 tp->t_state |= TS_CARR_ON;
127 ttychars(tp);
128 tp->t_iflag = TTYDEF_IFLAG;
129 tp->t_oflag = TTYDEF_OFLAG;
130 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
131 tp->t_lflag = TTYDEF_LFLAG;
132 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
133 ttsetwater(tp);
134
135 setuptimeout = 1;
136 } else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
137 return (EBUSY);
138 }
139
140 error = (*linesw[tp->t_line].l_open)(dev, tp);
141
142 if (error == 0 && setuptimeout) {
143 polltime = hz / OFW_POLL_HZ;
144 if (polltime < 1) {
145 polltime = 1;
146 }
147
148 ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
149 }
150
151 return (error);
152}
153
154static int
155ofw_dev_close(dev_t dev, int flag, int mode, struct thread *td)
156{
157 int unit;
158 struct tty *tp;
159
160 unit = minor(dev);
161 tp = ofw_tp;
162
163 if (unit != 0) {
164 return (ENXIO);
165 }
166
167 (*linesw[tp->t_line].l_close)(tp, flag);
168 ttyclose(tp);
169
170 return (0);
171}
172
173static int
174ofw_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
175{
176 int unit;
177 struct tty *tp;
178 int error;
179
180 unit = minor(dev);
181 tp = ofw_tp;
182
183 if (unit != 0) {
184 return (ENXIO);
185 }
186
187 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
188 if (error != ENOIOCTL) {
189 return (error);
190 }
191
192 error = ttioctl(tp, cmd, data, flag);
193 if (error != ENOIOCTL) {
194 return (error);
195 }
196
197 return (ENOTTY);
198}
199
200static int
201ofw_tty_param(struct tty *tp, struct termios *t)
202{
203
204 return (0);
205}
206
207static void
208ofw_tty_start(struct tty *tp)
209{
210
211 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
212 ttwwakeup(tp);
213 return;
214 }
215
216 tp->t_state |= TS_BUSY;
217 while (tp->t_outq.c_cc != 0) {
218 ofw_cons_putc(tp->t_dev, getc(&tp->t_outq));
219 }
220 tp->t_state &= ~TS_BUSY;
221
222 ttwwakeup(tp);
223}
224
225static void
226ofw_tty_stop(struct tty *tp, int flag)
227{
228
229 if (tp->t_state & TS_BUSY) {
230 if ((tp->t_state & TS_TTSTOP) == 0) {
231 tp->t_state |= TS_FLUSH;
232 }
233 }
234}
235
236static void
237ofw_timeout(void *v)
238{
239 struct tty *tp;
240 int c;
241
242 tp = (struct tty *)v;
243
244 while ((c = ofw_cons_checkc(tp->t_dev)) != -1) {
245 if (tp->t_state & TS_ISOPEN) {
246 (*linesw[tp->t_line].l_rint)(c, tp);
247 }
248 }
249
250 ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
251}
252
253static void
254ofw_cons_probe(struct consdev *cp)
255{
256 int chosen;
257
258 if ((chosen = OF_finddevice("/chosen")) == -1) {
259 cp->cn_pri = CN_DEAD;
260 return;
261 }
262
263 if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
264 cp->cn_pri = CN_DEAD;
265 return;
266 }
267
268 if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
269 cp->cn_pri = CN_DEAD;
270 return;
271 }
272
273 cp->cn_dev = NULL;
274 cp->cn_pri = CN_INTERNAL;
275}
276
277static void
278ofw_cons_init(struct consdev *cp)
279{
280
281 cp->cn_dev = makedev(CDEV_MAJOR, 0);
282 cp->cn_tp = ofw_tp;
283}
284
285static int
286ofw_cons_getc(dev_t dev)
287{
288 unsigned char ch;
289 int l;
290
291 ch = '\0';
292
293 while ((l = OF_read(stdin, &ch, 1)) != 1) {
294 if (l != -2 && l != 0) {
295 return (-1);
296 }
297 }
298
299 return (ch);
300}
301
302static int
303ofw_cons_checkc(dev_t dev)
304{
305 unsigned char ch;
306
307 if (OF_read(stdin, &ch, 1) > 0) {
308 return (ch);
309 }
310
311 return (-1);
312}
313
314static void
315ofw_cons_putc(dev_t dev, int c)
316{
317 char cbuf;
318
319 if (c == '\n') {
320 cbuf = '\r';
321 OF_write(stdout, &cbuf, 1);
322 }
323
324 cbuf = c;
325 OF_write(stdout, &cbuf, 1);
326}