ofw_console.c revision 136680
178346Sbenno/* 278346Sbenno * Copyright (C) 2001 Benno Rice. 378346Sbenno * All rights reserved. 478346Sbenno * 578346Sbenno * Redistribution and use in source and binary forms, with or without 678346Sbenno * modification, are permitted provided that the following conditions 778346Sbenno * are met: 878346Sbenno * 1. Redistributions of source code must retain the above copyright 978346Sbenno * notice, this list of conditions and the following disclaimer. 1078346Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1178346Sbenno * notice, this list of conditions and the following disclaimer in the 1278346Sbenno * documentation and/or other materials provided with the distribution. 1378346Sbenno * 1478346Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 1578346Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1678346Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1778346Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1878346Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1978346Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2078346Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2178346Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2278346Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2378346Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2478346Sbenno */ 2578346Sbenno 26113038Sobrien#include <sys/cdefs.h> 27113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_console.c 136680 2004-10-18 21:51:27Z phk $"); 2878346Sbenno 29110509Sharti#include "opt_comconsole.h" 30131016Sobrien#include "opt_ofw.h" 31110509Sharti 3278346Sbenno#include <sys/param.h> 33131916Smarcel#include <sys/kdb.h> 3478346Sbenno#include <sys/kernel.h> 3578346Sbenno#include <sys/systm.h> 3678346Sbenno#include <sys/types.h> 3778346Sbenno#include <sys/conf.h> 3878346Sbenno#include <sys/cons.h> 3978346Sbenno#include <sys/consio.h> 4078346Sbenno#include <sys/tty.h> 4178346Sbenno 4278346Sbenno#include <dev/ofw/openfirm.h> 4378346Sbenno 44110509Sharti#include <ddb/ddb.h> 45110509Sharti 46131016Sobrien#ifndef OFWCONS_POLL_HZ 47131016Sobrien#define OFWCONS_POLL_HZ 4 /* 50-100 works best on Ultra2 */ 48131016Sobrien#endif 49131016Sobrien#define OFBURSTLEN 128 /* max number of bytes to write in one chunk */ 5078346Sbenno 5178346Sbennostatic d_open_t ofw_dev_open; 5278346Sbennostatic d_close_t ofw_dev_close; 5378346Sbenno 5478346Sbennostatic struct cdevsw ofw_cdevsw = { 55126080Sphk .d_version = D_VERSION, 56111815Sphk .d_open = ofw_dev_open, 57111815Sphk .d_close = ofw_dev_close, 58111815Sphk .d_name = "ofw", 59126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 6078346Sbenno}; 6178346Sbenno 6278346Sbennostatic struct tty *ofw_tp = NULL; 6378346Sbennostatic int polltime; 6478346Sbennostatic struct callout_handle ofw_timeouthandle 6578346Sbenno = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); 6678346Sbenno 67131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 68110509Shartistatic int alt_break_state; 69110509Sharti#endif 70110509Sharti 7178346Sbennostatic void ofw_tty_start(struct tty *); 7278346Sbennostatic int ofw_tty_param(struct tty *, struct termios *); 7378346Sbennostatic void ofw_tty_stop(struct tty *, int); 7478346Sbennostatic void ofw_timeout(void *); 7578346Sbenno 7678346Sbennostatic cn_probe_t ofw_cons_probe; 7778346Sbennostatic cn_init_t ofw_cons_init; 7878346Sbennostatic cn_getc_t ofw_cons_getc; 7978346Sbennostatic cn_checkc_t ofw_cons_checkc; 8078346Sbennostatic cn_putc_t ofw_cons_putc; 8178346Sbenno 8278346SbennoCONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc, 8378346Sbenno ofw_cons_checkc, ofw_cons_putc, NULL); 8478346Sbenno 8589115Sjakestatic void 8689115Sjakecn_drvinit(void *unused) 8789115Sjake{ 88107044Sjake phandle_t options; 89107044Sjake char output[32]; 90130585Sphk struct cdev *dev; 9189115Sjake 92120544Sjake if (ofw_consdev.cn_pri != CN_DEAD && 93120544Sjake ofw_consdev.cn_name[0] != '\0') { 94107044Sjake if ((options = OF_finddevice("/options")) == -1 || 95107044Sjake OF_getprop(options, "output-device", output, 96107044Sjake sizeof(output)) == -1) 97107044Sjake return; 98136454Sphk /* 99136454Sphk * XXX: This is a hack and it may result in two /dev/ttya 100136454Sphk * XXX: devices on platforms where the sab driver works. 101136454Sphk */ 102120491Sphk dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", 103109921Sjake output); 104120491Sphk make_dev_alias(dev, "ofwcons"); 105107044Sjake } 10689115Sjake} 10789115Sjake 108126076SphkSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL) 10989115Sjake 11078346Sbennostatic int stdin; 11178346Sbennostatic int stdout; 11278346Sbenno 11378346Sbennostatic int 114130585Sphkofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 11578346Sbenno{ 11678346Sbenno struct tty *tp; 11778346Sbenno int unit; 11878346Sbenno int error, setuptimeout; 11978346Sbenno 12078346Sbenno error = 0; 12178346Sbenno setuptimeout = 0; 12278346Sbenno unit = minor(dev); 12378346Sbenno 124136454Sphk /* 125136454Sphk * XXX: BAD, should happen at attach time 126136454Sphk */ 127136454Sphk if (dev->si_tty == NULL) { 128136454Sphk ofw_tp = ttyalloc(); 129136454Sphk dev->si_tty = ofw_tp; 130136454Sphk ofw_tp->t_dev = dev; 131136454Sphk } 132136454Sphk tp = dev->si_tty; 13378346Sbenno 13478346Sbenno tp->t_oproc = ofw_tty_start; 13578346Sbenno tp->t_param = ofw_tty_param; 13678346Sbenno tp->t_stop = ofw_tty_stop; 13778346Sbenno tp->t_dev = dev; 13878346Sbenno 13978346Sbenno if ((tp->t_state & TS_ISOPEN) == 0) { 14078346Sbenno tp->t_state |= TS_CARR_ON; 141136680Sphk ttyconsolemode(tp, 0); 14278346Sbenno ttsetwater(tp); 14378346Sbenno 14478346Sbenno setuptimeout = 1; 14593593Sjhb } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 14678346Sbenno return (EBUSY); 14778346Sbenno } 14878346Sbenno 149130077Sphk error = ttyld_open(tp, dev); 15078346Sbenno 15178346Sbenno if (error == 0 && setuptimeout) { 152131016Sobrien polltime = hz / OFWCONS_POLL_HZ; 15378346Sbenno if (polltime < 1) { 15478346Sbenno polltime = 1; 15578346Sbenno } 15678346Sbenno 15778346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 15878346Sbenno } 15978346Sbenno 16078346Sbenno return (error); 16178346Sbenno} 16278346Sbenno 16378346Sbennostatic int 164130585Sphkofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td) 16578346Sbenno{ 16678346Sbenno int unit; 16778346Sbenno struct tty *tp; 16878346Sbenno 16978346Sbenno unit = minor(dev); 170136454Sphk tp = dev->si_tty; 17178346Sbenno 17278346Sbenno if (unit != 0) { 17378346Sbenno return (ENXIO); 17478346Sbenno } 17578346Sbenno 176131016Sobrien /* XXX Should be replaced with callout_stop(9) */ 177131016Sobrien untimeout(ofw_timeout, tp, ofw_timeouthandle); 178130077Sphk ttyld_close(tp, flag); 179132226Sphk tty_close(tp); 18078346Sbenno 18178346Sbenno return (0); 18278346Sbenno} 18378346Sbenno 18478346Sbenno 18578346Sbennostatic int 18678346Sbennoofw_tty_param(struct tty *tp, struct termios *t) 18778346Sbenno{ 18878346Sbenno 18978346Sbenno return (0); 19078346Sbenno} 19178346Sbenno 19278346Sbennostatic void 19378346Sbennoofw_tty_start(struct tty *tp) 19478346Sbenno{ 195131016Sobrien struct clist *cl; 196131016Sobrien int len; 197131016Sobrien u_char buf[OFBURSTLEN]; 19878346Sbenno 199131016Sobrien 200131016Sobrien if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 20178346Sbenno return; 20278346Sbenno 20378346Sbenno tp->t_state |= TS_BUSY; 204131016Sobrien cl = &tp->t_outq; 205131016Sobrien len = q_to_b(cl, buf, OFBURSTLEN); 206131016Sobrien OF_write(stdout, buf, len); 20778346Sbenno tp->t_state &= ~TS_BUSY; 20878346Sbenno 20978346Sbenno ttwwakeup(tp); 21078346Sbenno} 21178346Sbenno 21278346Sbennostatic void 21378346Sbennoofw_tty_stop(struct tty *tp, int flag) 21478346Sbenno{ 21578346Sbenno 21678346Sbenno if (tp->t_state & TS_BUSY) { 21778346Sbenno if ((tp->t_state & TS_TTSTOP) == 0) { 21878346Sbenno tp->t_state |= TS_FLUSH; 21978346Sbenno } 22078346Sbenno } 22178346Sbenno} 22278346Sbenno 22378346Sbennostatic void 22478346Sbennoofw_timeout(void *v) 22578346Sbenno{ 22678346Sbenno struct tty *tp; 22778346Sbenno int c; 22878346Sbenno 22978346Sbenno tp = (struct tty *)v; 23078346Sbenno 231111194Sphk while ((c = ofw_cons_checkc(NULL)) != -1) { 23278346Sbenno if (tp->t_state & TS_ISOPEN) { 233130077Sphk ttyld_rint(tp, c); 23478346Sbenno } 23578346Sbenno } 23678346Sbenno 23778346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 23878346Sbenno} 23978346Sbenno 24078346Sbennostatic void 24178346Sbennoofw_cons_probe(struct consdev *cp) 24278346Sbenno{ 24378346Sbenno int chosen; 24478346Sbenno 24578346Sbenno if ((chosen = OF_finddevice("/chosen")) == -1) { 24678346Sbenno cp->cn_pri = CN_DEAD; 24778346Sbenno return; 24878346Sbenno } 24978346Sbenno 25078346Sbenno if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 25178346Sbenno cp->cn_pri = CN_DEAD; 25278346Sbenno return; 25378346Sbenno } 25478346Sbenno 25578346Sbenno if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 25678346Sbenno cp->cn_pri = CN_DEAD; 25778346Sbenno return; 25878346Sbenno } 25978346Sbenno 260120542Sjake cp->cn_pri = CN_LOW; 26178346Sbenno} 26278346Sbenno 26378346Sbennostatic void 26478346Sbennoofw_cons_init(struct consdev *cp) 26578346Sbenno{ 26678346Sbenno 267120467Sphk /* XXX: This is the alias, but that should be good enough */ 268120467Sphk sprintf(cp->cn_name, "ofwcons"); 269107044Sjake cp->cn_tp = ofw_tp; 27078346Sbenno} 27178346Sbenno 27278346Sbennostatic int 273111194Sphkofw_cons_getc(struct consdev *cp) 27478346Sbenno{ 27578346Sbenno unsigned char ch; 27678346Sbenno int l; 27778346Sbenno 27878346Sbenno ch = '\0'; 27978346Sbenno 28078346Sbenno while ((l = OF_read(stdin, &ch, 1)) != 1) { 28178346Sbenno if (l != -2 && l != 0) { 28278346Sbenno return (-1); 28378346Sbenno } 28478346Sbenno } 28578346Sbenno 286131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 287131916Smarcel if (kdb_alt_break(ch, &alt_break_state)) 288131916Smarcel kdb_enter("Break sequence on console"); 289110509Sharti#endif 290110509Sharti 29178346Sbenno return (ch); 29278346Sbenno} 29378346Sbenno 29478346Sbennostatic int 295111194Sphkofw_cons_checkc(struct consdev *cp) 29678346Sbenno{ 29778346Sbenno unsigned char ch; 29878346Sbenno 29988792Sjake if (OF_read(stdin, &ch, 1) > 0) { 300131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 301131916Smarcel if (kdb_alt_break(ch, &alt_break_state)) 302131916Smarcel kdb_enter("Break sequence on console"); 303110509Sharti#endif 30478346Sbenno return (ch); 30578346Sbenno } 30678346Sbenno 30778346Sbenno return (-1); 30878346Sbenno} 30978346Sbenno 31078346Sbennostatic void 311111194Sphkofw_cons_putc(struct consdev *cp, int c) 31278346Sbenno{ 31378346Sbenno char cbuf; 31478346Sbenno 31578346Sbenno if (c == '\n') { 31678346Sbenno cbuf = '\r'; 31778346Sbenno OF_write(stdout, &cbuf, 1); 31878346Sbenno } 31978346Sbenno 32078346Sbenno cbuf = c; 32178346Sbenno OF_write(stdout, &cbuf, 1); 32278346Sbenno} 323