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