ofw_console.c revision 158964
1139749Simp/*- 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 158964 2006-05-26 18:25:34Z 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 76158964Sphkstatic cn_probe_t ofw_cnprobe; 77158964Sphkstatic cn_init_t ofw_cninit; 78158964Sphkstatic cn_term_t ofw_cnterm; 79158964Sphkstatic cn_getc_t ofw_cngetc; 80158964Sphkstatic cn_putc_t ofw_cnputc; 8178346Sbenno 82158964SphkCONSOLE_DRIVER(ofw) 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 14378346Sbenno setuptimeout = 1; 14493593Sjhb } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 14578346Sbenno return (EBUSY); 14678346Sbenno } 14778346Sbenno 148130077Sphk error = ttyld_open(tp, dev); 14978346Sbenno 15078346Sbenno if (error == 0 && setuptimeout) { 151131016Sobrien polltime = hz / OFWCONS_POLL_HZ; 15278346Sbenno if (polltime < 1) { 15378346Sbenno polltime = 1; 15478346Sbenno } 15578346Sbenno 15678346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 15778346Sbenno } 15878346Sbenno 15978346Sbenno return (error); 16078346Sbenno} 16178346Sbenno 16278346Sbennostatic int 163130585Sphkofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td) 16478346Sbenno{ 16578346Sbenno int unit; 16678346Sbenno struct tty *tp; 16778346Sbenno 16878346Sbenno unit = minor(dev); 169136454Sphk tp = dev->si_tty; 17078346Sbenno 17178346Sbenno if (unit != 0) { 17278346Sbenno return (ENXIO); 17378346Sbenno } 17478346Sbenno 175131016Sobrien /* XXX Should be replaced with callout_stop(9) */ 176131016Sobrien untimeout(ofw_timeout, tp, ofw_timeouthandle); 177130077Sphk ttyld_close(tp, flag); 178132226Sphk tty_close(tp); 17978346Sbenno 18078346Sbenno return (0); 18178346Sbenno} 18278346Sbenno 18378346Sbenno 18478346Sbennostatic int 18578346Sbennoofw_tty_param(struct tty *tp, struct termios *t) 18678346Sbenno{ 18778346Sbenno 18878346Sbenno return (0); 18978346Sbenno} 19078346Sbenno 19178346Sbennostatic void 19278346Sbennoofw_tty_start(struct tty *tp) 19378346Sbenno{ 194131016Sobrien struct clist *cl; 195131016Sobrien int len; 196131016Sobrien u_char buf[OFBURSTLEN]; 19778346Sbenno 198131016Sobrien 199131016Sobrien if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 20078346Sbenno return; 20178346Sbenno 20278346Sbenno tp->t_state |= TS_BUSY; 203131016Sobrien cl = &tp->t_outq; 204131016Sobrien len = q_to_b(cl, buf, OFBURSTLEN); 205131016Sobrien OF_write(stdout, buf, len); 20678346Sbenno tp->t_state &= ~TS_BUSY; 20778346Sbenno 20878346Sbenno ttwwakeup(tp); 20978346Sbenno} 21078346Sbenno 21178346Sbennostatic void 21278346Sbennoofw_tty_stop(struct tty *tp, int flag) 21378346Sbenno{ 21478346Sbenno 21578346Sbenno if (tp->t_state & TS_BUSY) { 21678346Sbenno if ((tp->t_state & TS_TTSTOP) == 0) { 21778346Sbenno tp->t_state |= TS_FLUSH; 21878346Sbenno } 21978346Sbenno } 22078346Sbenno} 22178346Sbenno 22278346Sbennostatic void 22378346Sbennoofw_timeout(void *v) 22478346Sbenno{ 22578346Sbenno struct tty *tp; 22678346Sbenno int c; 22778346Sbenno 22878346Sbenno tp = (struct tty *)v; 22978346Sbenno 230111194Sphk while ((c = ofw_cons_checkc(NULL)) != -1) { 23178346Sbenno if (tp->t_state & TS_ISOPEN) { 232130077Sphk ttyld_rint(tp, c); 23378346Sbenno } 23478346Sbenno } 23578346Sbenno 23678346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 23778346Sbenno} 23878346Sbenno 23978346Sbennostatic void 24078346Sbennoofw_cons_probe(struct consdev *cp) 24178346Sbenno{ 24278346Sbenno int chosen; 24378346Sbenno 24478346Sbenno if ((chosen = OF_finddevice("/chosen")) == -1) { 24578346Sbenno cp->cn_pri = CN_DEAD; 24678346Sbenno return; 24778346Sbenno } 24878346Sbenno 24978346Sbenno if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 25078346Sbenno cp->cn_pri = CN_DEAD; 25178346Sbenno return; 25278346Sbenno } 25378346Sbenno 25478346Sbenno if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 25578346Sbenno cp->cn_pri = CN_DEAD; 25678346Sbenno return; 25778346Sbenno } 25878346Sbenno 259120542Sjake cp->cn_pri = CN_LOW; 26078346Sbenno} 26178346Sbenno 26278346Sbennostatic void 263158964Sphkofw_cninit(struct consdev *cp) 26478346Sbenno{ 26578346Sbenno 266120467Sphk /* XXX: This is the alias, but that should be good enough */ 267120467Sphk sprintf(cp->cn_name, "ofwcons"); 268107044Sjake cp->cn_tp = ofw_tp; 26978346Sbenno} 27078346Sbenno 271158964Sphkstatic void 272158964Sphkofw_cneterm(struct consdev *cp) 27378346Sbenno{ 27478346Sbenno} 27578346Sbenno 27678346Sbennostatic int 277158964Sphkofw_cngetc(struct consdev *cp) 27878346Sbenno{ 27978346Sbenno unsigned char ch; 28078346Sbenno 28188792Sjake if (OF_read(stdin, &ch, 1) > 0) { 282131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 283131916Smarcel if (kdb_alt_break(ch, &alt_break_state)) 284131916Smarcel kdb_enter("Break sequence on console"); 285110509Sharti#endif 28678346Sbenno return (ch); 28778346Sbenno } 28878346Sbenno 28978346Sbenno return (-1); 29078346Sbenno} 29178346Sbenno 29278346Sbennostatic void 293158964Sphkofw_cnputc(struct consdev *cp, int c) 29478346Sbenno{ 29578346Sbenno char cbuf; 29678346Sbenno 29778346Sbenno if (c == '\n') { 29878346Sbenno cbuf = '\r'; 29978346Sbenno OF_write(stdout, &cbuf, 1); 30078346Sbenno } 30178346Sbenno 30278346Sbenno cbuf = c; 30378346Sbenno OF_write(stdout, &cbuf, 1); 30478346Sbenno} 305