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 110509 2003-02-07 16:20:09Z harti $";
29#endif /* not lint */
30
31#include "opt_ddb.h"
32#include "opt_comconsole.h"
33
34#include <sys/param.h>
35#include <sys/kernel.h>
36#include <sys/systm.h>
37#include <sys/types.h>
38#include <sys/conf.h>
39#include <sys/cons.h>
40#include <sys/consio.h>
41#include <sys/tty.h>
42
43#include <dev/ofw/openfirm.h>
44
45#include <ddb/ddb.h>
46
47#define OFW_POLL_HZ 4
48
49static d_open_t ofw_dev_open;
50static d_close_t ofw_dev_close;
51static d_ioctl_t ofw_dev_ioctl;
52
53#define CDEV_MAJOR 97
54
55static struct cdevsw ofw_cdevsw = {
56 /* open */ ofw_dev_open,
57 /* close */ ofw_dev_close,
58 /* read */ ttyread,
59 /* write */ ttywrite,
60 /* ioctl */ ofw_dev_ioctl,
61 /* poll */ ttypoll,
62 /* mmap */ nommap,
63 /* strategy */ nostrategy,
64 /* name */ "ofw",
65 /* major */ CDEV_MAJOR,
66 /* dump */ nodump,
67 /* psize */ nopsize,
68 /* flags */ 0,
69};
70
71static struct tty *ofw_tp = NULL;
72static int polltime;
73static struct callout_handle ofw_timeouthandle
74 = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
75
76#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
77static int alt_break_state;
78#endif
79
80static void ofw_tty_start(struct tty *);
81static int ofw_tty_param(struct tty *, struct termios *);
82static void ofw_tty_stop(struct tty *, int);
83static void ofw_timeout(void *);
84
85static cn_probe_t ofw_cons_probe;
86static cn_init_t ofw_cons_init;
87static cn_getc_t ofw_cons_getc;
88static cn_checkc_t ofw_cons_checkc;
89static cn_putc_t ofw_cons_putc;
90
91CONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
92 ofw_cons_checkc, ofw_cons_putc, NULL);
93
94static void
95cn_drvinit(void *unused)
96{
97 phandle_t options;
98 char output[32];
99
100 if (ofw_consdev.cn_dev != NULL) {
101 if ((options = OF_finddevice("/options")) == -1 ||
102 OF_getprop(options, "output-device", output,
103 sizeof(output)) == -1)
104 return;
105 make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
106 output);
107 make_dev_alias(ofw_consdev.cn_dev, "ofwcons");
108 }
109}
110
111SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + CDEV_MAJOR, cn_drvinit, NULL)
112
113static int stdin;
114static int stdout;
115
116static int
117ofw_dev_open(dev_t dev, int flag, int mode, struct thread *td)
118{
119 struct tty *tp;
120 int unit;
121 int error, setuptimeout;
122
123 error = 0;
124 setuptimeout = 0;
125 unit = minor(dev);
126
127 tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp);
128
129 tp->t_oproc = ofw_tty_start;
130 tp->t_param = ofw_tty_param;
131 tp->t_stop = ofw_tty_stop;
132 tp->t_dev = dev;
133
134 if ((tp->t_state & TS_ISOPEN) == 0) {
135 tp->t_state |= TS_CARR_ON;
136 ttychars(tp);
137 tp->t_iflag = TTYDEF_IFLAG;
138 tp->t_oflag = TTYDEF_OFLAG;
139 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
140 tp->t_lflag = TTYDEF_LFLAG;
141 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
142 ttsetwater(tp);
143
144 setuptimeout = 1;
145 } else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
146 return (EBUSY);
147 }
148
149 error = (*linesw[tp->t_line].l_open)(dev, tp);
150
151 if (error == 0 && setuptimeout) {
152 polltime = hz / OFW_POLL_HZ;
153 if (polltime < 1) {
154 polltime = 1;
155 }
156
157 ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
158 }
159
160 return (error);
161}
162
163static int
164ofw_dev_close(dev_t dev, int flag, int mode, struct thread *td)
165{
166 int unit;
167 struct tty *tp;
168
169 unit = minor(dev);
170 tp = ofw_tp;
171
172 if (unit != 0) {
173 return (ENXIO);
174 }
175
176 (*linesw[tp->t_line].l_close)(tp, flag);
177 ttyclose(tp);
178
179 return (0);
180}
181
182static int
183ofw_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
184{
185 int unit;
186 struct tty *tp;
187 int error;
188
189 unit = minor(dev);
190 tp = ofw_tp;
191
192 if (unit != 0) {
193 return (ENXIO);
194 }
195
196 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
197 if (error != ENOIOCTL) {
198 return (error);
199 }
200
201 error = ttioctl(tp, cmd, data, flag);
202 if (error != ENOIOCTL) {
203 return (error);
204 }
205
206 return (ENOTTY);
207}
208
209static int
210ofw_tty_param(struct tty *tp, struct termios *t)
211{
212
213 return (0);
214}
215
216static void
217ofw_tty_start(struct tty *tp)
218{
219
220 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
221 ttwwakeup(tp);
222 return;
223 }
224
225 tp->t_state |= TS_BUSY;
226 while (tp->t_outq.c_cc != 0) {
227 ofw_cons_putc(tp->t_dev, getc(&tp->t_outq));
228 }
229 tp->t_state &= ~TS_BUSY;
230
231 ttwwakeup(tp);
232}
233
234static void
235ofw_tty_stop(struct tty *tp, int flag)
236{
237
238 if (tp->t_state & TS_BUSY) {
239 if ((tp->t_state & TS_TTSTOP) == 0) {
240 tp->t_state |= TS_FLUSH;
241 }
242 }
243}
244
245static void
246ofw_timeout(void *v)
247{
248 struct tty *tp;
249 int c;
250
251 tp = (struct tty *)v;
252
253 while ((c = ofw_cons_checkc(tp->t_dev)) != -1) {
254 if (tp->t_state & TS_ISOPEN) {
255 (*linesw[tp->t_line].l_rint)(c, tp);
256 }
257 }
258
259 ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
260}
261
262static void
263ofw_cons_probe(struct consdev *cp)
264{
265 int chosen;
266
267 if ((chosen = OF_finddevice("/chosen")) == -1) {
268 cp->cn_pri = CN_DEAD;
269 return;
270 }
271
272 if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
273 cp->cn_pri = CN_DEAD;
274 return;
275 }
276
277 if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
278 cp->cn_pri = CN_DEAD;
279 return;
280 }
281
282 cp->cn_dev = NULL;
283 cp->cn_pri = CN_INTERNAL;
284}
285
286static void
287ofw_cons_init(struct consdev *cp)
288{
289
290 cp->cn_dev = makedev(CDEV_MAJOR, 0);
291 cp->cn_tp = ofw_tp;
292}
293
294static int
295ofw_cons_getc(dev_t dev)
296{
297 unsigned char ch;
298 int l;
299
300 ch = '\0';
301
302 while ((l = OF_read(stdin, &ch, 1)) != 1) {
303 if (l != -2 && l != 0) {
304 return (-1);
305 }
306 }
307
308#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
309 if (db_alt_break(ch, &alt_break_state))
310 breakpoint();
311#endif
312
313 return (ch);
314}
315
316static int
317ofw_cons_checkc(dev_t dev)
318{
319 unsigned char ch;
320
321 if (OF_read(stdin, &ch, 1) > 0) {
322#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
323 if (db_alt_break(ch, &alt_break_state))
324 breakpoint();
325#endif
326 return (ch);
327 }
328
329 return (-1);
330}
331
332static void
333ofw_cons_putc(dev_t dev, int c)
334{
335 char cbuf;
336
337 if (c == '\n') {
338 cbuf = '\r';
339 OF_write(stdout, &cbuf, 1);
340 }
341
342 cbuf = c;
343 OF_write(stdout, &cbuf, 1);
344}