1707fed20SBenno Rice /* 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> 35707fed20SBenno Rice #include <sys/systm.h> 36707fed20SBenno Rice #include <sys/types.h> 37707fed20SBenno Rice #include <sys/conf.h> 38707fed20SBenno Rice #include <sys/cons.h> 39707fed20SBenno Rice #include <sys/consio.h> 40707fed20SBenno Rice #include <sys/tty.h> 41707fed20SBenno Rice 42707fed20SBenno Rice #include <dev/ofw/openfirm.h> 43707fed20SBenno Rice 44761f89f9SHartmut Brandt #include <ddb/ddb.h> 45761f89f9SHartmut Brandt 46a82b25f9SDavid E. O'Brien #ifndef OFWCONS_POLL_HZ 47a82b25f9SDavid E. O'Brien #define OFWCONS_POLL_HZ 4 /* 50-100 works best on Ultra2 */ 48a82b25f9SDavid E. O'Brien #endif 49a82b25f9SDavid E. O'Brien #define OFBURSTLEN 128 /* max number of bytes to write in one chunk */ 50707fed20SBenno Rice 51707fed20SBenno Rice static d_open_t ofw_dev_open; 52707fed20SBenno Rice static d_close_t ofw_dev_close; 53707fed20SBenno Rice 54707fed20SBenno Rice static struct cdevsw ofw_cdevsw = { 55dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 567ac40f5fSPoul-Henning Kamp .d_open = ofw_dev_open, 577ac40f5fSPoul-Henning Kamp .d_close = ofw_dev_close, 587ac40f5fSPoul-Henning Kamp .d_name = "ofw", 59dc08ffecSPoul-Henning Kamp .d_flags = D_TTY | D_NEEDGIANT, 60707fed20SBenno Rice }; 61707fed20SBenno Rice 62707fed20SBenno Rice static struct tty *ofw_tp = NULL; 63707fed20SBenno Rice static int polltime; 64707fed20SBenno Rice static struct callout_handle ofw_timeouthandle 65707fed20SBenno Rice = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); 66707fed20SBenno Rice 678cabb94fSMarcel Moolenaar #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 68761f89f9SHartmut Brandt static int alt_break_state; 69761f89f9SHartmut Brandt #endif 70761f89f9SHartmut Brandt 71707fed20SBenno Rice static void ofw_tty_start(struct tty *); 72707fed20SBenno Rice static int ofw_tty_param(struct tty *, struct termios *); 73707fed20SBenno Rice static void ofw_tty_stop(struct tty *, int); 74707fed20SBenno Rice static void ofw_timeout(void *); 75707fed20SBenno Rice 76707fed20SBenno Rice static cn_probe_t ofw_cons_probe; 77707fed20SBenno Rice static cn_init_t ofw_cons_init; 78707fed20SBenno Rice static cn_getc_t ofw_cons_getc; 79707fed20SBenno Rice static cn_checkc_t ofw_cons_checkc; 80707fed20SBenno Rice static cn_putc_t ofw_cons_putc; 81707fed20SBenno Rice 82707fed20SBenno Rice CONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc, 83707fed20SBenno Rice ofw_cons_checkc, ofw_cons_putc, NULL); 84707fed20SBenno Rice 8547a1c915SJake Burkholder static void 8647a1c915SJake Burkholder cn_drvinit(void *unused) 8747a1c915SJake Burkholder { 88a121cb6aSJake Burkholder phandle_t options; 89a121cb6aSJake Burkholder char output[32]; 9089c9c53dSPoul-Henning Kamp struct cdev *dev; 9147a1c915SJake Burkholder 92278667afSJake Burkholder if (ofw_consdev.cn_pri != CN_DEAD && 93278667afSJake Burkholder ofw_consdev.cn_name[0] != '\0') { 94a121cb6aSJake Burkholder if ((options = OF_finddevice("/options")) == -1 || 95a121cb6aSJake Burkholder OF_getprop(options, "output-device", output, 96a121cb6aSJake Burkholder sizeof(output)) == -1) 97a121cb6aSJake Burkholder return; 98c5c5a2adSPoul-Henning Kamp /* 99c5c5a2adSPoul-Henning Kamp * XXX: This is a hack and it may result in two /dev/ttya 100c5c5a2adSPoul-Henning Kamp * XXX: devices on platforms where the sab driver works. 101c5c5a2adSPoul-Henning Kamp */ 1023f99f14bSPoul-Henning Kamp dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", 103984e2655SJake Burkholder output); 1043f99f14bSPoul-Henning Kamp make_dev_alias(dev, "ofwcons"); 105a121cb6aSJake Burkholder } 10647a1c915SJake Burkholder } 10747a1c915SJake Burkholder 108c9c7976fSPoul-Henning Kamp SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL) 10947a1c915SJake Burkholder 110707fed20SBenno Rice static int stdin; 111707fed20SBenno Rice static int stdout; 112707fed20SBenno Rice 113707fed20SBenno Rice static int 11489c9c53dSPoul-Henning Kamp ofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 115707fed20SBenno Rice { 116707fed20SBenno Rice struct tty *tp; 117707fed20SBenno Rice int unit; 118707fed20SBenno Rice int error, setuptimeout; 119707fed20SBenno Rice 120707fed20SBenno Rice error = 0; 121707fed20SBenno Rice setuptimeout = 0; 122707fed20SBenno Rice unit = minor(dev); 123707fed20SBenno Rice 124c5c5a2adSPoul-Henning Kamp /* 125c5c5a2adSPoul-Henning Kamp * XXX: BAD, should happen at attach time 126c5c5a2adSPoul-Henning Kamp */ 127c5c5a2adSPoul-Henning Kamp if (dev->si_tty == NULL) { 128c5c5a2adSPoul-Henning Kamp ofw_tp = ttyalloc(); 129c5c5a2adSPoul-Henning Kamp dev->si_tty = ofw_tp; 130c5c5a2adSPoul-Henning Kamp ofw_tp->t_dev = dev; 131c5c5a2adSPoul-Henning Kamp } 132c5c5a2adSPoul-Henning Kamp tp = dev->si_tty; 133707fed20SBenno Rice 134707fed20SBenno Rice tp->t_oproc = ofw_tty_start; 135707fed20SBenno Rice tp->t_param = ofw_tty_param; 136707fed20SBenno Rice tp->t_stop = ofw_tty_stop; 137707fed20SBenno Rice tp->t_dev = dev; 138707fed20SBenno Rice 139707fed20SBenno Rice if ((tp->t_state & TS_ISOPEN) == 0) { 140707fed20SBenno Rice tp->t_state |= TS_CARR_ON; 141707fed20SBenno Rice ttychars(tp); 142707fed20SBenno Rice tp->t_iflag = TTYDEF_IFLAG; 143707fed20SBenno Rice tp->t_oflag = TTYDEF_OFLAG; 144b11ef345SGarance A Drosehn tp->t_cflag = TTYDEF_CFLAG | CLOCAL; 145707fed20SBenno Rice tp->t_lflag = TTYDEF_LFLAG; 146707fed20SBenno Rice tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 147707fed20SBenno Rice ttsetwater(tp); 148707fed20SBenno Rice 149707fed20SBenno Rice setuptimeout = 1; 15044731cabSJohn Baldwin } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 151707fed20SBenno Rice return (EBUSY); 152707fed20SBenno Rice } 153707fed20SBenno Rice 1542140d01bSPoul-Henning Kamp error = ttyld_open(tp, dev); 155707fed20SBenno Rice 156707fed20SBenno Rice if (error == 0 && setuptimeout) { 157a82b25f9SDavid E. O'Brien polltime = hz / OFWCONS_POLL_HZ; 158707fed20SBenno Rice if (polltime < 1) { 159707fed20SBenno Rice polltime = 1; 160707fed20SBenno Rice } 161707fed20SBenno Rice 162707fed20SBenno Rice ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 163707fed20SBenno Rice } 164707fed20SBenno Rice 165707fed20SBenno Rice return (error); 166707fed20SBenno Rice } 167707fed20SBenno Rice 168707fed20SBenno Rice static int 16989c9c53dSPoul-Henning Kamp ofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td) 170707fed20SBenno Rice { 171707fed20SBenno Rice int unit; 172707fed20SBenno Rice struct tty *tp; 173707fed20SBenno Rice 174707fed20SBenno Rice unit = minor(dev); 175c5c5a2adSPoul-Henning Kamp tp = dev->si_tty; 176707fed20SBenno Rice 177707fed20SBenno Rice if (unit != 0) { 178707fed20SBenno Rice return (ENXIO); 179707fed20SBenno Rice } 180707fed20SBenno Rice 181a82b25f9SDavid E. O'Brien /* XXX Should be replaced with callout_stop(9) */ 182a82b25f9SDavid E. O'Brien untimeout(ofw_timeout, tp, ofw_timeouthandle); 1832140d01bSPoul-Henning Kamp ttyld_close(tp, flag); 184672c05d4SPoul-Henning Kamp tty_close(tp); 185707fed20SBenno Rice 186707fed20SBenno Rice return (0); 187707fed20SBenno Rice } 188707fed20SBenno Rice 189707fed20SBenno Rice 190707fed20SBenno Rice static int 191707fed20SBenno Rice ofw_tty_param(struct tty *tp, struct termios *t) 192707fed20SBenno Rice { 193707fed20SBenno Rice 194707fed20SBenno Rice return (0); 195707fed20SBenno Rice } 196707fed20SBenno Rice 197707fed20SBenno Rice static void 198707fed20SBenno Rice ofw_tty_start(struct tty *tp) 199707fed20SBenno Rice { 200a82b25f9SDavid E. O'Brien struct clist *cl; 201a82b25f9SDavid E. O'Brien int len; 202a82b25f9SDavid E. O'Brien u_char buf[OFBURSTLEN]; 203707fed20SBenno Rice 204a82b25f9SDavid E. O'Brien 205a82b25f9SDavid E. O'Brien if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 206707fed20SBenno Rice return; 207707fed20SBenno Rice 208707fed20SBenno Rice tp->t_state |= TS_BUSY; 209a82b25f9SDavid E. O'Brien cl = &tp->t_outq; 210a82b25f9SDavid E. O'Brien len = q_to_b(cl, buf, OFBURSTLEN); 211a82b25f9SDavid E. O'Brien OF_write(stdout, buf, len); 212707fed20SBenno Rice tp->t_state &= ~TS_BUSY; 213707fed20SBenno Rice 214707fed20SBenno Rice ttwwakeup(tp); 215707fed20SBenno Rice } 216707fed20SBenno Rice 217707fed20SBenno Rice static void 218707fed20SBenno Rice ofw_tty_stop(struct tty *tp, int flag) 219707fed20SBenno Rice { 220707fed20SBenno Rice 221707fed20SBenno Rice if (tp->t_state & TS_BUSY) { 222707fed20SBenno Rice if ((tp->t_state & TS_TTSTOP) == 0) { 223707fed20SBenno Rice tp->t_state |= TS_FLUSH; 224707fed20SBenno Rice } 225707fed20SBenno Rice } 226707fed20SBenno Rice } 227707fed20SBenno Rice 228707fed20SBenno Rice static void 229707fed20SBenno Rice ofw_timeout(void *v) 230707fed20SBenno Rice { 231707fed20SBenno Rice struct tty *tp; 232707fed20SBenno Rice int c; 233707fed20SBenno Rice 234707fed20SBenno Rice tp = (struct tty *)v; 235707fed20SBenno Rice 236263444cfSPoul-Henning Kamp while ((c = ofw_cons_checkc(NULL)) != -1) { 237707fed20SBenno Rice if (tp->t_state & TS_ISOPEN) { 2382140d01bSPoul-Henning Kamp ttyld_rint(tp, c); 239707fed20SBenno Rice } 240707fed20SBenno Rice } 241707fed20SBenno Rice 242707fed20SBenno Rice ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 243707fed20SBenno Rice } 244707fed20SBenno Rice 245707fed20SBenno Rice static void 246707fed20SBenno Rice ofw_cons_probe(struct consdev *cp) 247707fed20SBenno Rice { 248707fed20SBenno Rice int chosen; 249707fed20SBenno Rice 250707fed20SBenno Rice if ((chosen = OF_finddevice("/chosen")) == -1) { 251707fed20SBenno Rice cp->cn_pri = CN_DEAD; 252707fed20SBenno Rice return; 253707fed20SBenno Rice } 254707fed20SBenno Rice 255707fed20SBenno Rice if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 256707fed20SBenno Rice cp->cn_pri = CN_DEAD; 257707fed20SBenno Rice return; 258707fed20SBenno Rice } 259707fed20SBenno Rice 260707fed20SBenno Rice if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 261707fed20SBenno Rice cp->cn_pri = CN_DEAD; 262707fed20SBenno Rice return; 263707fed20SBenno Rice } 264707fed20SBenno Rice 2655dbb0622SJake Burkholder cp->cn_pri = CN_LOW; 266707fed20SBenno Rice } 267707fed20SBenno Rice 268707fed20SBenno Rice static void 269707fed20SBenno Rice ofw_cons_init(struct consdev *cp) 270707fed20SBenno Rice { 271707fed20SBenno Rice 2722f06c3e7SPoul-Henning Kamp /* XXX: This is the alias, but that should be good enough */ 2732f06c3e7SPoul-Henning Kamp sprintf(cp->cn_name, "ofwcons"); 274a121cb6aSJake Burkholder cp->cn_tp = ofw_tp; 275707fed20SBenno Rice } 276707fed20SBenno Rice 277707fed20SBenno Rice static int 278263444cfSPoul-Henning Kamp ofw_cons_getc(struct consdev *cp) 279707fed20SBenno Rice { 280707fed20SBenno Rice unsigned char ch; 281707fed20SBenno Rice int l; 282707fed20SBenno Rice 283707fed20SBenno Rice ch = '\0'; 284707fed20SBenno Rice 285707fed20SBenno Rice while ((l = OF_read(stdin, &ch, 1)) != 1) { 286707fed20SBenno Rice if (l != -2 && l != 0) { 287707fed20SBenno Rice return (-1); 288707fed20SBenno Rice } 289707fed20SBenno Rice } 290707fed20SBenno Rice 2918cabb94fSMarcel Moolenaar #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 2928cabb94fSMarcel Moolenaar if (kdb_alt_break(ch, &alt_break_state)) 2938cabb94fSMarcel Moolenaar kdb_enter("Break sequence on console"); 294761f89f9SHartmut Brandt #endif 295761f89f9SHartmut Brandt 296707fed20SBenno Rice return (ch); 297707fed20SBenno Rice } 298707fed20SBenno Rice 299707fed20SBenno Rice static int 300263444cfSPoul-Henning Kamp ofw_cons_checkc(struct consdev *cp) 301707fed20SBenno Rice { 302707fed20SBenno Rice unsigned char ch; 303707fed20SBenno Rice 304cbecdd57SJake Burkholder if (OF_read(stdin, &ch, 1) > 0) { 3058cabb94fSMarcel Moolenaar #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) 3068cabb94fSMarcel Moolenaar if (kdb_alt_break(ch, &alt_break_state)) 3078cabb94fSMarcel Moolenaar kdb_enter("Break sequence on console"); 308761f89f9SHartmut Brandt #endif 309707fed20SBenno Rice return (ch); 310707fed20SBenno Rice } 311707fed20SBenno Rice 312707fed20SBenno Rice return (-1); 313707fed20SBenno Rice } 314707fed20SBenno Rice 315707fed20SBenno Rice static void 316263444cfSPoul-Henning Kamp ofw_cons_putc(struct consdev *cp, int c) 317707fed20SBenno Rice { 318707fed20SBenno Rice char cbuf; 319707fed20SBenno Rice 320707fed20SBenno Rice if (c == '\n') { 321707fed20SBenno Rice cbuf = '\r'; 322707fed20SBenno Rice OF_write(stdout, &cbuf, 1); 323707fed20SBenno Rice } 324707fed20SBenno Rice 325707fed20SBenno Rice cbuf = c; 326707fed20SBenno Rice OF_write(stdout, &cbuf, 1); 327707fed20SBenno Rice } 328