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