1098ca2bdSWarner Losh /*- 2707fed20SBenno Rice * Copyright (C) 2001 Benno Rice. 3707fed20SBenno Rice * All rights reserved. 4707fed20SBenno Rice * 5707fed20SBenno Rice * Redistribution and use in source and binary forms, with or without 6707fed20SBenno Rice * modification, are permitted provided that the following conditions 7707fed20SBenno Rice * are met: 8707fed20SBenno Rice * 1. Redistributions of source code must retain the above copyright 9707fed20SBenno Rice * notice, this list of conditions and the following disclaimer. 10707fed20SBenno Rice * 2. Redistributions in binary form must reproduce the above copyright 11707fed20SBenno Rice * notice, this list of conditions and the following disclaimer in the 12707fed20SBenno Rice * documentation and/or other materials provided with the distribution. 13707fed20SBenno Rice * 14707fed20SBenno Rice * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15707fed20SBenno Rice * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16707fed20SBenno Rice * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17707fed20SBenno Rice * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18707fed20SBenno Rice * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19707fed20SBenno Rice * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20707fed20SBenno Rice * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21707fed20SBenno Rice * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22707fed20SBenno Rice * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23707fed20SBenno Rice * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24707fed20SBenno Rice */ 25707fed20SBenno Rice 268368cf8fSDavid E. O'Brien #include <sys/cdefs.h> 278368cf8fSDavid E. O'Brien __FBSDID("$FreeBSD$"); 28707fed20SBenno Rice 29761f89f9SHartmut Brandt #include "opt_comconsole.h" 30a82b25f9SDavid E. O'Brien #include "opt_ofw.h" 31761f89f9SHartmut Brandt 32707fed20SBenno Rice #include <sys/param.h> 338cabb94fSMarcel Moolenaar #include <sys/kdb.h> 34707fed20SBenno Rice #include <sys/kernel.h> 3543593547SRobert Watson #include <sys/priv.h> 36707fed20SBenno Rice #include <sys/systm.h> 37707fed20SBenno Rice #include <sys/types.h> 38707fed20SBenno Rice #include <sys/conf.h> 39707fed20SBenno Rice #include <sys/cons.h> 40707fed20SBenno Rice #include <sys/consio.h> 41707fed20SBenno Rice #include <sys/tty.h> 42707fed20SBenno Rice 43707fed20SBenno Rice #include <dev/ofw/openfirm.h> 44707fed20SBenno Rice 45761f89f9SHartmut Brandt #include <ddb/ddb.h> 46761f89f9SHartmut Brandt 47a82b25f9SDavid E. O'Brien #ifndef OFWCONS_POLL_HZ 48a82b25f9SDavid E. O'Brien #define OFWCONS_POLL_HZ 4 /* 50-100 works best on Ultra2 */ 49a82b25f9SDavid E. O'Brien #endif 50a82b25f9SDavid E. O'Brien #define OFBURSTLEN 128 /* max number of bytes to write in one chunk */ 51707fed20SBenno Rice 52bc093719SEd Schouten static tsw_open_t ofwtty_open; 53bc093719SEd Schouten static tsw_close_t ofwtty_close; 54bc093719SEd Schouten static tsw_outwakeup_t ofwtty_outwakeup; 55707fed20SBenno Rice 56bc093719SEd Schouten static struct ttydevsw ofw_ttydevsw = { 57bc093719SEd Schouten .tsw_flags = TF_NOPREFIX, 58bc093719SEd Schouten .tsw_open = ofwtty_open, 59bc093719SEd Schouten .tsw_close = ofwtty_close, 60bc093719SEd Schouten .tsw_outwakeup = ofwtty_outwakeup, 61707fed20SBenno Rice }; 62707fed20SBenno Rice 63707fed20SBenno Rice static struct tty *ofw_tp = NULL; 64707fed20SBenno Rice static int polltime; 65707fed20SBenno Rice static struct callout_handle ofw_timeouthandle 66707fed20SBenno Rice = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); 67707fed20SBenno Rice 688cabb94fSMarcel Moolenaar #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 69761f89f9SHartmut Brandt static int alt_break_state; 70761f89f9SHartmut Brandt #endif 71761f89f9SHartmut Brandt 72707fed20SBenno Rice static void ofw_timeout(void *); 73707fed20SBenno Rice 7405c3592eSPoul-Henning Kamp static cn_probe_t ofw_cnprobe; 7505c3592eSPoul-Henning Kamp static cn_init_t ofw_cninit; 7605c3592eSPoul-Henning Kamp static cn_term_t ofw_cnterm; 7705c3592eSPoul-Henning Kamp static cn_getc_t ofw_cngetc; 7805c3592eSPoul-Henning Kamp static cn_putc_t ofw_cnputc; 79707fed20SBenno Rice 8077dfeeadSPoul-Henning Kamp CONSOLE_DRIVER(ofw); 81707fed20SBenno Rice 8247a1c915SJake Burkholder static void 8347a1c915SJake Burkholder cn_drvinit(void *unused) 8447a1c915SJake Burkholder { 85a121cb6aSJake Burkholder phandle_t options; 86a121cb6aSJake Burkholder char output[32]; 87bc093719SEd Schouten struct tty *tp; 8847a1c915SJake Burkholder 89278667afSJake Burkholder if (ofw_consdev.cn_pri != CN_DEAD && 90278667afSJake Burkholder ofw_consdev.cn_name[0] != '\0') { 91a121cb6aSJake Burkholder if ((options = OF_finddevice("/options")) == -1 || 92a121cb6aSJake Burkholder OF_getprop(options, "output-device", output, 93a121cb6aSJake Burkholder sizeof(output)) == -1) 94a121cb6aSJake Burkholder return; 95c5c5a2adSPoul-Henning Kamp /* 96c5c5a2adSPoul-Henning Kamp * XXX: This is a hack and it may result in two /dev/ttya 97c5c5a2adSPoul-Henning Kamp * XXX: devices on platforms where the sab driver works. 98c5c5a2adSPoul-Henning Kamp */ 99bc093719SEd Schouten tp = tty_alloc(&ofw_ttydevsw, NULL, NULL); 100bc093719SEd Schouten tty_makedev(tp, NULL, "%s", output); 101bc093719SEd Schouten tty_makealias(tp, "ofwcons"); 102a121cb6aSJake Burkholder } 10347a1c915SJake Burkholder } 10447a1c915SJake Burkholder 105237fdd78SRobert Watson SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 10647a1c915SJake Burkholder 107707fed20SBenno Rice static int stdin; 108707fed20SBenno Rice static int stdout; 109707fed20SBenno Rice 110707fed20SBenno Rice static int 111bc093719SEd Schouten ofwtty_open(struct tty *tp) 112707fed20SBenno Rice { 113a82b25f9SDavid E. O'Brien polltime = hz / OFWCONS_POLL_HZ; 114bc093719SEd Schouten if (polltime < 1) 115707fed20SBenno Rice polltime = 1; 116707fed20SBenno Rice 117707fed20SBenno Rice ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 118bc093719SEd Schouten 119bc093719SEd Schouten return (0); 120707fed20SBenno Rice } 121707fed20SBenno Rice 122bc093719SEd Schouten static void 123bc093719SEd Schouten ofwtty_close(struct tty *tp) 124707fed20SBenno Rice { 125707fed20SBenno Rice 126a82b25f9SDavid E. O'Brien /* XXX Should be replaced with callout_stop(9) */ 127a82b25f9SDavid E. O'Brien untimeout(ofw_timeout, tp, ofw_timeouthandle); 128707fed20SBenno Rice } 129707fed20SBenno Rice 130707fed20SBenno Rice static void 131bc093719SEd Schouten ofwtty_outwakeup(struct tty *tp) 132707fed20SBenno Rice { 133a82b25f9SDavid E. O'Brien int len; 134a82b25f9SDavid E. O'Brien u_char buf[OFBURSTLEN]; 135707fed20SBenno Rice 136bc093719SEd Schouten for (;;) { 137bc093719SEd Schouten len = ttydisc_getc(tp, buf, sizeof buf); 138bc093719SEd Schouten if (len == 0) 139bc093719SEd Schouten break; 140a82b25f9SDavid E. O'Brien OF_write(stdout, buf, len); 141707fed20SBenno Rice } 142707fed20SBenno Rice } 143707fed20SBenno Rice 144707fed20SBenno Rice static void 145707fed20SBenno Rice ofw_timeout(void *v) 146707fed20SBenno Rice { 147707fed20SBenno Rice struct tty *tp; 148707fed20SBenno Rice int c; 149707fed20SBenno Rice 150707fed20SBenno Rice tp = (struct tty *)v; 151707fed20SBenno Rice 152bc093719SEd Schouten tty_lock(tp); 153bc093719SEd Schouten while ((c = ofw_cngetc(NULL)) != -1) 154bc093719SEd Schouten ttydisc_rint(tp, c, 0); 155bc093719SEd Schouten ttydisc_rint_done(tp); 156bc093719SEd Schouten tty_unlock(tp); 157707fed20SBenno Rice 158707fed20SBenno Rice ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 159707fed20SBenno Rice } 160707fed20SBenno Rice 161707fed20SBenno Rice static void 16277dfeeadSPoul-Henning Kamp ofw_cnprobe(struct consdev *cp) 163707fed20SBenno Rice { 164707fed20SBenno Rice int chosen; 165707fed20SBenno Rice 166707fed20SBenno Rice if ((chosen = OF_finddevice("/chosen")) == -1) { 167707fed20SBenno Rice cp->cn_pri = CN_DEAD; 168707fed20SBenno Rice return; 169707fed20SBenno Rice } 170707fed20SBenno Rice 171707fed20SBenno Rice if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 172707fed20SBenno Rice cp->cn_pri = CN_DEAD; 173707fed20SBenno Rice return; 174707fed20SBenno Rice } 175707fed20SBenno Rice 176707fed20SBenno Rice if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 177707fed20SBenno Rice cp->cn_pri = CN_DEAD; 178707fed20SBenno Rice return; 179707fed20SBenno Rice } 180707fed20SBenno Rice 1815dbb0622SJake Burkholder cp->cn_pri = CN_LOW; 182707fed20SBenno Rice } 183707fed20SBenno Rice 184707fed20SBenno Rice static void 18505c3592eSPoul-Henning Kamp ofw_cninit(struct consdev *cp) 186707fed20SBenno Rice { 187707fed20SBenno Rice 1882f06c3e7SPoul-Henning Kamp /* XXX: This is the alias, but that should be good enough */ 1892f06c3e7SPoul-Henning Kamp sprintf(cp->cn_name, "ofwcons"); 190a121cb6aSJake Burkholder cp->cn_tp = ofw_tp; 191707fed20SBenno Rice } 192707fed20SBenno Rice 19305c3592eSPoul-Henning Kamp static void 19477dfeeadSPoul-Henning Kamp ofw_cnterm(struct consdev *cp) 195707fed20SBenno Rice { 196707fed20SBenno Rice } 197707fed20SBenno Rice 198707fed20SBenno Rice static int 19905c3592eSPoul-Henning Kamp ofw_cngetc(struct consdev *cp) 200707fed20SBenno Rice { 201707fed20SBenno Rice unsigned char ch; 202707fed20SBenno Rice 203cbecdd57SJake Burkholder if (OF_read(stdin, &ch, 1) > 0) { 2048cabb94fSMarcel Moolenaar #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 20543d7128cSPeter Wemm int kdb_brk; 20643d7128cSPeter Wemm 20743d7128cSPeter Wemm if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { 20843d7128cSPeter Wemm switch (kdb_brk) { 20943d7128cSPeter Wemm case KDB_REQ_DEBUGGER: 21043d7128cSPeter Wemm kdb_enter(KDB_WHY_BREAK, 21143d7128cSPeter Wemm "Break sequence on console"); 21243d7128cSPeter Wemm break; 21343d7128cSPeter Wemm case KDB_REQ_PANIC: 21443d7128cSPeter Wemm kdb_panic("Panic sequence on console"); 21543d7128cSPeter Wemm break; 21643d7128cSPeter Wemm case KDB_REQ_REBOOT: 21743d7128cSPeter Wemm kdb_reboot(); 21843d7128cSPeter Wemm break; 21943d7128cSPeter Wemm 22043d7128cSPeter Wemm } 22143d7128cSPeter Wemm } 222761f89f9SHartmut Brandt #endif 223707fed20SBenno Rice return (ch); 224707fed20SBenno Rice } 225707fed20SBenno Rice 226707fed20SBenno Rice return (-1); 227707fed20SBenno Rice } 228707fed20SBenno Rice 229707fed20SBenno Rice static void 23005c3592eSPoul-Henning Kamp ofw_cnputc(struct consdev *cp, int c) 231707fed20SBenno Rice { 232707fed20SBenno Rice char cbuf; 233707fed20SBenno Rice 234707fed20SBenno Rice if (c == '\n') { 235707fed20SBenno Rice cbuf = '\r'; 236707fed20SBenno Rice OF_write(stdout, &cbuf, 1); 237707fed20SBenno Rice } 238707fed20SBenno Rice 239707fed20SBenno Rice cbuf = c; 240707fed20SBenno Rice OF_write(stdout, &cbuf, 1); 241707fed20SBenno Rice } 242