1 /* $NetBSD: romcons.c,v 1.3 2014/07/25 08:10:34 dholland 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.3 2014/07/25 08:10:34 dholland 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 .d_open = romcons_open,
86 .d_close = romcons_close,
87 .d_read = romcons_read,
88 .d_write = romcons_write,
89 .d_ioctl = romcons_ioctl,
90 .d_stop = nostop,
91 .d_tty = romcons_tty,
92 .d_poll = romcons_poll,
93 .d_mmap = nommap,
94 .d_kqfilter = ttykqfilter,
95 .d_discard = nodiscard,
96 .d_flag = D_TTY
97 };
98
99 struct consdev consdev_rom = cons_init(romcons_);
100
101 bool romcons_is_console;
102
103 static int
romcons_match(device_t parent,cfdata_t match,void * aux)104 romcons_match(device_t parent, cfdata_t match, void *aux)
105 {
106 struct mainbus_attach_args *ma = aux;
107 static bool romcons_matched;
108
109 if (strcmp(ma->ma_name, "romcons"))
110 return 0;
111
112 if (!romcons_is_console)
113 return 0;
114
115 if (romcons_matched)
116 return 0;
117
118 romcons_matched = true;
119 return 1;
120 }
121
122 static void
romcons_attach(device_t parent,device_t self,void * aux)123 romcons_attach(device_t parent, device_t self, void *aux)
124 {
125 struct romcons_softc *sc = device_private(self);
126
127 sc->sc_dev = self;
128 vectab[46] = romcallvec; /* XXX */
129 aprint_normal("\n");
130
131 callout_init(&sc->sc_poll_ch, 0);
132 }
133
134 static void romcons_start(struct tty *);
135 static int romcons_param(struct tty *, struct termios *);
136 static void romcons_pollin(void *);
137
138 int
romcons_open(dev_t dev,int flag,int mode,struct lwp * l)139 romcons_open(dev_t dev, int flag, int mode, struct lwp *l)
140 {
141 struct romcons_softc *sc;
142 struct tty *tp;
143
144 sc = device_lookup_private(&romcons_cd, minor(dev));
145 if (sc == NULL)
146 return ENXIO;
147 if ((tp = sc->sc_tty) == 0)
148 sc->sc_tty = tp = tty_alloc();
149 tp->t_oproc = romcons_start;
150 tp->t_param = romcons_param;
151 tp->t_dev = dev;
152 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
153 return EBUSY;
154 if ((tp->t_state & TS_ISOPEN) == 0) {
155 ttychars(tp);
156 tp->t_iflag = TTYDEF_IFLAG;
157 tp->t_oflag = TTYDEF_OFLAG;
158 tp->t_cflag = TTYDEF_CFLAG;
159 tp->t_lflag = TTYDEF_LFLAG;
160 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
161 romcons_param(tp, &tp->t_termios);
162 ttsetwater(tp);
163 }
164 tp->t_state |= TS_CARR_ON;
165
166 if ((sc->sc_flags & CONS_POLL) == 0) {
167 sc->sc_flags |= CONS_POLL;
168 callout_reset(&sc->sc_poll_ch, 1, romcons_pollin, sc);
169 }
170
171 return (*tp->t_linesw->l_open)(dev, tp);
172 }
173
174 int
romcons_close(dev_t dev,int flag,int mode,struct lwp * l)175 romcons_close(dev_t dev, int flag, int mode, struct lwp *l)
176 {
177 struct romcons_softc *sc;
178 struct tty *tp;
179
180 sc = device_lookup_private(&romcons_cd, minor(dev));
181 tp = sc->sc_tty;
182 callout_stop(&sc->sc_poll_ch);
183 sc->sc_flags &= ~CONS_POLL;
184 (*tp->t_linesw->l_close)(tp, flag);
185 ttyclose(tp);
186 return 0;
187 }
188
189 int
romcons_read(dev_t dev,struct uio * uio,int flag)190 romcons_read(dev_t dev, struct uio *uio, int flag)
191 {
192 struct romcons_softc *sc;
193 struct tty *tp;
194
195 sc = device_lookup_private(&romcons_cd, minor(dev));
196 tp = sc->sc_tty;
197
198 return (*tp->t_linesw->l_read)(tp, uio, flag);
199 }
200
201 int
romcons_write(dev_t dev,struct uio * uio,int flag)202 romcons_write(dev_t dev, struct uio *uio, int flag)
203 {
204 struct romcons_softc *sc;
205 struct tty *tp;
206
207 sc = device_lookup_private(&romcons_cd, minor(dev));
208 tp = sc->sc_tty;
209 return (*tp->t_linesw->l_write)(tp, uio, flag);
210 }
211
212 int
romcons_poll(dev_t dev,int events,struct lwp * l)213 romcons_poll(dev_t dev, int events, struct lwp *l)
214 {
215 struct romcons_softc *sc;
216 struct tty *tp;
217
218 sc = device_lookup_private(&romcons_cd, minor(dev));
219 tp = sc->sc_tty;
220 return (*tp->t_linesw->l_poll)(tp, events, l);
221 }
222 int
romcons_ioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)223 romcons_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
224 {
225 struct romcons_softc *sc;
226 struct tty *tp;
227 int error;
228
229 sc = device_lookup_private(&romcons_cd, minor(dev));
230 tp = sc->sc_tty;
231 if ((error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l)) !=
232 EPASSTHROUGH)
233 return error;
234 return ttioctl(tp, cmd, data, flag, l);
235 }
236
237 struct tty *
romcons_tty(dev_t dev)238 romcons_tty(dev_t dev)
239 {
240 struct romcons_softc *sc;
241
242 sc = device_lookup_private(&romcons_cd, minor(dev));
243 return sc->sc_tty;
244 }
245
246 static void
romcons_start(struct tty * tp)247 romcons_start(struct tty *tp)
248 {
249 int s, len;
250 uint8_t buf[BURSTLEN];
251
252 s = spltty();
253 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
254 splx(s);
255 return;
256 }
257 tp->t_state |= TS_BUSY;
258 splx(s);
259 len = q_to_b(&tp->t_outq, buf, BURSTLEN);
260 s = splhigh();
261 rom_write(1, buf, len);
262 splx(s);
263 s = spltty();
264 tp->t_state &= ~TS_BUSY;
265 if (ttypull(tp)) {
266 tp->t_state |= TS_TIMEOUT;
267 callout_schedule(&tp->t_rstrt_ch, 1);
268 }
269 splx(s);
270 }
271
272 static int
romcons_param(struct tty * tp,struct termios * t)273 romcons_param(struct tty *tp, struct termios *t)
274 {
275
276 tp->t_ispeed = t->c_ispeed;
277 tp->t_ospeed = t->c_ospeed;
278 tp->t_cflag = t->c_cflag;
279 return 0;
280 }
281
282 static void
romcons_pollin(void * aux)283 romcons_pollin(void *aux)
284 {
285 struct romcons_softc *sc = aux;
286 struct tty *tp = sc->sc_tty;
287 char ch;
288 int rv;
289
290 while (0 && (rv = rom_read(1, &ch, 1)) > 0) {
291 if (tp && (tp->t_state & TS_ISOPEN))
292 (*tp->t_linesw->l_rint)(ch, tp);
293 }
294 callout_reset(&sc->sc_poll_ch, 1, romcons_pollin, sc);
295 }
296
297 void
romcons_kbdinput(int ks)298 romcons_kbdinput(int ks)
299 {
300 struct romcons_softc *sc;
301 struct tty *tp;
302
303 sc = device_lookup_private(&romcons_cd, 0);
304 tp = sc->sc_tty;
305 if (tp && (tp->t_state & TS_ISOPEN))
306 (*tp->t_linesw->l_rint)(ks, tp);
307 }
308
309 void
romcons_cnprobe(struct consdev * cd)310 romcons_cnprobe(struct consdev *cd)
311 {
312 }
313
314 void
romcons_cninit(struct consdev * cd)315 romcons_cninit(struct consdev *cd)
316 {
317 int maj;
318
319 maj = cdevsw_lookup_major(&romcons_cdevsw);
320 cd->cn_dev = makedev(maj, 0);
321 romcons_is_console = true;
322 vectab[46] = romcallvec; /* XXX */
323 }
324
325 int
romcons_cngetc(dev_t dev)326 romcons_cngetc(dev_t dev)
327 {
328 unsigned char ch = '\0';
329 int l;
330
331 while ((l = rom_read(1, &ch, 1)) != 1)
332 if (l != -2 && l != 0)
333 return -1;
334 return ch;
335 }
336
337 void
romcons_cnputc(dev_t dev,int c)338 romcons_cnputc(dev_t dev, int c)
339 {
340 char ch = c;
341
342 rom_write(1, &ch, 1);
343 }
344
345 void
romcons_cnpollc(dev_t dev,int on)346 romcons_cnpollc(dev_t dev, int on)
347 {
348 struct romcons_softc *sc;
349
350 sc = device_lookup_private(&romcons_cd, minor(dev));
351
352 if (sc == NULL)
353 return;
354 if (on) {
355 if (sc->sc_flags & CONS_POLL)
356 callout_stop(&sc->sc_poll_ch);
357 sc->sc_flags &= ~CONS_POLL;
358 } else {
359 if ((sc->sc_flags & CONS_POLL) == 0) {
360 sc->sc_flags |= CONS_POLL;
361 callout_reset(&sc->sc_poll_ch, 1, romcons_pollin, sc);
362 }
363 }
364 }
365