1 1.22 dholland /* $NetBSD: pcons.c,v 1.22 2014/07/25 08:10:35 dholland Exp $ */ 2 1.1 fredette 3 1.1 fredette /*- 4 1.1 fredette * Copyright (c) 2000 Eduardo E. Horvath 5 1.1 fredette * All rights reserved. 6 1.1 fredette * 7 1.1 fredette * Redistribution and use in source and binary forms, with or without 8 1.1 fredette * modification, are permitted provided that the following conditions 9 1.1 fredette * are met: 10 1.1 fredette * 1. Redistributions of source code must retain the above copyright 11 1.1 fredette * notice, this list of conditions and the following disclaimer. 12 1.1 fredette * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 fredette * notice, this list of conditions and the following disclaimer in the 14 1.1 fredette * documentation and/or other materials provided with the distribution. 15 1.1 fredette * 3. The name of the author may not be used to endorse or promote products 16 1.1 fredette * derived from this software without specific prior written permission. 17 1.1 fredette * 18 1.1 fredette * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 fredette * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 fredette * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 fredette * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 fredette * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 1.1 fredette * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 1.1 fredette * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 1.1 fredette * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 1.1 fredette * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 fredette * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 fredette * SUCH DAMAGE. 29 1.1 fredette */ 30 1.1 fredette 31 1.1 fredette /* 32 1.1 fredette * Default console driver. Uses the PROM or whatever 33 1.1 fredette * driver(s) are appropriate. 34 1.1 fredette */ 35 1.7 lukem 36 1.7 lukem #include <sys/cdefs.h> 37 1.22 dholland __KERNEL_RCSID(0, "$NetBSD: pcons.c,v 1.22 2014/07/25 08:10:35 dholland Exp $"); 38 1.1 fredette 39 1.1 fredette #include "opt_ddb.h" 40 1.1 fredette 41 1.1 fredette #include <sys/param.h> 42 1.1 fredette #include <sys/systm.h> 43 1.1 fredette #include <sys/conf.h> 44 1.1 fredette #include <sys/device.h> 45 1.1 fredette #include <sys/file.h> 46 1.1 fredette #include <sys/ioctl.h> 47 1.1 fredette #include <sys/kernel.h> 48 1.1 fredette #include <sys/proc.h> 49 1.1 fredette #include <sys/tty.h> 50 1.1 fredette #include <sys/time.h> 51 1.1 fredette #include <sys/syslog.h> 52 1.10 elad #include <sys/kauth.h> 53 1.1 fredette 54 1.1 fredette #include <machine/autoconf.h> 55 1.1 fredette #include <machine/promlib.h> 56 1.1 fredette #include <machine/cpu.h> 57 1.1 fredette #include <machine/psl.h> 58 1.1 fredette 59 1.1 fredette #include <dev/cons.h> 60 1.1 fredette 61 1.1 fredette #include <sun2/dev/cons.h> 62 1.1 fredette 63 1.19 tsutsui #include "ioconf.h" 64 1.1 fredette 65 1.19 tsutsui static int pconsmatch(device_t, cfdata_t, void *); 66 1.19 tsutsui static void pconsattach(device_t, device_t, void *); 67 1.19 tsutsui 68 1.19 tsutsui CFATTACH_DECL_NEW(pcons, sizeof(struct pconssoftc), 69 1.5 thorpej pconsmatch, pconsattach, NULL, NULL); 70 1.1 fredette 71 1.1 fredette static struct cnm_state pcons_cnm_state; 72 1.1 fredette 73 1.8 chs static int pconsprobe(void); 74 1.1 fredette 75 1.2 gehenna dev_type_open(pconsopen); 76 1.2 gehenna dev_type_close(pconsclose); 77 1.2 gehenna dev_type_read(pconsread); 78 1.2 gehenna dev_type_write(pconswrite); 79 1.2 gehenna dev_type_ioctl(pconsioctl); 80 1.2 gehenna dev_type_tty(pconstty); 81 1.2 gehenna dev_type_poll(pconspoll); 82 1.2 gehenna 83 1.2 gehenna const struct cdevsw pcons_cdevsw = { 84 1.21 dholland .d_open = pconsopen, 85 1.21 dholland .d_close = pconsclose, 86 1.21 dholland .d_read = pconsread, 87 1.21 dholland .d_write = pconswrite, 88 1.21 dholland .d_ioctl = pconsioctl, 89 1.21 dholland .d_stop = nostop, 90 1.21 dholland .d_tty = pconstty, 91 1.21 dholland .d_poll = pconspoll, 92 1.21 dholland .d_mmap = nommap, 93 1.21 dholland .d_kqfilter = ttykqfilter, 94 1.22 dholland .d_discard = nodiscard, 95 1.21 dholland .d_flag = D_TTY 96 1.2 gehenna }; 97 1.2 gehenna 98 1.8 chs static int 99 1.19 tsutsui pconsmatch(device_t parent, cfdata_t cf, void *aux) 100 1.1 fredette { 101 1.1 fredette struct mainbus_attach_args *ma = aux; 102 1.19 tsutsui extern int prom_cngetc(dev_t); 103 1.1 fredette 104 1.1 fredette /* Only attach if no other console has attached. */ 105 1.19 tsutsui return (ma->ma_name != NULL) && 106 1.19 tsutsui (strcmp("pcons", ma->ma_name) == 0) && 107 1.19 tsutsui (cn_tab->cn_getc == prom_cngetc); 108 1.1 fredette 109 1.1 fredette } 110 1.1 fredette 111 1.8 chs static void 112 1.19 tsutsui pconsattach(device_t parent, device_t self, void *aux) 113 1.1 fredette { 114 1.19 tsutsui struct pconssoftc *sc = device_private(self); 115 1.1 fredette 116 1.19 tsutsui aprint_normal("\n"); 117 1.1 fredette if (!pconsprobe()) 118 1.1 fredette return; 119 1.1 fredette 120 1.1 fredette cn_init_magic(&pcons_cnm_state); 121 1.1 fredette cn_set_magic("+++++"); 122 1.14 ad callout_init(&sc->sc_poll_ch, 0); 123 1.1 fredette } 124 1.1 fredette 125 1.8 chs static void pconsstart(struct tty *); 126 1.8 chs static int pconsparam(struct tty *, struct termios *); 127 1.8 chs static void pcons_poll(void *); 128 1.8 chs 129 1.8 chs int 130 1.9 christos pconsopen(dev_t dev, int flag, int mode, struct lwp *l) 131 1.1 fredette { 132 1.1 fredette struct pconssoftc *sc; 133 1.1 fredette struct tty *tp; 134 1.1 fredette 135 1.18 cegger sc = device_lookup_private(&pcons_cd, minor(dev)); 136 1.19 tsutsui if (sc == NULL) 137 1.1 fredette return ENXIO; 138 1.19 tsutsui if ((tp = sc->of_tty) == NULL) 139 1.20 rmind sc->of_tty = tp = tty_alloc(); 140 1.1 fredette tp->t_oproc = pconsstart; 141 1.1 fredette tp->t_param = pconsparam; 142 1.1 fredette tp->t_dev = dev; 143 1.1 fredette cn_tab->cn_dev = dev; 144 1.12 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 145 1.12 elad return (EBUSY); 146 1.19 tsutsui if ((tp->t_state & TS_ISOPEN) == 0) { 147 1.1 fredette ttychars(tp); 148 1.1 fredette tp->t_iflag = TTYDEF_IFLAG; 149 1.1 fredette tp->t_oflag = TTYDEF_OFLAG; 150 1.1 fredette tp->t_cflag = TTYDEF_CFLAG; 151 1.1 fredette tp->t_lflag = TTYDEF_LFLAG; 152 1.1 fredette tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 153 1.1 fredette pconsparam(tp, &tp->t_termios); 154 1.1 fredette ttsetwater(tp); 155 1.12 elad } 156 1.1 fredette tp->t_state |= TS_CARR_ON; 157 1.1 fredette 158 1.19 tsutsui if ((sc->of_flags & OFPOLL) == 0) { 159 1.1 fredette sc->of_flags |= OFPOLL; 160 1.1 fredette callout_reset(&sc->sc_poll_ch, 1, pcons_poll, sc); 161 1.1 fredette } 162 1.1 fredette 163 1.1 fredette return (*tp->t_linesw->l_open)(dev, tp); 164 1.1 fredette } 165 1.1 fredette 166 1.8 chs int 167 1.9 christos pconsclose(dev_t dev, int flag, int mode, struct lwp *l) 168 1.1 fredette { 169 1.18 cegger struct pconssoftc *sc = device_lookup_private(&pcons_cd, minor(dev)); 170 1.1 fredette struct tty *tp = sc->of_tty; 171 1.1 fredette 172 1.1 fredette callout_stop(&sc->sc_poll_ch); 173 1.1 fredette sc->of_flags &= ~OFPOLL; 174 1.1 fredette (*tp->t_linesw->l_close)(tp, flag); 175 1.1 fredette ttyclose(tp); 176 1.1 fredette return 0; 177 1.1 fredette } 178 1.1 fredette 179 1.8 chs int 180 1.8 chs pconsread(dev_t dev, struct uio *uio, int flag) 181 1.1 fredette { 182 1.18 cegger struct pconssoftc *sc = device_lookup_private(&pcons_cd, minor(dev)); 183 1.1 fredette struct tty *tp = sc->of_tty; 184 1.1 fredette 185 1.1 fredette return (*tp->t_linesw->l_read)(tp, uio, flag); 186 1.1 fredette } 187 1.1 fredette 188 1.8 chs int 189 1.8 chs pconswrite(dev_t dev, struct uio *uio, int flag) 190 1.1 fredette { 191 1.18 cegger struct pconssoftc *sc = device_lookup_private(&pcons_cd, minor(dev)); 192 1.1 fredette struct tty *tp = sc->of_tty; 193 1.1 fredette 194 1.1 fredette return (*tp->t_linesw->l_write)(tp, uio, flag); 195 1.1 fredette } 196 1.1 fredette 197 1.8 chs int 198 1.9 christos pconspoll(dev_t dev, int events, struct lwp *l) 199 1.1 fredette { 200 1.18 cegger struct pconssoftc *sc = device_lookup_private(&pcons_cd, minor(dev)); 201 1.1 fredette struct tty *tp = sc->of_tty; 202 1.1 fredette 203 1.19 tsutsui return (*tp->t_linesw->l_poll)(tp, events, l); 204 1.1 fredette } 205 1.1 fredette 206 1.8 chs int 207 1.13 christos pconsioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 208 1.1 fredette { 209 1.18 cegger struct pconssoftc *sc = device_lookup_private(&pcons_cd, minor(dev)); 210 1.1 fredette struct tty *tp = sc->of_tty; 211 1.1 fredette int error; 212 1.1 fredette 213 1.9 christos if ((error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l)) >= 0) 214 1.1 fredette return error; 215 1.9 christos if ((error = ttioctl(tp, cmd, data, flag, l)) >= 0) 216 1.1 fredette return error; 217 1.1 fredette return ENOTTY; 218 1.1 fredette } 219 1.1 fredette 220 1.1 fredette struct tty * 221 1.8 chs pconstty(dev_t dev) 222 1.1 fredette { 223 1.18 cegger struct pconssoftc *sc = device_lookup_private(&pcons_cd, minor(dev)); 224 1.1 fredette 225 1.1 fredette return sc->of_tty; 226 1.1 fredette } 227 1.1 fredette 228 1.8 chs static void 229 1.8 chs pconsstart(struct tty *tp) 230 1.1 fredette { 231 1.1 fredette struct clist *cl; 232 1.1 fredette int s, len; 233 1.19 tsutsui uint8_t buf[OFBURSTLEN]; 234 1.1 fredette 235 1.1 fredette s = spltty(); 236 1.1 fredette if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 237 1.1 fredette splx(s); 238 1.1 fredette return; 239 1.1 fredette } 240 1.1 fredette tp->t_state |= TS_BUSY; 241 1.1 fredette splx(s); 242 1.1 fredette cl = &tp->t_outq; 243 1.1 fredette len = q_to_b(cl, buf, OFBURSTLEN); 244 1.1 fredette prom_putstr(buf, len); 245 1.1 fredette s = spltty(); 246 1.1 fredette tp->t_state &= ~TS_BUSY; 247 1.17 ad if (ttypull(tp)) { 248 1.1 fredette tp->t_state |= TS_TIMEOUT; 249 1.16 joerg callout_schedule(&tp->t_rstrt_ch, 1); 250 1.1 fredette } 251 1.1 fredette splx(s); 252 1.1 fredette } 253 1.1 fredette 254 1.8 chs static int 255 1.8 chs pconsparam(struct tty *tp, struct termios *t) 256 1.1 fredette { 257 1.19 tsutsui 258 1.1 fredette tp->t_ispeed = t->c_ispeed; 259 1.1 fredette tp->t_ospeed = t->c_ospeed; 260 1.1 fredette tp->t_cflag = t->c_cflag; 261 1.1 fredette return 0; 262 1.1 fredette } 263 1.1 fredette 264 1.8 chs static void 265 1.8 chs pcons_poll(void *aux) 266 1.1 fredette { 267 1.1 fredette struct pconssoftc *sc = aux; 268 1.1 fredette struct tty *tp = sc->of_tty; 269 1.1 fredette int c; 270 1.1 fredette char ch; 271 1.1 fredette 272 1.1 fredette while ((c = prom_peekchar()) >= 0) { 273 1.1 fredette ch = c; 274 1.1 fredette cn_check_magic(tp->t_dev, ch, pcons_cnm_state); 275 1.1 fredette if (tp && (tp->t_state & TS_ISOPEN)) 276 1.1 fredette (*tp->t_linesw->l_rint)(ch, tp); 277 1.1 fredette } 278 1.1 fredette callout_reset(&sc->sc_poll_ch, 1, pcons_poll, sc); 279 1.1 fredette } 280 1.1 fredette 281 1.8 chs int 282 1.8 chs pconsprobe(void) 283 1.1 fredette { 284 1.19 tsutsui 285 1.1 fredette switch (prom_version()) { 286 1.1 fredette #ifdef PROM_OLDMON 287 1.1 fredette case PROM_OLDMON: 288 1.1 fredette case PROM_OBP_V0: 289 1.19 tsutsui return 1; 290 1.1 fredette #endif /* PROM_OLDMON */ 291 1.1 fredette #ifdef PROM_OBP_V2 292 1.1 fredette case PROM_OBP_V2: 293 1.1 fredette case PROM_OBP_V3: 294 1.1 fredette case PROM_OPENFIRM: 295 1.19 tsutsui return prom_stdin() && prom_stdout(); 296 1.1 fredette #endif /* PROM_OBP_V2 */ 297 1.19 tsutsui default: 298 1.19 tsutsui break; 299 1.1 fredette } 300 1.19 tsutsui return 0; 301 1.1 fredette } 302 1.1 fredette 303 1.8 chs void 304 1.8 chs pcons_cnpollc(dev_t dev, int on) 305 1.1 fredette { 306 1.19 tsutsui struct pconssoftc *sc; 307 1.1 fredette 308 1.18 cegger sc = device_lookup_private(&pcons_cd, minor(dev)); 309 1.18 cegger if (sc == NULL) 310 1.18 cegger return; 311 1.1 fredette 312 1.1 fredette if (on) { 313 1.1 fredette if (sc->of_flags & OFPOLL) 314 1.1 fredette callout_stop(&sc->sc_poll_ch); 315 1.1 fredette sc->of_flags &= ~OFPOLL; 316 1.1 fredette } else { 317 1.1 fredette /* Resuming kernel. */ 318 1.19 tsutsui if ((sc->of_flags & OFPOLL) == 0) { 319 1.1 fredette sc->of_flags |= OFPOLL; 320 1.1 fredette callout_reset(&sc->sc_poll_ch, 1, pcons_poll, sc); 321 1.1 fredette } 322 1.1 fredette } 323 1.1 fredette } 324 1.1 fredette 325 1.8 chs void pcons_dopoll(void); 326 1.19 tsutsui 327 1.8 chs void 328 1.8 chs pcons_dopoll(void) 329 1.8 chs { 330 1.19 tsutsui 331 1.18 cegger pcons_poll(device_lookup_private(&pcons_cd, 0)); 332 1.1 fredette } 333