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