ofw_console.c revision 131916
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 131916 2004-07-10 21:07:44Z marcel $"); 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; 98120491Sphk dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", 99109921Sjake output); 100120491Sphk make_dev_alias(dev, "ofwcons"); 101107044Sjake } 10289115Sjake} 10389115Sjake 104126076SphkSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL) 10589115Sjake 10678346Sbennostatic int stdin; 10778346Sbennostatic int stdout; 10878346Sbenno 10978346Sbennostatic int 110130585Sphkofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 11178346Sbenno{ 11278346Sbenno struct tty *tp; 11378346Sbenno int unit; 11478346Sbenno int error, setuptimeout; 11578346Sbenno 11678346Sbenno error = 0; 11778346Sbenno setuptimeout = 0; 11878346Sbenno unit = minor(dev); 11978346Sbenno 12078346Sbenno tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp); 12178346Sbenno 12278346Sbenno tp->t_oproc = ofw_tty_start; 12378346Sbenno tp->t_param = ofw_tty_param; 12478346Sbenno tp->t_stop = ofw_tty_stop; 12578346Sbenno tp->t_dev = dev; 12678346Sbenno 12778346Sbenno if ((tp->t_state & TS_ISOPEN) == 0) { 12878346Sbenno tp->t_state |= TS_CARR_ON; 12978346Sbenno ttychars(tp); 13078346Sbenno tp->t_iflag = TTYDEF_IFLAG; 13178346Sbenno tp->t_oflag = TTYDEF_OFLAG; 132131016Sobrien tp->t_cflag = TTYDEF_CFLAG; 13378346Sbenno tp->t_lflag = TTYDEF_LFLAG; 13478346Sbenno tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 13578346Sbenno ttsetwater(tp); 13678346Sbenno 13778346Sbenno setuptimeout = 1; 13893593Sjhb } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 13978346Sbenno return (EBUSY); 14078346Sbenno } 14178346Sbenno 142130077Sphk error = ttyld_open(tp, dev); 14378346Sbenno 14478346Sbenno if (error == 0 && setuptimeout) { 145131016Sobrien polltime = hz / OFWCONS_POLL_HZ; 14678346Sbenno if (polltime < 1) { 14778346Sbenno polltime = 1; 14878346Sbenno } 14978346Sbenno 15078346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 15178346Sbenno } 15278346Sbenno 15378346Sbenno return (error); 15478346Sbenno} 15578346Sbenno 15678346Sbennostatic int 157130585Sphkofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td) 15878346Sbenno{ 15978346Sbenno int unit; 16078346Sbenno struct tty *tp; 16178346Sbenno 16278346Sbenno unit = minor(dev); 16378346Sbenno tp = ofw_tp; 16478346Sbenno 16578346Sbenno if (unit != 0) { 16678346Sbenno return (ENXIO); 16778346Sbenno } 16878346Sbenno 169131016Sobrien /* XXX Should be replaced with callout_stop(9) */ 170131016Sobrien untimeout(ofw_timeout, tp, ofw_timeouthandle); 171130077Sphk ttyld_close(tp, flag); 17278346Sbenno ttyclose(tp); 17378346Sbenno 17478346Sbenno return (0); 17578346Sbenno} 17678346Sbenno 17778346Sbenno 17878346Sbennostatic int 17978346Sbennoofw_tty_param(struct tty *tp, struct termios *t) 18078346Sbenno{ 18178346Sbenno 18278346Sbenno return (0); 18378346Sbenno} 18478346Sbenno 18578346Sbennostatic void 18678346Sbennoofw_tty_start(struct tty *tp) 18778346Sbenno{ 188131016Sobrien struct clist *cl; 189131016Sobrien int len; 190131016Sobrien u_char buf[OFBURSTLEN]; 19178346Sbenno 192131016Sobrien 193131016Sobrien if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 19478346Sbenno return; 19578346Sbenno 19678346Sbenno tp->t_state |= TS_BUSY; 197131016Sobrien cl = &tp->t_outq; 198131016Sobrien len = q_to_b(cl, buf, OFBURSTLEN); 199131016Sobrien OF_write(stdout, buf, len); 20078346Sbenno tp->t_state &= ~TS_BUSY; 20178346Sbenno 20278346Sbenno ttwwakeup(tp); 20378346Sbenno} 20478346Sbenno 20578346Sbennostatic void 20678346Sbennoofw_tty_stop(struct tty *tp, int flag) 20778346Sbenno{ 20878346Sbenno 20978346Sbenno if (tp->t_state & TS_BUSY) { 21078346Sbenno if ((tp->t_state & TS_TTSTOP) == 0) { 21178346Sbenno tp->t_state |= TS_FLUSH; 21278346Sbenno } 21378346Sbenno } 21478346Sbenno} 21578346Sbenno 21678346Sbennostatic void 21778346Sbennoofw_timeout(void *v) 21878346Sbenno{ 21978346Sbenno struct tty *tp; 22078346Sbenno int c; 22178346Sbenno 22278346Sbenno tp = (struct tty *)v; 22378346Sbenno 224111194Sphk while ((c = ofw_cons_checkc(NULL)) != -1) { 22578346Sbenno if (tp->t_state & TS_ISOPEN) { 226130077Sphk ttyld_rint(tp, c); 22778346Sbenno } 22878346Sbenno } 22978346Sbenno 23078346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 23178346Sbenno} 23278346Sbenno 23378346Sbennostatic void 23478346Sbennoofw_cons_probe(struct consdev *cp) 23578346Sbenno{ 23678346Sbenno int chosen; 23778346Sbenno 23878346Sbenno if ((chosen = OF_finddevice("/chosen")) == -1) { 23978346Sbenno cp->cn_pri = CN_DEAD; 24078346Sbenno return; 24178346Sbenno } 24278346Sbenno 24378346Sbenno if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 24478346Sbenno cp->cn_pri = CN_DEAD; 24578346Sbenno return; 24678346Sbenno } 24778346Sbenno 24878346Sbenno if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 24978346Sbenno cp->cn_pri = CN_DEAD; 25078346Sbenno return; 25178346Sbenno } 25278346Sbenno 253120542Sjake cp->cn_pri = CN_LOW; 25478346Sbenno} 25578346Sbenno 25678346Sbennostatic void 25778346Sbennoofw_cons_init(struct consdev *cp) 25878346Sbenno{ 25978346Sbenno 260120467Sphk /* XXX: This is the alias, but that should be good enough */ 261120467Sphk sprintf(cp->cn_name, "ofwcons"); 262107044Sjake cp->cn_tp = ofw_tp; 26378346Sbenno} 26478346Sbenno 26578346Sbennostatic int 266111194Sphkofw_cons_getc(struct consdev *cp) 26778346Sbenno{ 26878346Sbenno unsigned char ch; 26978346Sbenno int l; 27078346Sbenno 27178346Sbenno ch = '\0'; 27278346Sbenno 27378346Sbenno while ((l = OF_read(stdin, &ch, 1)) != 1) { 27478346Sbenno if (l != -2 && l != 0) { 27578346Sbenno return (-1); 27678346Sbenno } 27778346Sbenno } 27878346Sbenno 279131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 280131916Smarcel if (kdb_alt_break(ch, &alt_break_state)) 281131916Smarcel kdb_enter("Break sequence on console"); 282110509Sharti#endif 283110509Sharti 28478346Sbenno return (ch); 28578346Sbenno} 28678346Sbenno 28778346Sbennostatic int 288111194Sphkofw_cons_checkc(struct consdev *cp) 28978346Sbenno{ 29078346Sbenno unsigned char ch; 29178346Sbenno 29288792Sjake if (OF_read(stdin, &ch, 1) > 0) { 293131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 294131916Smarcel if (kdb_alt_break(ch, &alt_break_state)) 295131916Smarcel kdb_enter("Break sequence on console"); 296110509Sharti#endif 29778346Sbenno return (ch); 29878346Sbenno } 29978346Sbenno 30078346Sbenno return (-1); 30178346Sbenno} 30278346Sbenno 30378346Sbennostatic void 304111194Sphkofw_cons_putc(struct consdev *cp, int c) 30578346Sbenno{ 30678346Sbenno char cbuf; 30778346Sbenno 30878346Sbenno if (c == '\n') { 30978346Sbenno cbuf = '\r'; 31078346Sbenno OF_write(stdout, &cbuf, 1); 31178346Sbenno } 31278346Sbenno 31378346Sbenno cbuf = c; 31478346Sbenno OF_write(stdout, &cbuf, 1); 31578346Sbenno} 316