ofw_console.c revision 130585
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 130585 2004-06-16 09:47:26Z phk $"); 2878346Sbenno 29110509Sharti#include "opt_ddb.h" 30110509Sharti#include "opt_comconsole.h" 31110509Sharti 3278346Sbenno#include <sys/param.h> 3378346Sbenno#include <sys/kernel.h> 3478346Sbenno#include <sys/systm.h> 3578346Sbenno#include <sys/types.h> 3678346Sbenno#include <sys/conf.h> 3778346Sbenno#include <sys/cons.h> 3878346Sbenno#include <sys/consio.h> 3978346Sbenno#include <sys/tty.h> 4078346Sbenno 4178346Sbenno#include <dev/ofw/openfirm.h> 4278346Sbenno 43110509Sharti#include <ddb/ddb.h> 44110509Sharti 4588792Sjake#define OFW_POLL_HZ 4 4678346Sbenno 4778346Sbennostatic d_open_t ofw_dev_open; 4878346Sbennostatic d_close_t ofw_dev_close; 4978346Sbenno 5078346Sbennostatic struct cdevsw ofw_cdevsw = { 51126080Sphk .d_version = D_VERSION, 52111815Sphk .d_open = ofw_dev_open, 53111815Sphk .d_close = ofw_dev_close, 54111815Sphk .d_name = "ofw", 55126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 5678346Sbenno}; 5778346Sbenno 5878346Sbennostatic struct tty *ofw_tp = NULL; 5978346Sbennostatic int polltime; 6078346Sbennostatic struct callout_handle ofw_timeouthandle 6178346Sbenno = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); 6278346Sbenno 63110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 64110509Shartistatic int alt_break_state; 65110509Sharti#endif 66110509Sharti 6778346Sbennostatic void ofw_tty_start(struct tty *); 6878346Sbennostatic int ofw_tty_param(struct tty *, struct termios *); 6978346Sbennostatic void ofw_tty_stop(struct tty *, int); 7078346Sbennostatic void ofw_timeout(void *); 7178346Sbenno 7278346Sbennostatic cn_probe_t ofw_cons_probe; 7378346Sbennostatic cn_init_t ofw_cons_init; 7478346Sbennostatic cn_getc_t ofw_cons_getc; 7578346Sbennostatic cn_checkc_t ofw_cons_checkc; 7678346Sbennostatic cn_putc_t ofw_cons_putc; 7778346Sbenno 7878346SbennoCONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc, 7978346Sbenno ofw_cons_checkc, ofw_cons_putc, NULL); 8078346Sbenno 8189115Sjakestatic void 8289115Sjakecn_drvinit(void *unused) 8389115Sjake{ 84107044Sjake phandle_t options; 85107044Sjake char output[32]; 86130585Sphk struct cdev *dev; 8789115Sjake 88120544Sjake if (ofw_consdev.cn_pri != CN_DEAD && 89120544Sjake ofw_consdev.cn_name[0] != '\0') { 90107044Sjake if ((options = OF_finddevice("/options")) == -1 || 91107044Sjake OF_getprop(options, "output-device", output, 92107044Sjake sizeof(output)) == -1) 93107044Sjake return; 94120491Sphk dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", 95109921Sjake output); 96120491Sphk make_dev_alias(dev, "ofwcons"); 97107044Sjake } 9889115Sjake} 9989115Sjake 100126076SphkSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL) 10189115Sjake 10278346Sbennostatic int stdin; 10378346Sbennostatic int stdout; 10478346Sbenno 10578346Sbennostatic int 106130585Sphkofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 10778346Sbenno{ 10878346Sbenno struct tty *tp; 10978346Sbenno int unit; 11078346Sbenno int error, setuptimeout; 11178346Sbenno 11278346Sbenno error = 0; 11378346Sbenno setuptimeout = 0; 11478346Sbenno unit = minor(dev); 11578346Sbenno 11678346Sbenno tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp); 11778346Sbenno 11878346Sbenno tp->t_oproc = ofw_tty_start; 11978346Sbenno tp->t_param = ofw_tty_param; 12078346Sbenno tp->t_stop = ofw_tty_stop; 12178346Sbenno tp->t_dev = dev; 12278346Sbenno 12378346Sbenno if ((tp->t_state & TS_ISOPEN) == 0) { 12478346Sbenno tp->t_state |= TS_CARR_ON; 12578346Sbenno ttychars(tp); 12678346Sbenno tp->t_iflag = TTYDEF_IFLAG; 12778346Sbenno tp->t_oflag = TTYDEF_OFLAG; 12878346Sbenno tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 12978346Sbenno tp->t_lflag = TTYDEF_LFLAG; 13078346Sbenno tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 13178346Sbenno ttsetwater(tp); 13278346Sbenno 13378346Sbenno setuptimeout = 1; 13493593Sjhb } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 13578346Sbenno return (EBUSY); 13678346Sbenno } 13778346Sbenno 138130077Sphk error = ttyld_open(tp, dev); 13978346Sbenno 14078346Sbenno if (error == 0 && setuptimeout) { 14178346Sbenno polltime = hz / OFW_POLL_HZ; 14278346Sbenno if (polltime < 1) { 14378346Sbenno polltime = 1; 14478346Sbenno } 14578346Sbenno 14678346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 14778346Sbenno } 14878346Sbenno 14978346Sbenno return (error); 15078346Sbenno} 15178346Sbenno 15278346Sbennostatic int 153130585Sphkofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td) 15478346Sbenno{ 15578346Sbenno int unit; 15678346Sbenno struct tty *tp; 15778346Sbenno 15878346Sbenno unit = minor(dev); 15978346Sbenno tp = ofw_tp; 16078346Sbenno 16178346Sbenno if (unit != 0) { 16278346Sbenno return (ENXIO); 16378346Sbenno } 16478346Sbenno 165130077Sphk ttyld_close(tp, flag); 16678346Sbenno ttyclose(tp); 16778346Sbenno 16878346Sbenno return (0); 16978346Sbenno} 17078346Sbenno 17178346Sbenno 17278346Sbennostatic int 17378346Sbennoofw_tty_param(struct tty *tp, struct termios *t) 17478346Sbenno{ 17578346Sbenno 17678346Sbenno return (0); 17778346Sbenno} 17878346Sbenno 17978346Sbennostatic void 18078346Sbennoofw_tty_start(struct tty *tp) 18178346Sbenno{ 18278346Sbenno 18378346Sbenno if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 18478346Sbenno ttwwakeup(tp); 18578346Sbenno return; 18678346Sbenno } 18778346Sbenno 18878346Sbenno tp->t_state |= TS_BUSY; 18978346Sbenno while (tp->t_outq.c_cc != 0) { 190111194Sphk ofw_cons_putc(NULL, getc(&tp->t_outq)); 19178346Sbenno } 19278346Sbenno tp->t_state &= ~TS_BUSY; 19378346Sbenno 19478346Sbenno ttwwakeup(tp); 19578346Sbenno} 19678346Sbenno 19778346Sbennostatic void 19878346Sbennoofw_tty_stop(struct tty *tp, int flag) 19978346Sbenno{ 20078346Sbenno 20178346Sbenno if (tp->t_state & TS_BUSY) { 20278346Sbenno if ((tp->t_state & TS_TTSTOP) == 0) { 20378346Sbenno tp->t_state |= TS_FLUSH; 20478346Sbenno } 20578346Sbenno } 20678346Sbenno} 20778346Sbenno 20878346Sbennostatic void 20978346Sbennoofw_timeout(void *v) 21078346Sbenno{ 21178346Sbenno struct tty *tp; 21278346Sbenno int c; 21378346Sbenno 21478346Sbenno tp = (struct tty *)v; 21578346Sbenno 216111194Sphk while ((c = ofw_cons_checkc(NULL)) != -1) { 21778346Sbenno if (tp->t_state & TS_ISOPEN) { 218130077Sphk ttyld_rint(tp, c); 21978346Sbenno } 22078346Sbenno } 22178346Sbenno 22278346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 22378346Sbenno} 22478346Sbenno 22578346Sbennostatic void 22678346Sbennoofw_cons_probe(struct consdev *cp) 22778346Sbenno{ 22878346Sbenno int chosen; 22978346Sbenno 23078346Sbenno if ((chosen = OF_finddevice("/chosen")) == -1) { 23178346Sbenno cp->cn_pri = CN_DEAD; 23278346Sbenno return; 23378346Sbenno } 23478346Sbenno 23578346Sbenno if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 23678346Sbenno cp->cn_pri = CN_DEAD; 23778346Sbenno return; 23878346Sbenno } 23978346Sbenno 24078346Sbenno if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 24178346Sbenno cp->cn_pri = CN_DEAD; 24278346Sbenno return; 24378346Sbenno } 24478346Sbenno 245120542Sjake cp->cn_pri = CN_LOW; 24678346Sbenno} 24778346Sbenno 24878346Sbennostatic void 24978346Sbennoofw_cons_init(struct consdev *cp) 25078346Sbenno{ 25178346Sbenno 252120467Sphk /* XXX: This is the alias, but that should be good enough */ 253120467Sphk sprintf(cp->cn_name, "ofwcons"); 254107044Sjake cp->cn_tp = ofw_tp; 25578346Sbenno} 25678346Sbenno 25778346Sbennostatic int 258111194Sphkofw_cons_getc(struct consdev *cp) 25978346Sbenno{ 26078346Sbenno unsigned char ch; 26178346Sbenno int l; 26278346Sbenno 26378346Sbenno ch = '\0'; 26478346Sbenno 26578346Sbenno while ((l = OF_read(stdin, &ch, 1)) != 1) { 26678346Sbenno if (l != -2 && l != 0) { 26778346Sbenno return (-1); 26878346Sbenno } 26978346Sbenno } 27078346Sbenno 271110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 272110509Sharti if (db_alt_break(ch, &alt_break_state)) 273110509Sharti breakpoint(); 274110509Sharti#endif 275110509Sharti 27678346Sbenno return (ch); 27778346Sbenno} 27878346Sbenno 27978346Sbennostatic int 280111194Sphkofw_cons_checkc(struct consdev *cp) 28178346Sbenno{ 28278346Sbenno unsigned char ch; 28378346Sbenno 28488792Sjake if (OF_read(stdin, &ch, 1) > 0) { 285110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 286110509Sharti if (db_alt_break(ch, &alt_break_state)) 287110509Sharti breakpoint(); 288110509Sharti#endif 28978346Sbenno return (ch); 29078346Sbenno } 29178346Sbenno 29278346Sbenno return (-1); 29378346Sbenno} 29478346Sbenno 29578346Sbennostatic void 296111194Sphkofw_cons_putc(struct consdev *cp, int c) 29778346Sbenno{ 29878346Sbenno char cbuf; 29978346Sbenno 30078346Sbenno if (c == '\n') { 30178346Sbenno cbuf = '\r'; 30278346Sbenno OF_write(stdout, &cbuf, 1); 30378346Sbenno } 30478346Sbenno 30578346Sbenno cbuf = c; 30678346Sbenno OF_write(stdout, &cbuf, 1); 30778346Sbenno} 308