1ae36cccdSWarner Losh /*- 2ae36cccdSWarner Losh * Copyright (c) 2007 Bruce M. Simpson. 3ae36cccdSWarner Losh * All rights reserved. 4ae36cccdSWarner Losh * 5ae36cccdSWarner Losh * Redistribution and use in source and binary forms, with or without 6ae36cccdSWarner Losh * modification, are permitted provided that the following conditions 7ae36cccdSWarner Losh * are met: 8ae36cccdSWarner Losh * 1. Redistributions of source code must retain the above copyright 9ae36cccdSWarner Losh * notice, this list of conditions and the following disclaimer. 10ae36cccdSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11ae36cccdSWarner Losh * notice, this list of conditions and the following disclaimer in the 12ae36cccdSWarner Losh * documentation and/or other materials provided with the distribution. 13ae36cccdSWarner Losh * 14ae36cccdSWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ae36cccdSWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ae36cccdSWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ae36cccdSWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ae36cccdSWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ae36cccdSWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ae36cccdSWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ae36cccdSWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ae36cccdSWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ae36cccdSWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ae36cccdSWarner Losh * SUCH DAMAGE. 25ae36cccdSWarner Losh */ 26ae36cccdSWarner Losh 27ae36cccdSWarner Losh #include <sys/cdefs.h> 28ae36cccdSWarner Losh __FBSDID("$FreeBSD$"); 29ae36cccdSWarner Losh 30ae36cccdSWarner Losh #include "opt_comconsole.h" 31ae36cccdSWarner Losh 32ae36cccdSWarner Losh #include <sys/param.h> 33ae36cccdSWarner Losh #include <sys/kdb.h> 34ae36cccdSWarner Losh #include <sys/kernel.h> 35ae36cccdSWarner Losh #include <sys/priv.h> 36ae36cccdSWarner Losh #include <sys/systm.h> 37ae36cccdSWarner Losh #include <sys/types.h> 38ae36cccdSWarner Losh #include <sys/conf.h> 39ae36cccdSWarner Losh #include <sys/cons.h> 40ae36cccdSWarner Losh #include <sys/consio.h> 41ae36cccdSWarner Losh #include <sys/tty.h> 42ae36cccdSWarner Losh 43ae36cccdSWarner Losh #include <dev/cfe/cfe_api.h> 44ae36cccdSWarner Losh #include <dev/cfe/cfe_error.h> 45ae36cccdSWarner Losh 46ae36cccdSWarner Losh #include <ddb/ddb.h> 47ae36cccdSWarner Losh 48ae36cccdSWarner Losh #ifndef CFECONS_POLL_HZ 498e8ee9aaSWarner Losh #define CFECONS_POLL_HZ 4 50ae36cccdSWarner Losh #endif 51ae36cccdSWarner Losh #define CFEBURSTLEN 128 /* max number of bytes to write in one chunk */ 52ae36cccdSWarner Losh 536f079ba1SWarner Losh static tsw_open_t cfe_tty_open; 546f079ba1SWarner Losh static tsw_close_t cfe_tty_close; 556f079ba1SWarner Losh static tsw_outwakeup_t cfe_tty_outwakeup; 56ae36cccdSWarner Losh 576f079ba1SWarner Losh static struct ttydevsw cfe_ttydevsw = { 586f079ba1SWarner Losh .tsw_flags = TF_NOPREFIX, 596f079ba1SWarner Losh .tsw_open = cfe_tty_open, 606f079ba1SWarner Losh .tsw_close = cfe_tty_close, 616f079ba1SWarner Losh .tsw_outwakeup = cfe_tty_outwakeup, 62ae36cccdSWarner Losh }; 63ae36cccdSWarner Losh 64ae36cccdSWarner Losh static int conhandle = -1; 65ae36cccdSWarner Losh static struct tty *cfe_tp = NULL; 66ae36cccdSWarner Losh /* XXX does cfe have to poll? */ 67ae36cccdSWarner Losh static int polltime; 68ae36cccdSWarner Losh static struct callout_handle cfe_timeouthandle 69ae36cccdSWarner Losh = CALLOUT_HANDLE_INITIALIZER(&cfe_timeouthandle); 70ae36cccdSWarner Losh 71ae36cccdSWarner Losh #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 72ae36cccdSWarner Losh static int alt_break_state; 73ae36cccdSWarner Losh #endif 74ae36cccdSWarner Losh 75ae36cccdSWarner Losh static void cfe_timeout(void *); 76ae36cccdSWarner Losh 77ae36cccdSWarner Losh static cn_probe_t cfe_cnprobe; 78ae36cccdSWarner Losh static cn_init_t cfe_cninit; 79ae36cccdSWarner Losh static cn_term_t cfe_cnterm; 80ae36cccdSWarner Losh static cn_getc_t cfe_cngetc; 81ae36cccdSWarner Losh static cn_putc_t cfe_cnputc; 82ae36cccdSWarner Losh 83ae36cccdSWarner Losh CONSOLE_DRIVER(cfe); 84ae36cccdSWarner Losh 85ae36cccdSWarner Losh static void 86ae36cccdSWarner Losh cn_drvinit(void *unused) 87ae36cccdSWarner Losh { 88ae36cccdSWarner Losh char output[32]; 896f079ba1SWarner Losh struct tty *tp; 90ae36cccdSWarner Losh 91ae36cccdSWarner Losh if (cfe_consdev.cn_pri != CN_DEAD && 92ae36cccdSWarner Losh cfe_consdev.cn_name[0] != '\0') { 936f079ba1SWarner Losh tp = tty_alloc(&cfe_ttydevsw, NULL, NULL); 946f079ba1SWarner Losh tty_makedev(tp, NULL, "%s", output); 956f079ba1SWarner Losh tty_makealias(tp, "cfecons"); 96ae36cccdSWarner Losh } 97ae36cccdSWarner Losh } 98ae36cccdSWarner Losh 99ae36cccdSWarner Losh static int 1006f079ba1SWarner Losh cfe_tty_open(struct tty *tp) 101ae36cccdSWarner Losh { 102ae36cccdSWarner Losh polltime = hz / CFECONS_POLL_HZ; 1036f079ba1SWarner Losh if (polltime < 1) 104ae36cccdSWarner Losh polltime = 1; 105ae36cccdSWarner Losh cfe_timeouthandle = timeout(cfe_timeout, tp, polltime); 1066f079ba1SWarner Losh 1076f079ba1SWarner Losh return (0); 108ae36cccdSWarner Losh } 109ae36cccdSWarner Losh 1106f079ba1SWarner Losh static void 1116f079ba1SWarner Losh cfe_tty_close(struct tty *tp) 112ae36cccdSWarner Losh { 113ae36cccdSWarner Losh 114ae36cccdSWarner Losh /* XXX Should be replaced with callout_stop(9) */ 115ae36cccdSWarner Losh untimeout(cfe_timeout, tp, cfe_timeouthandle); 116ae36cccdSWarner Losh } 117ae36cccdSWarner Losh 118ae36cccdSWarner Losh static void 1196f079ba1SWarner Losh cfe_tty_outwakeup(struct tty *tp) 120ae36cccdSWarner Losh { 121ae36cccdSWarner Losh int len; 122ae36cccdSWarner Losh u_char buf[CFEBURSTLEN]; 123ae36cccdSWarner Losh 1246f079ba1SWarner Losh for (;;) { 1256f079ba1SWarner Losh len = ttydisc_getc(tp, buf, sizeof buf); 1266f079ba1SWarner Losh if (len == 0) 1276f079ba1SWarner Losh break; 128ae36cccdSWarner Losh while (cfe_write(conhandle, buf, len) == 0) 129750595efSWarner Losh continue; 130ae36cccdSWarner Losh } 131ae36cccdSWarner Losh } 132ae36cccdSWarner Losh 133ae36cccdSWarner Losh static void 134ae36cccdSWarner Losh cfe_timeout(void *v) 135ae36cccdSWarner Losh { 136ae36cccdSWarner Losh struct tty *tp; 137ae36cccdSWarner Losh int c; 138ae36cccdSWarner Losh 139ae36cccdSWarner Losh tp = (struct tty *)v; 140ae36cccdSWarner Losh 1416f079ba1SWarner Losh tty_lock(tp); 1426f079ba1SWarner Losh while ((c = cfe_cngetc(NULL)) != -1) 1436f079ba1SWarner Losh ttydisc_rint(tp, c, 0); 1446f079ba1SWarner Losh ttydisc_rint_done(tp); 1456f079ba1SWarner Losh tty_unlock(tp); 146ae36cccdSWarner Losh 147ae36cccdSWarner Losh cfe_timeouthandle = timeout(cfe_timeout, tp, polltime); 148ae36cccdSWarner Losh } 149ae36cccdSWarner Losh 150ae36cccdSWarner Losh static void 151ae36cccdSWarner Losh cfe_cnprobe(struct consdev *cp) 152ae36cccdSWarner Losh { 153ae36cccdSWarner Losh 154ae36cccdSWarner Losh conhandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); 155ae36cccdSWarner Losh if (conhandle < 0) { 156ae36cccdSWarner Losh cp->cn_pri = CN_DEAD; 157ae36cccdSWarner Losh return; 158ae36cccdSWarner Losh } 159ae36cccdSWarner Losh 160ae36cccdSWarner Losh /* XXX */ 161ae36cccdSWarner Losh if (bootverbose) { 162ae36cccdSWarner Losh char *bootmsg = "Using CFE firmware console.\n"; 163ae36cccdSWarner Losh int i; 164ae36cccdSWarner Losh 165ae36cccdSWarner Losh for (i = 0; i < strlen(bootmsg); i++) 166ae36cccdSWarner Losh cfe_cnputc(cp, bootmsg[i]); 167ae36cccdSWarner Losh } 168ae36cccdSWarner Losh 169ae36cccdSWarner Losh cp->cn_pri = CN_LOW; 170ae36cccdSWarner Losh } 171ae36cccdSWarner Losh 172ae36cccdSWarner Losh static void 173ae36cccdSWarner Losh cfe_cninit(struct consdev *cp) 174ae36cccdSWarner Losh { 175ae36cccdSWarner Losh 176c8978106SEd Schouten strcpy(cp->cn_name, "cfecons"); 177ae36cccdSWarner Losh } 178ae36cccdSWarner Losh 179ae36cccdSWarner Losh static void 180ae36cccdSWarner Losh cfe_cnterm(struct consdev *cp) 181ae36cccdSWarner Losh { 182ae36cccdSWarner Losh 183ae36cccdSWarner Losh } 184ae36cccdSWarner Losh 185ae36cccdSWarner Losh static int 186ae36cccdSWarner Losh cfe_cngetc(struct consdev *cp) 187ae36cccdSWarner Losh { 188ae36cccdSWarner Losh int result; 189ae36cccdSWarner Losh unsigned char ch; 190ae36cccdSWarner Losh 191ae36cccdSWarner Losh while ((result = cfe_read(conhandle, &ch, 1)) == 0) 192750595efSWarner Losh continue; 193ae36cccdSWarner Losh 194ae36cccdSWarner Losh if (result > 0) { 195ae36cccdSWarner Losh #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 1966f079ba1SWarner Losh int kdb_brk; 1976f079ba1SWarner Losh 1986f079ba1SWarner Losh if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { 1996f079ba1SWarner Losh switch (kdb_brk) { 2006f079ba1SWarner Losh case KDB_REQ_DEBUGGER: 2016f079ba1SWarner Losh kdb_enter(KDB_WHY_BREAK, 2026f079ba1SWarner Losh "Break sequence on console"); 2036f079ba1SWarner Losh break; 2046f079ba1SWarner Losh case KDB_REQ_PANIC: 2056f079ba1SWarner Losh kdb_panic("Panic sequence on console"); 2066f079ba1SWarner Losh break; 2076f079ba1SWarner Losh case KDB_REQ_REBOOT: 2086f079ba1SWarner Losh kdb_reboot(); 2096f079ba1SWarner Losh break; 2106f079ba1SWarner Losh 2116f079ba1SWarner Losh } 2126f079ba1SWarner Losh } 213ae36cccdSWarner Losh #endif 214ae36cccdSWarner Losh return (ch); 215ae36cccdSWarner Losh } 216ae36cccdSWarner Losh 217ae36cccdSWarner Losh return (-1); 218ae36cccdSWarner Losh } 219ae36cccdSWarner Losh 220ae36cccdSWarner Losh static void 221ae36cccdSWarner Losh cfe_cnputc(struct consdev *cp, int c) 222ae36cccdSWarner Losh { 223ae36cccdSWarner Losh char cbuf; 224ae36cccdSWarner Losh 225ae36cccdSWarner Losh if (c == '\n') 226ae36cccdSWarner Losh cfe_cnputc(cp, '\r'); 227ae36cccdSWarner Losh 228ae36cccdSWarner Losh cbuf = c; 229ae36cccdSWarner Losh while (cfe_write(conhandle, &cbuf, 1) == 0) 230750595efSWarner Losh continue; 231ae36cccdSWarner Losh } 232ae36cccdSWarner Losh 2336f079ba1SWarner Losh SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 234