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$"); 2878346Sbenno 29131016Sobrien#include "opt_ofw.h" 30110509Sharti 3178346Sbenno#include <sys/param.h> 32131916Smarcel#include <sys/kdb.h> 3378346Sbenno#include <sys/kernel.h> 34164049Srwatson#include <sys/priv.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 51181905Sedstatic tsw_open_t ofwtty_open; 52181905Sedstatic tsw_close_t ofwtty_close; 53181905Sedstatic tsw_outwakeup_t ofwtty_outwakeup; 5478346Sbenno 55181905Sedstatic struct ttydevsw ofw_ttydevsw = { 56181905Sed .tsw_flags = TF_NOPREFIX, 57181905Sed .tsw_open = ofwtty_open, 58181905Sed .tsw_close = ofwtty_close, 59181905Sed .tsw_outwakeup = ofwtty_outwakeup, 6078346Sbenno}; 6178346Sbenno 6278346Sbennostatic int polltime; 6378346Sbennostatic struct callout_handle ofw_timeouthandle 6478346Sbenno = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); 6578346Sbenno 66225203Srwatson#if defined(KDB) 67110509Shartistatic int alt_break_state; 68110509Sharti#endif 69110509Sharti 7078346Sbennostatic void ofw_timeout(void *); 7178346Sbenno 72158964Sphkstatic cn_probe_t ofw_cnprobe; 73158964Sphkstatic cn_init_t ofw_cninit; 74158964Sphkstatic cn_term_t ofw_cnterm; 75158964Sphkstatic cn_getc_t ofw_cngetc; 76158964Sphkstatic cn_putc_t ofw_cnputc; 77235405Savgstatic cn_grab_t ofw_cngrab; 78235405Savgstatic cn_ungrab_t ofw_cnungrab; 7978346Sbenno 80159065SphkCONSOLE_DRIVER(ofw); 8178346Sbenno 8289115Sjakestatic void 8389115Sjakecn_drvinit(void *unused) 8489115Sjake{ 85107044Sjake phandle_t options; 86107044Sjake char output[32]; 87181905Sed struct tty *tp; 8889115Sjake 89120544Sjake if (ofw_consdev.cn_pri != CN_DEAD && 90120544Sjake ofw_consdev.cn_name[0] != '\0') { 91107044Sjake if ((options = OF_finddevice("/options")) == -1 || 92107044Sjake OF_getprop(options, "output-device", output, 93107044Sjake sizeof(output)) == -1) 94107044Sjake return; 95136454Sphk /* 96136454Sphk * XXX: This is a hack and it may result in two /dev/ttya 97136454Sphk * XXX: devices on platforms where the sab driver works. 98136454Sphk */ 99193018Sed tp = tty_alloc(&ofw_ttydevsw, NULL); 100181905Sed tty_makedev(tp, NULL, "%s", output); 101181905Sed tty_makealias(tp, "ofwcons"); 102107044Sjake } 10389115Sjake} 10489115Sjake 105177253SrwatsonSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 10689115Sjake 10778346Sbennostatic int stdin; 10878346Sbennostatic int stdout; 10978346Sbenno 11078346Sbennostatic int 111181905Sedofwtty_open(struct tty *tp) 11278346Sbenno{ 113181905Sed polltime = hz / OFWCONS_POLL_HZ; 114181905Sed if (polltime < 1) 115181905Sed polltime = 1; 11678346Sbenno 117181905Sed ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 11878346Sbenno 119181905Sed return (0); 12078346Sbenno} 12178346Sbenno 122181905Sedstatic void 123181905Sedofwtty_close(struct tty *tp) 12478346Sbenno{ 12578346Sbenno 126131016Sobrien /* XXX Should be replaced with callout_stop(9) */ 127131016Sobrien untimeout(ofw_timeout, tp, ofw_timeouthandle); 12878346Sbenno} 12978346Sbenno 13078346Sbennostatic void 131181905Sedofwtty_outwakeup(struct tty *tp) 13278346Sbenno{ 133131016Sobrien int len; 134131016Sobrien u_char buf[OFBURSTLEN]; 13578346Sbenno 136181905Sed for (;;) { 137181905Sed len = ttydisc_getc(tp, buf, sizeof buf); 138181905Sed if (len == 0) 139181905Sed break; 140181905Sed OF_write(stdout, buf, len); 14178346Sbenno } 14278346Sbenno} 14378346Sbenno 14478346Sbennostatic void 14578346Sbennoofw_timeout(void *v) 14678346Sbenno{ 14778346Sbenno struct tty *tp; 14878346Sbenno int c; 14978346Sbenno 15078346Sbenno tp = (struct tty *)v; 15178346Sbenno 152181905Sed tty_lock(tp); 153181905Sed while ((c = ofw_cngetc(NULL)) != -1) 154181905Sed ttydisc_rint(tp, c, 0); 155181905Sed ttydisc_rint_done(tp); 156181905Sed tty_unlock(tp); 15778346Sbenno 15878346Sbenno ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 15978346Sbenno} 16078346Sbenno 16178346Sbennostatic void 162159065Sphkofw_cnprobe(struct consdev *cp) 16378346Sbenno{ 16478346Sbenno int chosen; 16578346Sbenno 16678346Sbenno if ((chosen = OF_finddevice("/chosen")) == -1) { 16778346Sbenno cp->cn_pri = CN_DEAD; 16878346Sbenno return; 16978346Sbenno } 17078346Sbenno 17178346Sbenno if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 17278346Sbenno cp->cn_pri = CN_DEAD; 17378346Sbenno return; 17478346Sbenno } 17578346Sbenno 17678346Sbenno if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 17778346Sbenno cp->cn_pri = CN_DEAD; 17878346Sbenno return; 17978346Sbenno } 18078346Sbenno 181120542Sjake cp->cn_pri = CN_LOW; 18278346Sbenno} 18378346Sbenno 18478346Sbennostatic void 185158964Sphkofw_cninit(struct consdev *cp) 18678346Sbenno{ 18778346Sbenno 188120467Sphk /* XXX: This is the alias, but that should be good enough */ 189184329Sed strcpy(cp->cn_name, "ofwcons"); 19078346Sbenno} 19178346Sbenno 192158964Sphkstatic void 193159065Sphkofw_cnterm(struct consdev *cp) 19478346Sbenno{ 19578346Sbenno} 19678346Sbenno 197235405Savgstatic void 198235405Savgofw_cngrab(struct consdev *cp) 199235405Savg{ 200235405Savg} 201235405Savg 202235405Savgstatic void 203235405Savgofw_cnungrab(struct consdev *cp) 204235405Savg{ 205235405Savg} 206235405Savg 20778346Sbennostatic int 208158964Sphkofw_cngetc(struct consdev *cp) 20978346Sbenno{ 21078346Sbenno unsigned char ch; 21178346Sbenno 21288792Sjake if (OF_read(stdin, &ch, 1) > 0) { 213225203Srwatson#if defined(KDB) 214225203Srwatson kdb_alt_break(ch, &alt_break_state); 215110509Sharti#endif 21678346Sbenno return (ch); 21778346Sbenno } 21878346Sbenno 21978346Sbenno return (-1); 22078346Sbenno} 22178346Sbenno 22278346Sbennostatic void 223158964Sphkofw_cnputc(struct consdev *cp, int c) 22478346Sbenno{ 22578346Sbenno char cbuf; 22678346Sbenno 22778346Sbenno if (c == '\n') { 22878346Sbenno cbuf = '\r'; 22978346Sbenno OF_write(stdout, &cbuf, 1); 23078346Sbenno } 23178346Sbenno 23278346Sbenno cbuf = c; 23378346Sbenno OF_write(stdout, &cbuf, 1); 23478346Sbenno} 235