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