1 /* $NetBSD: pcons.c,v 1.1 2002/03/22 00:22:44 fredette 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/promlib.h> 52 #include <machine/conf.h> 53 #include <machine/cpu.h> 54 #include <machine/psl.h> 55 56 #include <dev/cons.h> 57 58 #include <sun2/dev/cons.h> 59 60 static int pconsmatch __P((struct device *, struct cfdata *, void *)); 61 static void pconsattach __P((struct device *, struct device *, void *)); 62 63 struct cfattach pcons_ca = { 64 sizeof(struct pconssoftc), pconsmatch, pconsattach 65 }; 66 67 extern struct cfdriver pcons_cd; 68 static struct cnm_state pcons_cnm_state; 69 70 static int pconsprobe __P((void)); 71 extern struct consdev *cn_tab; 72 73 static int 74 pconsmatch(parent, match, aux) 75 struct device *parent; 76 struct cfdata *match; 77 void *aux; 78 { 79 struct mainbus_attach_args *ma = aux; 80 extern int prom_cngetc __P((dev_t)); 81 82 /* Only attach if no other console has attached. */ 83 return ((ma->ma_name != NULL) && 84 (strcmp("pcons", ma->ma_name) == 0) && 85 (cn_tab->cn_getc == prom_cngetc)); 86 87 } 88 89 static void 90 pconsattach(parent, self, aux) 91 struct device *parent, *self; 92 void *aux; 93 { 94 struct pconssoftc *sc = (struct pconssoftc *) self; 95 96 printf("\n"); 97 if (!pconsprobe()) 98 return; 99 100 cn_init_magic(&pcons_cnm_state); 101 cn_set_magic("+++++"); 102 callout_init(&sc->sc_poll_ch); 103 } 104 105 static void pconsstart __P((struct tty *)); 106 static int pconsparam __P((struct tty *, struct termios *)); 107 static void pcons_poll __P((void *)); 108 109 int 110 pconsopen(dev, flag, mode, p) 111 dev_t dev; 112 int flag, mode; 113 struct proc *p; 114 { 115 struct pconssoftc *sc; 116 int unit = minor(dev); 117 struct tty *tp; 118 119 if (unit >= pcons_cd.cd_ndevs) 120 return ENXIO; 121 sc = pcons_cd.cd_devs[unit]; 122 if (!sc) 123 return ENXIO; 124 if (!(tp = sc->of_tty)) 125 sc->of_tty = tp = ttymalloc(); 126 tp->t_oproc = pconsstart; 127 tp->t_param = pconsparam; 128 tp->t_dev = dev; 129 cn_tab->cn_dev = dev; 130 if (!(tp->t_state & TS_ISOPEN)) { 131 ttychars(tp); 132 tp->t_iflag = TTYDEF_IFLAG; 133 tp->t_oflag = TTYDEF_OFLAG; 134 tp->t_cflag = TTYDEF_CFLAG; 135 tp->t_lflag = TTYDEF_LFLAG; 136 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 137 pconsparam(tp, &tp->t_termios); 138 ttsetwater(tp); 139 } else if ((tp->t_state&TS_XCLUDE) && suser(p->p_ucred, &p->p_acflag)) 140 return EBUSY; 141 tp->t_state |= TS_CARR_ON; 142 143 if (!(sc->of_flags & OFPOLL)) { 144 sc->of_flags |= OFPOLL; 145 callout_reset(&sc->sc_poll_ch, 1, pcons_poll, sc); 146 } 147 148 return (*tp->t_linesw->l_open)(dev, tp); 149 } 150 151 int 152 pconsclose(dev, flag, mode, p) 153 dev_t dev; 154 int flag, mode; 155 struct proc *p; 156 { 157 struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)]; 158 struct tty *tp = sc->of_tty; 159 160 callout_stop(&sc->sc_poll_ch); 161 sc->of_flags &= ~OFPOLL; 162 (*tp->t_linesw->l_close)(tp, flag); 163 ttyclose(tp); 164 return 0; 165 } 166 167 int 168 pconsread(dev, uio, flag) 169 dev_t dev; 170 struct uio *uio; 171 int flag; 172 { 173 struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)]; 174 struct tty *tp = sc->of_tty; 175 176 return (*tp->t_linesw->l_read)(tp, uio, flag); 177 } 178 179 int 180 pconswrite(dev, uio, flag) 181 dev_t dev; 182 struct uio *uio; 183 int flag; 184 { 185 struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)]; 186 struct tty *tp = sc->of_tty; 187 188 return (*tp->t_linesw->l_write)(tp, uio, flag); 189 } 190 191 int 192 pconspoll(dev, events, p) 193 dev_t dev; 194 int events; 195 struct proc *p; 196 { 197 struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)]; 198 struct tty *tp = sc->of_tty; 199 200 return ((*tp->t_linesw->l_poll)(tp, events, p)); 201 } 202 203 int 204 pconsioctl(dev, cmd, data, flag, p) 205 dev_t dev; 206 u_long cmd; 207 caddr_t data; 208 int flag; 209 struct proc *p; 210 { 211 struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)]; 212 struct tty *tp = sc->of_tty; 213 int error; 214 215 if ((error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p)) >= 0) 216 return error; 217 if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0) 218 return error; 219 return ENOTTY; 220 } 221 222 struct tty * 223 pconstty(dev) 224 dev_t dev; 225 { 226 struct pconssoftc *sc = pcons_cd.cd_devs[minor(dev)]; 227 228 return sc->of_tty; 229 } 230 231 void 232 pconsstop(tp, flag) 233 struct tty *tp; 234 int flag; 235 { 236 } 237 238 static void 239 pconsstart(tp) 240 struct tty *tp; 241 { 242 struct clist *cl; 243 int s, len; 244 u_char buf[OFBURSTLEN]; 245 246 s = spltty(); 247 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 248 splx(s); 249 return; 250 } 251 tp->t_state |= TS_BUSY; 252 splx(s); 253 cl = &tp->t_outq; 254 len = q_to_b(cl, buf, OFBURSTLEN); 255 prom_putstr(buf, len); 256 s = spltty(); 257 tp->t_state &= ~TS_BUSY; 258 if (cl->c_cc) { 259 tp->t_state |= TS_TIMEOUT; 260 callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, (void *)tp); 261 } 262 if (cl->c_cc <= tp->t_lowat) { 263 if (tp->t_state & TS_ASLEEP) { 264 tp->t_state &= ~TS_ASLEEP; 265 wakeup(cl); 266 } 267 selwakeup(&tp->t_wsel); 268 } 269 splx(s); 270 } 271 272 static int 273 pconsparam(tp, t) 274 struct tty *tp; 275 struct termios *t; 276 { 277 tp->t_ispeed = t->c_ispeed; 278 tp->t_ospeed = t->c_ospeed; 279 tp->t_cflag = t->c_cflag; 280 return 0; 281 } 282 283 static void 284 pcons_poll(aux) 285 void *aux; 286 { 287 struct pconssoftc *sc = aux; 288 struct tty *tp = sc->of_tty; 289 int c; 290 char ch; 291 292 while ((c = prom_peekchar()) >= 0) { 293 ch = c; 294 cn_check_magic(tp->t_dev, ch, pcons_cnm_state); 295 if (tp && (tp->t_state & TS_ISOPEN)) 296 (*tp->t_linesw->l_rint)(ch, tp); 297 } 298 callout_reset(&sc->sc_poll_ch, 1, pcons_poll, sc); 299 } 300 301 int 302 pconsprobe() 303 { 304 switch (prom_version()) { 305 #ifdef PROM_OLDMON 306 case PROM_OLDMON: 307 case PROM_OBP_V0: 308 return (1); 309 #endif /* PROM_OLDMON */ 310 #ifdef PROM_OBP_V2 311 case PROM_OBP_V2: 312 case PROM_OBP_V3: 313 case PROM_OPENFIRM: 314 return (prom_stdin() && prom_stdout()); 315 #endif /* PROM_OBP_V2 */ 316 default: break; 317 } 318 return (0); 319 } 320 321 void 322 pcons_cnpollc(dev, on) 323 dev_t dev; 324 int on; 325 { 326 struct pconssoftc *sc = NULL; 327 328 if (pcons_cd.cd_devs) 329 sc = pcons_cd.cd_devs[minor(dev)]; 330 331 if (on) { 332 if (!sc) return; 333 if (sc->of_flags & OFPOLL) 334 callout_stop(&sc->sc_poll_ch); 335 sc->of_flags &= ~OFPOLL; 336 } else { 337 /* Resuming kernel. */ 338 if (sc && !(sc->of_flags & OFPOLL)) { 339 sc->of_flags |= OFPOLL; 340 callout_reset(&sc->sc_poll_ch, 1, pcons_poll, sc); 341 } 342 } 343 } 344 345 void pcons_dopoll __P((void)); 346 void 347 pcons_dopoll() { 348 pcons_poll((void*)pcons_cd.cd_devs[0]); 349 } 350