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