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 53ae36cccdSWarner Losh static d_open_t cfe_dev_open; 54ae36cccdSWarner Losh static d_close_t cfe_dev_close; 55ae36cccdSWarner Losh 56ae36cccdSWarner Losh static struct cdevsw cfe_cdevsw = { 57ae36cccdSWarner Losh .d_version = D_VERSION, 58ae36cccdSWarner Losh .d_open = cfe_dev_open, 59ae36cccdSWarner Losh .d_close = cfe_dev_close, 60ae36cccdSWarner Losh .d_name = "cfe", 61ae36cccdSWarner Losh .d_flags = D_TTY | D_NEEDGIANT, 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_tty_start(struct tty *); 76ae36cccdSWarner Losh static int cfe_tty_param(struct tty *, struct termios *); 77ae36cccdSWarner Losh static void cfe_tty_stop(struct tty *, int); 78ae36cccdSWarner Losh static void cfe_timeout(void *); 79ae36cccdSWarner Losh 80ae36cccdSWarner Losh static cn_probe_t cfe_cnprobe; 81ae36cccdSWarner Losh static cn_init_t cfe_cninit; 82ae36cccdSWarner Losh static cn_term_t cfe_cnterm; 83ae36cccdSWarner Losh static cn_getc_t cfe_cngetc; 84ae36cccdSWarner Losh static cn_putc_t cfe_cnputc; 85ae36cccdSWarner Losh 86ae36cccdSWarner Losh CONSOLE_DRIVER(cfe); 87ae36cccdSWarner Losh 88ae36cccdSWarner Losh static void 89ae36cccdSWarner Losh cn_drvinit(void *unused) 90ae36cccdSWarner Losh { 91ae36cccdSWarner Losh char output[32]; 92ae36cccdSWarner Losh struct cdev *dev; 93ae36cccdSWarner Losh 94ae36cccdSWarner Losh if (cfe_consdev.cn_pri != CN_DEAD && 95ae36cccdSWarner Losh cfe_consdev.cn_name[0] != '\0') { 96ae36cccdSWarner Losh dev = make_dev(&cfe_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", 97ae36cccdSWarner Losh output); 98ae36cccdSWarner Losh make_dev_alias(dev, "cfecons"); 99ae36cccdSWarner Losh } 100ae36cccdSWarner Losh } 101ae36cccdSWarner Losh 102ae36cccdSWarner Losh static int 103ae36cccdSWarner Losh cfe_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 104ae36cccdSWarner Losh { 105ae36cccdSWarner Losh struct tty *tp; 106ae36cccdSWarner Losh int unit; 107ae36cccdSWarner Losh int error, setuptimeout; 108ae36cccdSWarner Losh 109ae36cccdSWarner Losh error = 0; 110ae36cccdSWarner Losh setuptimeout = 0; 111ae36cccdSWarner Losh unit = minor(dev); 112ae36cccdSWarner Losh 113ae36cccdSWarner Losh /* 114ae36cccdSWarner Losh * XXX: BAD, should happen at attach time 115ae36cccdSWarner Losh */ 116ae36cccdSWarner Losh if (dev->si_tty == NULL) { 117ae36cccdSWarner Losh cfe_tp = ttyalloc(); 118ae36cccdSWarner Losh dev->si_tty = cfe_tp; 119ae36cccdSWarner Losh cfe_tp->t_dev = dev; 120ae36cccdSWarner Losh } 121ae36cccdSWarner Losh tp = dev->si_tty; 122ae36cccdSWarner Losh 123ae36cccdSWarner Losh tp->t_oproc = cfe_tty_start; 124ae36cccdSWarner Losh tp->t_param = cfe_tty_param; 125ae36cccdSWarner Losh tp->t_stop = cfe_tty_stop; 126ae36cccdSWarner Losh tp->t_dev = dev; 127ae36cccdSWarner Losh 128ae36cccdSWarner Losh if ((tp->t_state & TS_ISOPEN) == 0) { 129ae36cccdSWarner Losh tp->t_state |= TS_CARR_ON; 130ae36cccdSWarner Losh ttyconsolemode(tp, 0); 131ae36cccdSWarner Losh 132ae36cccdSWarner Losh setuptimeout = 1; 133ae36cccdSWarner Losh } else if ((tp->t_state & TS_XCLUDE) && 134ae36cccdSWarner Losh priv_check(td, PRIV_TTY_EXCLUSIVE)) { 135ae36cccdSWarner Losh return (EBUSY); 136ae36cccdSWarner Losh } 137ae36cccdSWarner Losh 138ae36cccdSWarner Losh error = ttyld_open(tp, dev); 139ae36cccdSWarner Losh 140ae36cccdSWarner Losh if (error == 0 && setuptimeout) { 141ae36cccdSWarner Losh polltime = hz / CFECONS_POLL_HZ; 142ae36cccdSWarner Losh if (polltime < 1) { 143ae36cccdSWarner Losh polltime = 1; 144ae36cccdSWarner Losh } 145ae36cccdSWarner Losh 146ae36cccdSWarner Losh cfe_timeouthandle = timeout(cfe_timeout, tp, polltime); 147ae36cccdSWarner Losh } 148ae36cccdSWarner Losh 149ae36cccdSWarner Losh return (error); 150ae36cccdSWarner Losh } 151ae36cccdSWarner Losh 152ae36cccdSWarner Losh static int 153ae36cccdSWarner Losh cfe_dev_close(struct cdev *dev, int flag, int mode, struct thread *td) 154ae36cccdSWarner Losh { 155ae36cccdSWarner Losh int unit; 156ae36cccdSWarner Losh struct tty *tp; 157ae36cccdSWarner Losh 158ae36cccdSWarner Losh unit = minor(dev); 159ae36cccdSWarner Losh tp = dev->si_tty; 160ae36cccdSWarner Losh 161ae36cccdSWarner Losh if (unit != 0) { 162ae36cccdSWarner Losh return (ENXIO); 163ae36cccdSWarner Losh } 164ae36cccdSWarner Losh 165ae36cccdSWarner Losh /* XXX Should be replaced with callout_stop(9) */ 166ae36cccdSWarner Losh untimeout(cfe_timeout, tp, cfe_timeouthandle); 167ae36cccdSWarner Losh ttyld_close(tp, flag); 168ae36cccdSWarner Losh tty_close(tp); 169ae36cccdSWarner Losh 170ae36cccdSWarner Losh return (0); 171ae36cccdSWarner Losh } 172ae36cccdSWarner Losh 173ae36cccdSWarner Losh 174ae36cccdSWarner Losh static int 175ae36cccdSWarner Losh cfe_tty_param(struct tty *tp, struct termios *t) 176ae36cccdSWarner Losh { 177ae36cccdSWarner Losh 178ae36cccdSWarner Losh return (0); 179ae36cccdSWarner Losh } 180ae36cccdSWarner Losh 181ae36cccdSWarner Losh static void 182ae36cccdSWarner Losh cfe_tty_start(struct tty *tp) 183ae36cccdSWarner Losh { 184ae36cccdSWarner Losh struct clist *cl; 185ae36cccdSWarner Losh int len; 186ae36cccdSWarner Losh u_char buf[CFEBURSTLEN]; 187ae36cccdSWarner Losh 188ae36cccdSWarner Losh if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 189ae36cccdSWarner Losh return; 190ae36cccdSWarner Losh 191ae36cccdSWarner Losh tp->t_state |= TS_BUSY; 192ae36cccdSWarner Losh cl = &tp->t_outq; 193ae36cccdSWarner Losh len = q_to_b(cl, buf, CFEBURSTLEN); 194ae36cccdSWarner Losh while (cfe_write(conhandle, buf, len) == 0) 195ae36cccdSWarner Losh ; 196ae36cccdSWarner Losh tp->t_state &= ~TS_BUSY; 197ae36cccdSWarner Losh 198ae36cccdSWarner Losh ttwwakeup(tp); 199ae36cccdSWarner Losh } 200ae36cccdSWarner Losh 201ae36cccdSWarner Losh static void 202ae36cccdSWarner Losh cfe_tty_stop(struct tty *tp, int flag) 203ae36cccdSWarner Losh { 204ae36cccdSWarner Losh 205ae36cccdSWarner Losh if (tp->t_state & TS_BUSY) { 206ae36cccdSWarner Losh if ((tp->t_state & TS_TTSTOP) == 0) { 207ae36cccdSWarner Losh tp->t_state |= TS_FLUSH; 208ae36cccdSWarner Losh } 209ae36cccdSWarner Losh } 210ae36cccdSWarner Losh } 211ae36cccdSWarner Losh 212ae36cccdSWarner Losh static void 213ae36cccdSWarner Losh cfe_timeout(void *v) 214ae36cccdSWarner Losh { 215ae36cccdSWarner Losh struct tty *tp; 216ae36cccdSWarner Losh int c; 217ae36cccdSWarner Losh 218ae36cccdSWarner Losh tp = (struct tty *)v; 219ae36cccdSWarner Losh 220ae36cccdSWarner Losh while ((c = cfe_cngetc(NULL)) != -1) { 221ae36cccdSWarner Losh if (tp->t_state & TS_ISOPEN) { 222ae36cccdSWarner Losh ttyld_rint(tp, c); 223ae36cccdSWarner Losh } 224ae36cccdSWarner Losh } 225ae36cccdSWarner Losh 226ae36cccdSWarner Losh cfe_timeouthandle = timeout(cfe_timeout, tp, polltime); 227ae36cccdSWarner Losh } 228ae36cccdSWarner Losh 229ae36cccdSWarner Losh static void 230ae36cccdSWarner Losh cfe_cnprobe(struct consdev *cp) 231ae36cccdSWarner Losh { 232ae36cccdSWarner Losh 233ae36cccdSWarner Losh conhandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); 234ae36cccdSWarner Losh if (conhandle < 0) { 235ae36cccdSWarner Losh cp->cn_pri = CN_DEAD; 236ae36cccdSWarner Losh return; 237ae36cccdSWarner Losh } 238ae36cccdSWarner Losh 239ae36cccdSWarner Losh /* XXX */ 240ae36cccdSWarner Losh if (bootverbose) { 241ae36cccdSWarner Losh char *bootmsg = "Using CFE firmware console.\n"; 242ae36cccdSWarner Losh int i; 243ae36cccdSWarner Losh 244ae36cccdSWarner Losh for (i = 0; i < strlen(bootmsg); i++) 245ae36cccdSWarner Losh cfe_cnputc(cp, bootmsg[i]); 246ae36cccdSWarner Losh } 247ae36cccdSWarner Losh 248ae36cccdSWarner Losh cp->cn_pri = CN_LOW; 249ae36cccdSWarner Losh } 250ae36cccdSWarner Losh 251ae36cccdSWarner Losh static void 252ae36cccdSWarner Losh cfe_cninit(struct consdev *cp) 253ae36cccdSWarner Losh { 254ae36cccdSWarner Losh 255ae36cccdSWarner Losh sprintf(cp->cn_name, "cfecons"); 256ae36cccdSWarner Losh cp->cn_tp = cfe_tp; 257ae36cccdSWarner Losh } 258ae36cccdSWarner Losh 259ae36cccdSWarner Losh static void 260ae36cccdSWarner Losh cfe_cnterm(struct consdev *cp) 261ae36cccdSWarner Losh { 262ae36cccdSWarner Losh 263ae36cccdSWarner Losh } 264ae36cccdSWarner Losh 265ae36cccdSWarner Losh static int 266ae36cccdSWarner Losh cfe_cngetc(struct consdev *cp) 267ae36cccdSWarner Losh { 268ae36cccdSWarner Losh int result; 269ae36cccdSWarner Losh unsigned char ch; 270ae36cccdSWarner Losh 271ae36cccdSWarner Losh while ((result = cfe_read(conhandle, &ch, 1)) == 0) 272ae36cccdSWarner Losh ; 273ae36cccdSWarner Losh 274ae36cccdSWarner Losh if (result > 0) { 275ae36cccdSWarner Losh #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 276ae36cccdSWarner Losh if (kdb_alt_break(ch, &alt_break_state)) 277ae36cccdSWarner Losh kdb_enter(KDB_WHY_BREAK, "Break sequence on console"); 278ae36cccdSWarner Losh #endif 279ae36cccdSWarner Losh return (ch); 280ae36cccdSWarner Losh } 281ae36cccdSWarner Losh 282ae36cccdSWarner Losh return (-1); 283ae36cccdSWarner Losh } 284ae36cccdSWarner Losh 285ae36cccdSWarner Losh static void 286ae36cccdSWarner Losh cfe_cnputc(struct consdev *cp, int c) 287ae36cccdSWarner Losh { 288ae36cccdSWarner Losh char cbuf; 289ae36cccdSWarner Losh 290ae36cccdSWarner Losh if (c == '\n') 291ae36cccdSWarner Losh cfe_cnputc(cp, '\r'); 292ae36cccdSWarner Losh 293ae36cccdSWarner Losh cbuf = c; 294ae36cccdSWarner Losh while (cfe_write(conhandle, &cbuf, 1) == 0) 295ae36cccdSWarner Losh ; 296ae36cccdSWarner Losh } 297ae36cccdSWarner Losh 298ae36cccdSWarner Losh SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL) 299