romcons.c revision 1.1 1 /* $NetBSD: romcons.c,v 1.1 2011/11/20 15:38:00 tsutsui Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 /*
34 * romcons.c - from sys/dev/ofw/ofcons.c
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: romcons.c,v 1.1 2011/11/20 15:38:00 tsutsui Exp $");
39
40 #include <sys/param.h>
41 #include <sys/conf.h>
42 #include <sys/device.h>
43 #include <sys/proc.h>
44 #include <sys/systm.h>
45 #include <sys/callout.h>
46 #include <sys/tty.h>
47 #include <sys/kauth.h>
48
49 #include <dev/cons.h>
50
51 #include <machine/autoconf.h>
52 #include <machine/romcall.h>
53
54 #include "ioconf.h"
55
56 struct romcons_softc {
57 device_t sc_dev;
58 struct tty *sc_tty;
59 struct callout sc_poll_ch;
60 int sc_flags;
61 #define CONS_POLL 1
62 };
63
64 #define BURSTLEN 128 /* max number of bytes to write in one chunk */
65
66 cons_decl(romcons_);
67
68 static int romcons_match(device_t, cfdata_t, void *);
69 static void romcons_attach(device_t, device_t, void *);
70
71 CFATTACH_DECL_NEW(romcons, sizeof(struct romcons_softc),
72 romcons_match, romcons_attach, NULL, NULL);
73
74 dev_type_open(romcons_open);
75 dev_type_close(romcons_close);
76 dev_type_read(romcons_read);
77 dev_type_write(romcons_write);
78 dev_type_ioctl(romcons_ioctl);
79 dev_type_tty(romcons_tty);
80 dev_type_poll(romcons_poll);
81
82 void romcons_kbdinput(int);
83
84 const struct cdevsw romcons_cdevsw = {
85 romcons_open, romcons_close, romcons_read, romcons_write, romcons_ioctl,
86 nostop, romcons_tty, romcons_poll, nommap, ttykqfilter, D_TTY
87 };
88
89 struct consdev consdev_rom = cons_init(romcons_);
90
91 bool romcons_is_console;
92
93 static int
94 romcons_match(device_t parent, cfdata_t match, void *aux)
95 {
96 struct mainbus_attach_args *ma = aux;
97 static bool romcons_matched;
98
99 if (strcmp(ma->ma_name, "romcons"))
100 return 0;
101
102 if (!romcons_is_console)
103 return 0;
104
105 if (romcons_matched)
106 return 0;
107
108 romcons_matched = true;
109 return 1;
110 }
111
112 static void
113 romcons_attach(device_t parent, device_t self, void *aux)
114 {
115 struct romcons_softc *sc = device_private(self);
116
117 sc->sc_dev = self;
118 vectab[46] = romcallvec; /* XXX */
119 aprint_normal("\n");
120
121 callout_init(&sc->sc_poll_ch, 0);
122 }
123
124 static void romcons_start(struct tty *);
125 static int romcons_param(struct tty *, struct termios *);
126 static void romcons_pollin(void *);
127
128 int
129 romcons_open(dev_t dev, int flag, int mode, struct lwp *l)
130 {
131 struct romcons_softc *sc;
132 struct tty *tp;
133
134 sc = device_lookup_private(&romcons_cd, minor(dev));
135 if (sc == NULL)
136 return ENXIO;
137 if ((tp = sc->sc_tty) == 0)
138 sc->sc_tty = tp = tty_alloc();
139 tp->t_oproc = romcons_start;
140 tp->t_param = romcons_param;
141 tp->t_dev = dev;
142 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
143 return EBUSY;
144 if ((tp->t_state & TS_ISOPEN) == 0) {
145 ttychars(tp);
146 tp->t_iflag = TTYDEF_IFLAG;
147 tp->t_oflag = TTYDEF_OFLAG;
148 tp->t_cflag = TTYDEF_CFLAG;
149 tp->t_lflag = TTYDEF_LFLAG;
150 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
151 romcons_param(tp, &tp->t_termios);
152 ttsetwater(tp);
153 }
154 tp->t_state |= TS_CARR_ON;
155
156 if ((sc->sc_flags & CONS_POLL) == 0) {
157 sc->sc_flags |= CONS_POLL;
158 callout_reset(&sc->sc_poll_ch, 1, romcons_pollin, sc);
159 }
160
161 return (*tp->t_linesw->l_open)(dev, tp);
162 }
163
164 int
165 romcons_close(dev_t dev, int flag, int mode, struct lwp *l)
166 {
167 struct romcons_softc *sc;
168 struct tty *tp;
169
170 sc = device_lookup_private(&romcons_cd, minor(dev));
171 tp = sc->sc_tty;
172 callout_stop(&sc->sc_poll_ch);
173 sc->sc_flags &= ~CONS_POLL;
174 (*tp->t_linesw->l_close)(tp, flag);
175 ttyclose(tp);
176 return 0;
177 }
178
179 int
180 romcons_read(dev_t dev, struct uio *uio, int flag)
181 {
182 struct romcons_softc *sc;
183 struct tty *tp;
184
185 sc = device_lookup_private(&romcons_cd, minor(dev));
186 tp = sc->sc_tty;
187
188 return (*tp->t_linesw->l_read)(tp, uio, flag);
189 }
190
191 int
192 romcons_write(dev_t dev, struct uio *uio, int flag)
193 {
194 struct romcons_softc *sc;
195 struct tty *tp;
196
197 sc = device_lookup_private(&romcons_cd, minor(dev));
198 tp = sc->sc_tty;
199 return (*tp->t_linesw->l_write)(tp, uio, flag);
200 }
201
202 int
203 romcons_poll(dev_t dev, int events, struct lwp *l)
204 {
205 struct romcons_softc *sc;
206 struct tty *tp;
207
208 sc = device_lookup_private(&romcons_cd, minor(dev));
209 tp = sc->sc_tty;
210 return (*tp->t_linesw->l_poll)(tp, events, l);
211 }
212 int
213 romcons_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
214 {
215 struct romcons_softc *sc;
216 struct tty *tp;
217 int error;
218
219 sc = device_lookup_private(&romcons_cd, minor(dev));
220 tp = sc->sc_tty;
221 if ((error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l)) !=
222 EPASSTHROUGH)
223 return error;
224 return ttioctl(tp, cmd, data, flag, l);
225 }
226
227 struct tty *
228 romcons_tty(dev_t dev)
229 {
230 struct romcons_softc *sc;
231
232 sc = device_lookup_private(&romcons_cd, minor(dev));
233 return sc->sc_tty;
234 }
235
236 static void
237 romcons_start(struct tty *tp)
238 {
239 int s, len;
240 uint8_t buf[BURSTLEN];
241
242 s = spltty();
243 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
244 splx(s);
245 return;
246 }
247 tp->t_state |= TS_BUSY;
248 splx(s);
249 len = q_to_b(&tp->t_outq, buf, BURSTLEN);
250 s = splhigh();
251 rom_write(1, buf, len);
252 splx(s);
253 s = spltty();
254 tp->t_state &= ~TS_BUSY;
255 if (ttypull(tp)) {
256 tp->t_state |= TS_TIMEOUT;
257 callout_schedule(&tp->t_rstrt_ch, 1);
258 }
259 splx(s);
260 }
261
262 static int
263 romcons_param(struct tty *tp, struct termios *t)
264 {
265
266 tp->t_ispeed = t->c_ispeed;
267 tp->t_ospeed = t->c_ospeed;
268 tp->t_cflag = t->c_cflag;
269 return 0;
270 }
271
272 static void
273 romcons_pollin(void *aux)
274 {
275 struct romcons_softc *sc = aux;
276 struct tty *tp = sc->sc_tty;
277 char ch;
278 int rv;
279
280 while (0 && (rv = rom_read(1, &ch, 1)) > 0) {
281 if (tp && (tp->t_state & TS_ISOPEN))
282 (*tp->t_linesw->l_rint)(ch, tp);
283 }
284 callout_reset(&sc->sc_poll_ch, 1, romcons_pollin, sc);
285 }
286
287 void
288 romcons_kbdinput(int ks)
289 {
290 struct romcons_softc *sc;
291 struct tty *tp;
292
293 sc = device_lookup_private(&romcons_cd, 0);
294 tp = sc->sc_tty;
295 if (tp && (tp->t_state & TS_ISOPEN))
296 (*tp->t_linesw->l_rint)(ks, tp);
297 }
298
299 void
300 romcons_cnprobe(struct consdev *cd)
301 {
302 }
303
304 void
305 romcons_cninit(struct consdev *cd)
306 {
307 int maj;
308
309 maj = cdevsw_lookup_major(&romcons_cdevsw);
310 cd->cn_dev = makedev(maj, 0);
311 romcons_is_console = true;
312 vectab[46] = romcallvec; /* XXX */
313 }
314
315 int
316 romcons_cngetc(dev_t dev)
317 {
318 unsigned char ch = '\0';
319 int l;
320
321 while ((l = rom_read(1, &ch, 1)) != 1)
322 if (l != -2 && l != 0)
323 return -1;
324 return ch;
325 }
326
327 void
328 romcons_cnputc(dev_t dev, int c)
329 {
330 char ch = c;
331
332 rom_write(1, &ch, 1);
333 }
334
335 void
336 romcons_cnpollc(dev_t dev, int on)
337 {
338 struct romcons_softc *sc;
339
340 sc = device_lookup_private(&romcons_cd, minor(dev));
341
342 if (sc == NULL)
343 return;
344 if (on) {
345 if (sc->sc_flags & CONS_POLL)
346 callout_stop(&sc->sc_poll_ch);
347 sc->sc_flags &= ~CONS_POLL;
348 } else {
349 if ((sc->sc_flags & CONS_POLL) == 0) {
350 sc->sc_flags |= CONS_POLL;
351 callout_reset(&sc->sc_poll_ch, 1, romcons_pollin, sc);
352 }
353 }
354 }
355