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 26707fed20SBenno Rice #ifndef lint 27707fed20SBenno Rice static const char rcsid[] = 28707fed20SBenno Rice "$FreeBSD$"; 29707fed20SBenno Rice #endif /* not lint */ 30707fed20SBenno Rice 31761f89f9SHartmut Brandt #include "opt_ddb.h" 32761f89f9SHartmut Brandt #include "opt_comconsole.h" 33761f89f9SHartmut Brandt 34707fed20SBenno Rice #include <sys/param.h> 35707fed20SBenno Rice #include <sys/kernel.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 47cbecdd57SJake Burkholder #define OFW_POLL_HZ 4 48707fed20SBenno Rice 49707fed20SBenno Rice static d_open_t ofw_dev_open; 50707fed20SBenno Rice static d_close_t ofw_dev_close; 51707fed20SBenno Rice static d_ioctl_t ofw_dev_ioctl; 52707fed20SBenno Rice 53707fed20SBenno Rice #define CDEV_MAJOR 97 54707fed20SBenno Rice 55707fed20SBenno Rice static struct cdevsw ofw_cdevsw = { 56707fed20SBenno Rice /* open */ ofw_dev_open, 57707fed20SBenno Rice /* close */ ofw_dev_close, 58707fed20SBenno Rice /* read */ ttyread, 59707fed20SBenno Rice /* write */ ttywrite, 60707fed20SBenno Rice /* ioctl */ ofw_dev_ioctl, 61707fed20SBenno Rice /* poll */ ttypoll, 62707fed20SBenno Rice /* mmap */ nommap, 63707fed20SBenno Rice /* strategy */ nostrategy, 64707fed20SBenno Rice /* name */ "ofw", 65707fed20SBenno Rice /* major */ CDEV_MAJOR, 66707fed20SBenno Rice /* dump */ nodump, 67707fed20SBenno Rice /* psize */ nopsize, 68707fed20SBenno Rice /* flags */ 0, 69707fed20SBenno Rice }; 70707fed20SBenno Rice 71707fed20SBenno Rice static struct tty *ofw_tp = NULL; 72707fed20SBenno Rice static int polltime; 73707fed20SBenno Rice static struct callout_handle ofw_timeouthandle 74707fed20SBenno Rice = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); 75707fed20SBenno Rice 76761f89f9SHartmut Brandt #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 77761f89f9SHartmut Brandt static int alt_break_state; 78761f89f9SHartmut Brandt #endif 79761f89f9SHartmut Brandt 80707fed20SBenno Rice static void ofw_tty_start(struct tty *); 81707fed20SBenno Rice static int ofw_tty_param(struct tty *, struct termios *); 82707fed20SBenno Rice static void ofw_tty_stop(struct tty *, int); 83707fed20SBenno Rice static void ofw_timeout(void *); 84707fed20SBenno Rice 85707fed20SBenno Rice static cn_probe_t ofw_cons_probe; 86707fed20SBenno Rice static cn_init_t ofw_cons_init; 87707fed20SBenno Rice static cn_getc_t ofw_cons_getc; 88707fed20SBenno Rice static cn_checkc_t ofw_cons_checkc; 89707fed20SBenno Rice static cn_putc_t ofw_cons_putc; 90707fed20SBenno Rice 91707fed20SBenno Rice CONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc, 92707fed20SBenno Rice ofw_cons_checkc, ofw_cons_putc, NULL); 93707fed20SBenno Rice 9447a1c915SJake Burkholder static void 9547a1c915SJake Burkholder cn_drvinit(void *unused) 9647a1c915SJake Burkholder { 97a121cb6aSJake Burkholder phandle_t options; 98a121cb6aSJake Burkholder char output[32]; 9947a1c915SJake Burkholder 100a121cb6aSJake Burkholder if (ofw_consdev.cn_dev != NULL) { 101a121cb6aSJake Burkholder if ((options = OF_finddevice("/options")) == -1 || 102a121cb6aSJake Burkholder OF_getprop(options, "output-device", output, 103a121cb6aSJake Burkholder sizeof(output)) == -1) 104a121cb6aSJake Burkholder return; 105984e2655SJake Burkholder make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", 106984e2655SJake Burkholder output); 107984e2655SJake Burkholder make_dev_alias(ofw_consdev.cn_dev, "ofwcons"); 108a121cb6aSJake Burkholder } 10947a1c915SJake Burkholder } 11047a1c915SJake Burkholder 111a121cb6aSJake Burkholder SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + CDEV_MAJOR, cn_drvinit, NULL) 11247a1c915SJake Burkholder 113707fed20SBenno Rice static int stdin; 114707fed20SBenno Rice static int stdout; 115707fed20SBenno Rice 116707fed20SBenno Rice static int 117b40ce416SJulian Elischer ofw_dev_open(dev_t dev, int flag, int mode, struct thread *td) 118707fed20SBenno Rice { 119707fed20SBenno Rice struct tty *tp; 120707fed20SBenno Rice int unit; 121707fed20SBenno Rice int error, setuptimeout; 122707fed20SBenno Rice 123707fed20SBenno Rice error = 0; 124707fed20SBenno Rice setuptimeout = 0; 125707fed20SBenno Rice unit = minor(dev); 126707fed20SBenno Rice 127707fed20SBenno Rice tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp); 128707fed20SBenno Rice 129707fed20SBenno Rice tp->t_oproc = ofw_tty_start; 130707fed20SBenno Rice tp->t_param = ofw_tty_param; 131707fed20SBenno Rice tp->t_stop = ofw_tty_stop; 132707fed20SBenno Rice tp->t_dev = dev; 133707fed20SBenno Rice 134707fed20SBenno Rice if ((tp->t_state & TS_ISOPEN) == 0) { 135707fed20SBenno Rice tp->t_state |= TS_CARR_ON; 136707fed20SBenno Rice ttychars(tp); 137707fed20SBenno Rice tp->t_iflag = TTYDEF_IFLAG; 138707fed20SBenno Rice tp->t_oflag = TTYDEF_OFLAG; 139707fed20SBenno Rice tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 140707fed20SBenno Rice tp->t_lflag = TTYDEF_LFLAG; 141707fed20SBenno Rice tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 142707fed20SBenno Rice ttsetwater(tp); 143707fed20SBenno Rice 144707fed20SBenno Rice setuptimeout = 1; 14544731cabSJohn Baldwin } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 146707fed20SBenno Rice return (EBUSY); 147707fed20SBenno Rice } 148707fed20SBenno Rice 149707fed20SBenno Rice error = (*linesw[tp->t_line].l_open)(dev, tp); 150707fed20SBenno Rice 151707fed20SBenno Rice if (error == 0 && setuptimeout) { 152707fed20SBenno Rice polltime = hz / OFW_POLL_HZ; 153707fed20SBenno Rice if (polltime < 1) { 154707fed20SBenno Rice polltime = 1; 155707fed20SBenno Rice } 156707fed20SBenno Rice 157707fed20SBenno Rice ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 158707fed20SBenno Rice } 159707fed20SBenno Rice 160707fed20SBenno Rice return (error); 161707fed20SBenno Rice } 162707fed20SBenno Rice 163707fed20SBenno Rice static int 164b40ce416SJulian Elischer ofw_dev_close(dev_t dev, int flag, int mode, struct thread *td) 165707fed20SBenno Rice { 166707fed20SBenno Rice int unit; 167707fed20SBenno Rice struct tty *tp; 168707fed20SBenno Rice 169707fed20SBenno Rice unit = minor(dev); 170707fed20SBenno Rice tp = ofw_tp; 171707fed20SBenno Rice 172707fed20SBenno Rice if (unit != 0) { 173707fed20SBenno Rice return (ENXIO); 174707fed20SBenno Rice } 175707fed20SBenno Rice 176707fed20SBenno Rice (*linesw[tp->t_line].l_close)(tp, flag); 177707fed20SBenno Rice ttyclose(tp); 178707fed20SBenno Rice 179707fed20SBenno Rice return (0); 180707fed20SBenno Rice } 181707fed20SBenno Rice 182707fed20SBenno Rice static int 183b40ce416SJulian Elischer ofw_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 184707fed20SBenno Rice { 185707fed20SBenno Rice int unit; 186707fed20SBenno Rice struct tty *tp; 187707fed20SBenno Rice int error; 188707fed20SBenno Rice 189707fed20SBenno Rice unit = minor(dev); 190c22c65b1SJake Burkholder tp = ofw_tp; 191c22c65b1SJake Burkholder 192707fed20SBenno Rice if (unit != 0) { 193707fed20SBenno Rice return (ENXIO); 194707fed20SBenno Rice } 195707fed20SBenno Rice 196b40ce416SJulian Elischer error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); 197707fed20SBenno Rice if (error != ENOIOCTL) { 198707fed20SBenno Rice return (error); 199707fed20SBenno Rice } 200707fed20SBenno Rice 201707fed20SBenno Rice error = ttioctl(tp, cmd, data, flag); 202707fed20SBenno Rice if (error != ENOIOCTL) { 203707fed20SBenno Rice return (error); 204707fed20SBenno Rice } 205707fed20SBenno Rice 206707fed20SBenno Rice return (ENOTTY); 207707fed20SBenno Rice } 208707fed20SBenno Rice 209707fed20SBenno Rice static int 210707fed20SBenno Rice ofw_tty_param(struct tty *tp, struct termios *t) 211707fed20SBenno Rice { 212707fed20SBenno Rice 213707fed20SBenno Rice return (0); 214707fed20SBenno Rice } 215707fed20SBenno Rice 216707fed20SBenno Rice static void 217707fed20SBenno Rice ofw_tty_start(struct tty *tp) 218707fed20SBenno Rice { 219707fed20SBenno Rice 220707fed20SBenno Rice if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 221707fed20SBenno Rice ttwwakeup(tp); 222707fed20SBenno Rice return; 223707fed20SBenno Rice } 224707fed20SBenno Rice 225707fed20SBenno Rice tp->t_state |= TS_BUSY; 226707fed20SBenno Rice while (tp->t_outq.c_cc != 0) { 227707fed20SBenno Rice ofw_cons_putc(tp->t_dev, getc(&tp->t_outq)); 228707fed20SBenno Rice } 229707fed20SBenno Rice tp->t_state &= ~TS_BUSY; 230707fed20SBenno Rice 231707fed20SBenno Rice ttwwakeup(tp); 232707fed20SBenno Rice } 233707fed20SBenno Rice 234707fed20SBenno Rice static void 235707fed20SBenno Rice ofw_tty_stop(struct tty *tp, int flag) 236707fed20SBenno Rice { 237707fed20SBenno Rice 238707fed20SBenno Rice if (tp->t_state & TS_BUSY) { 239707fed20SBenno Rice if ((tp->t_state & TS_TTSTOP) == 0) { 240707fed20SBenno Rice tp->t_state |= TS_FLUSH; 241707fed20SBenno Rice } 242707fed20SBenno Rice } 243707fed20SBenno Rice } 244707fed20SBenno Rice 245707fed20SBenno Rice static void 246707fed20SBenno Rice ofw_timeout(void *v) 247707fed20SBenno Rice { 248707fed20SBenno Rice struct tty *tp; 249707fed20SBenno Rice int c; 250707fed20SBenno Rice 251707fed20SBenno Rice tp = (struct tty *)v; 252707fed20SBenno Rice 253707fed20SBenno Rice while ((c = ofw_cons_checkc(tp->t_dev)) != -1) { 254707fed20SBenno Rice if (tp->t_state & TS_ISOPEN) { 255707fed20SBenno Rice (*linesw[tp->t_line].l_rint)(c, tp); 256707fed20SBenno Rice } 257707fed20SBenno Rice } 258707fed20SBenno Rice 259707fed20SBenno Rice ofw_timeouthandle = timeout(ofw_timeout, tp, polltime); 260707fed20SBenno Rice } 261707fed20SBenno Rice 262707fed20SBenno Rice static void 263707fed20SBenno Rice ofw_cons_probe(struct consdev *cp) 264707fed20SBenno Rice { 265707fed20SBenno Rice int chosen; 266707fed20SBenno Rice 267707fed20SBenno Rice if ((chosen = OF_finddevice("/chosen")) == -1) { 268707fed20SBenno Rice cp->cn_pri = CN_DEAD; 269707fed20SBenno Rice return; 270707fed20SBenno Rice } 271707fed20SBenno Rice 272707fed20SBenno Rice if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) { 273707fed20SBenno Rice cp->cn_pri = CN_DEAD; 274707fed20SBenno Rice return; 275707fed20SBenno Rice } 276707fed20SBenno Rice 277707fed20SBenno Rice if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) { 278707fed20SBenno Rice cp->cn_pri = CN_DEAD; 279707fed20SBenno Rice return; 280707fed20SBenno Rice } 281707fed20SBenno Rice 282a121cb6aSJake Burkholder cp->cn_dev = NULL; 283707fed20SBenno Rice cp->cn_pri = CN_INTERNAL; 284707fed20SBenno Rice } 285707fed20SBenno Rice 286707fed20SBenno Rice static void 287707fed20SBenno Rice ofw_cons_init(struct consdev *cp) 288707fed20SBenno Rice { 289707fed20SBenno Rice 290a121cb6aSJake Burkholder cp->cn_dev = makedev(CDEV_MAJOR, 0); 291a121cb6aSJake Burkholder cp->cn_tp = ofw_tp; 292707fed20SBenno Rice } 293707fed20SBenno Rice 294707fed20SBenno Rice static int 295707fed20SBenno Rice ofw_cons_getc(dev_t dev) 296707fed20SBenno Rice { 297707fed20SBenno Rice unsigned char ch; 298707fed20SBenno Rice int l; 299707fed20SBenno Rice 300707fed20SBenno Rice ch = '\0'; 301707fed20SBenno Rice 302707fed20SBenno Rice while ((l = OF_read(stdin, &ch, 1)) != 1) { 303707fed20SBenno Rice if (l != -2 && l != 0) { 304707fed20SBenno Rice return (-1); 305707fed20SBenno Rice } 306707fed20SBenno Rice } 307707fed20SBenno Rice 308761f89f9SHartmut Brandt #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 309761f89f9SHartmut Brandt if (db_alt_break(ch, &alt_break_state)) 310761f89f9SHartmut Brandt breakpoint(); 311761f89f9SHartmut Brandt #endif 312761f89f9SHartmut Brandt 313707fed20SBenno Rice return (ch); 314707fed20SBenno Rice } 315707fed20SBenno Rice 316707fed20SBenno Rice static int 317707fed20SBenno Rice ofw_cons_checkc(dev_t dev) 318707fed20SBenno Rice { 319707fed20SBenno Rice unsigned char ch; 320707fed20SBenno Rice 321cbecdd57SJake Burkholder if (OF_read(stdin, &ch, 1) > 0) { 322761f89f9SHartmut Brandt #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) 323761f89f9SHartmut Brandt if (db_alt_break(ch, &alt_break_state)) 324761f89f9SHartmut Brandt breakpoint(); 325761f89f9SHartmut Brandt #endif 326707fed20SBenno Rice return (ch); 327707fed20SBenno Rice } 328707fed20SBenno Rice 329707fed20SBenno Rice return (-1); 330707fed20SBenno Rice } 331707fed20SBenno Rice 332707fed20SBenno Rice static void 333707fed20SBenno Rice ofw_cons_putc(dev_t dev, int c) 334707fed20SBenno Rice { 335707fed20SBenno Rice char cbuf; 336707fed20SBenno Rice 337707fed20SBenno Rice if (c == '\n') { 338707fed20SBenno Rice cbuf = '\r'; 339707fed20SBenno Rice OF_write(stdout, &cbuf, 1); 340707fed20SBenno Rice } 341707fed20SBenno Rice 342707fed20SBenno Rice cbuf = c; 343707fed20SBenno Rice OF_write(stdout, &cbuf, 1); 344707fed20SBenno Rice } 345