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