1*dc26833bSad /* $NetBSD: kd.c,v 1.19 2007/11/19 18:51:43 ad Exp $ */ 2ae1f6b9eSfredette 3ae1f6b9eSfredette /*- 4ae1f6b9eSfredette * Copyright (c) 1996 The NetBSD Foundation, Inc. 5ae1f6b9eSfredette * All rights reserved. 6ae1f6b9eSfredette * 7ae1f6b9eSfredette * This code is derived from software contributed to The NetBSD Foundation 8ae1f6b9eSfredette * by Gordon W. Ross. 9ae1f6b9eSfredette * 10ae1f6b9eSfredette * Redistribution and use in source and binary forms, with or without 11ae1f6b9eSfredette * modification, are permitted provided that the following conditions 12ae1f6b9eSfredette * are met: 13ae1f6b9eSfredette * 1. Redistributions of source code must retain the above copyright 14ae1f6b9eSfredette * notice, this list of conditions and the following disclaimer. 15ae1f6b9eSfredette * 2. Redistributions in binary form must reproduce the above copyright 16ae1f6b9eSfredette * notice, this list of conditions and the following disclaimer in the 17ae1f6b9eSfredette * documentation and/or other materials provided with the distribution. 18ae1f6b9eSfredette * 3. All advertising materials mentioning features or use of this software 19ae1f6b9eSfredette * must display the following acknowledgement: 20ae1f6b9eSfredette * This product includes software developed by the NetBSD 21ae1f6b9eSfredette * Foundation, Inc. and its contributors. 22ae1f6b9eSfredette * 4. Neither the name of The NetBSD Foundation nor the names of its 23ae1f6b9eSfredette * contributors may be used to endorse or promote products derived 24ae1f6b9eSfredette * from this software without specific prior written permission. 25ae1f6b9eSfredette * 26ae1f6b9eSfredette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27ae1f6b9eSfredette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28ae1f6b9eSfredette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29ae1f6b9eSfredette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30ae1f6b9eSfredette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31ae1f6b9eSfredette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32ae1f6b9eSfredette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33ae1f6b9eSfredette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34ae1f6b9eSfredette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35ae1f6b9eSfredette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36ae1f6b9eSfredette * POSSIBILITY OF SUCH DAMAGE. 37ae1f6b9eSfredette */ 38ae1f6b9eSfredette 39ae1f6b9eSfredette /* 40ae1f6b9eSfredette * Keyboard/Display device. 41ae1f6b9eSfredette * 42ae1f6b9eSfredette * This driver exists simply to provide a tty device that 43ae1f6b9eSfredette * the indirect console driver can point to. 44ae1f6b9eSfredette * The kbd driver sends its input here. 45ae1f6b9eSfredette * Output goes to the screen via PROM printf. 46ae1f6b9eSfredette */ 47ae1f6b9eSfredette 48ed517291Slukem #include <sys/cdefs.h> 49*dc26833bSad __KERNEL_RCSID(0, "$NetBSD: kd.c,v 1.19 2007/11/19 18:51:43 ad Exp $"); 50ed517291Slukem 51ae1f6b9eSfredette #include <sys/param.h> 52ae1f6b9eSfredette #include <sys/proc.h> 53ae1f6b9eSfredette #include <sys/systm.h> 54ae1f6b9eSfredette #include <sys/ioctl.h> 55ae1f6b9eSfredette #include <sys/tty.h> 56ae1f6b9eSfredette #include <sys/file.h> 57ae1f6b9eSfredette #include <sys/conf.h> 58ae1f6b9eSfredette #include <sys/device.h> 598ccb6c93Selad #include <sys/kauth.h> 60ae1f6b9eSfredette 61ae1f6b9eSfredette #include <machine/promlib.h> 62ae1f6b9eSfredette #include <machine/eeprom.h> 63ae1f6b9eSfredette #include <machine/psl.h> 64ae1f6b9eSfredette #include <machine/cpu.h> 65ae1f6b9eSfredette #include <machine/kbd.h> 66ae1f6b9eSfredette #include <machine/autoconf.h> 67ae1f6b9eSfredette 68ae1f6b9eSfredette #ifdef RASTERCONSOLE 69ae1f6b9eSfredette #include <dev/sun/fbio.h> 70ae1f6b9eSfredette #include <machine/fbvar.h> 71ae1f6b9eSfredette #endif 72ae1f6b9eSfredette 73ae1f6b9eSfredette 74ae1f6b9eSfredette #include <dev/cons.h> 75ae1f6b9eSfredette #include <dev/sun/event_var.h> 76ae1f6b9eSfredette #include <dev/sun/kbd_xlate.h> 77ae1f6b9eSfredette #include <dev/sun/kbdvar.h> 78ae1f6b9eSfredette #include <sun2/dev/cons.h> 79ae1f6b9eSfredette 80ae1f6b9eSfredette struct tty *fbconstty = 0; /* tty structure for frame buffer console */ 81ae1f6b9eSfredette 82ae1f6b9eSfredette #define PUT_WSIZE 64 83ae1f6b9eSfredette 84ae1f6b9eSfredette struct kd_softc { 85ae1f6b9eSfredette struct device kd_dev; /* required first: base device */ 86ae1f6b9eSfredette struct tty *kd_tty; 87ae1f6b9eSfredette int rows, cols; 88ae1f6b9eSfredette 89ae1f6b9eSfredette /* Console input hook */ 90ae1f6b9eSfredette struct cons_channel *kd_in; 91ae1f6b9eSfredette }; 92ae1f6b9eSfredette 93ae1f6b9eSfredette /* 94ae1f6b9eSfredette * There is no point in pretending there might be 95ae1f6b9eSfredette * more than one keyboard/display device. 96ae1f6b9eSfredette */ 97ae1f6b9eSfredette static struct kd_softc kd_softc; 98ae1f6b9eSfredette static int kd_is_console; 99ae1f6b9eSfredette 100ae1f6b9eSfredette static int kdparam(struct tty *, struct termios *); 101ae1f6b9eSfredette static void kdstart(struct tty *); 10210b1a7beSchs static void kd_init(struct kd_softc *); 10310b1a7beSchs static void kd_cons_input(int); 10410b1a7beSchs static int kdcngetc(dev_t); 105028d83d7She static void kd_later(void*); 106ae1f6b9eSfredette 10777a6b82bSgehenna dev_type_open(kdopen); 10877a6b82bSgehenna dev_type_close(kdclose); 10977a6b82bSgehenna dev_type_read(kdread); 11077a6b82bSgehenna dev_type_write(kdwrite); 11177a6b82bSgehenna dev_type_ioctl(kdioctl); 11277a6b82bSgehenna dev_type_tty(kdtty); 11377a6b82bSgehenna dev_type_poll(kdpoll); 11477a6b82bSgehenna 11577a6b82bSgehenna const struct cdevsw kd_cdevsw = { 11677a6b82bSgehenna kdopen, kdclose, kdread, kdwrite, kdioctl, 117e0cc03a0Sjdolecek nostop, kdtty, kdpoll, nommap, ttykqfilter, D_TTY 11877a6b82bSgehenna }; 11977a6b82bSgehenna 120ae1f6b9eSfredette /* 121ae1f6b9eSfredette * This is called by kbd_attach() 122ae1f6b9eSfredette * XXX - Make this a proper child of kbd? 123ae1f6b9eSfredette */ 124ae1f6b9eSfredette void 12510b1a7beSchs kd_init(struct kd_softc *kd) 126ae1f6b9eSfredette { 127ae1f6b9eSfredette struct tty *tp; 128ae1f6b9eSfredette #ifdef PROM_OLDMON 129ae1f6b9eSfredette struct eeprom *ep; 130ae1f6b9eSfredette #endif 131ae1f6b9eSfredette #ifdef notyet /* PROM_OBP_V2 */ 132ae1f6b9eSfredette int i; 133ae1f6b9eSfredette char *prop; 134ae1f6b9eSfredette #endif 135ae1f6b9eSfredette 136ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 137ae1f6b9eSfredette 138ae1f6b9eSfredette tp = ttymalloc(); 139d238692cSjoerg callout_setfunc(&tp->t_rstrt_ch, kd_later, tp); 140ae1f6b9eSfredette tp->t_oproc = kdstart; 141ae1f6b9eSfredette tp->t_param = kdparam; 14277a6b82bSgehenna tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 143ae1f6b9eSfredette 144ae1f6b9eSfredette tty_attach(tp); 145ae1f6b9eSfredette kd->kd_tty = tp; 146ae1f6b9eSfredette 147ae1f6b9eSfredette /* 148ae1f6b9eSfredette * get the console struct winsize. 149ae1f6b9eSfredette */ 150ae1f6b9eSfredette if (kd_is_console) { 151ae1f6b9eSfredette fbconstty = tp; 152ae1f6b9eSfredette #ifdef RASTERCONSOLE 153ae1f6b9eSfredette kd->rows = fbrcons_rows(); 154ae1f6b9eSfredette kd->cols = fbrcons_cols(); 155ae1f6b9eSfredette rcons_ttyinit(tp); 156ae1f6b9eSfredette #endif 157ae1f6b9eSfredette } 158ae1f6b9eSfredette 159ae1f6b9eSfredette /* else, consult the PROM */ 160ae1f6b9eSfredette switch (prom_version()) { 161ae1f6b9eSfredette #ifdef PROM_OLDMON 162ae1f6b9eSfredette case PROM_OLDMON: 163ae1f6b9eSfredette if ((ep = (struct eeprom *)eeprom_va) == NULL) 164ae1f6b9eSfredette break; 165ae1f6b9eSfredette if (kd->rows == 0) 166ae1f6b9eSfredette kd->rows = (u_short)ep->eeTtyRows; 167ae1f6b9eSfredette if (kd->cols == 0) 168ae1f6b9eSfredette kd->cols = (u_short)ep->eeTtyCols; 169ae1f6b9eSfredette break; 170ae1f6b9eSfredette #endif /* PROM_OLDMON */ 171ae1f6b9eSfredette #ifdef notyet /* PROM_OBP_V2 */ 172ae1f6b9eSfredette case PROM_OBP_V0: 173ae1f6b9eSfredette case PROM_OBP_V2: 174ae1f6b9eSfredette case PROM_OBP_V3: 175ae1f6b9eSfredette case PROM_OPENFIRM: 176ae1f6b9eSfredette 177ae1f6b9eSfredette if (kd->rows == 0 && 178ae1f6b9eSfredette (prop = PROM_getpropstring(optionsnode, "screen-#rows"))) { 179ae1f6b9eSfredette i = 0; 180ae1f6b9eSfredette while (*prop != '\0') 181ae1f6b9eSfredette i = i * 10 + *prop++ - '0'; 182ae1f6b9eSfredette kd->rows = (unsigned short)i; 183ae1f6b9eSfredette } 184ae1f6b9eSfredette if (kd->cols == 0 && 185ae1f6b9eSfredette (prop = PROM_getpropstring(optionsnode, "screen-#columns"))) { 186ae1f6b9eSfredette i = 0; 187ae1f6b9eSfredette while (*prop != '\0') 188ae1f6b9eSfredette i = i * 10 + *prop++ - '0'; 189ae1f6b9eSfredette kd->cols = (unsigned short)i; 190ae1f6b9eSfredette } 191ae1f6b9eSfredette break; 192ae1f6b9eSfredette #endif /* PROM_OBP_V2 */ 193ae1f6b9eSfredette } 194ae1f6b9eSfredette return; 195ae1f6b9eSfredette } 196ae1f6b9eSfredette 197ae1f6b9eSfredette struct tty * 19810b1a7beSchs kdtty(dev_t dev) 199ae1f6b9eSfredette { 200ae1f6b9eSfredette struct kd_softc *kd; 201ae1f6b9eSfredette 202ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 203ae1f6b9eSfredette return (kd->kd_tty); 204ae1f6b9eSfredette } 205ae1f6b9eSfredette 206ae1f6b9eSfredette int 20795e1ffb1Schristos kdopen(dev_t dev, int flag, int mode, struct lwp *l) 208ae1f6b9eSfredette { 209ae1f6b9eSfredette struct kd_softc *kd; 210ae1f6b9eSfredette int error, s, unit; 211ae1f6b9eSfredette struct tty *tp; 212ae1f6b9eSfredette static int firstopen = 1; 213ae1f6b9eSfredette 214ae1f6b9eSfredette unit = minor(dev); 215ae1f6b9eSfredette if (unit != 0) 216ae1f6b9eSfredette return ENXIO; 217ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 218ae1f6b9eSfredette 219ae1f6b9eSfredette if (firstopen) { 220ae1f6b9eSfredette kd_init(kd); 221ae1f6b9eSfredette firstopen = 0; 222ae1f6b9eSfredette } 223ae1f6b9eSfredette tp = kd->kd_tty; 224ae1f6b9eSfredette 225ae1f6b9eSfredette /* It's simpler to do this up here. */ 226e8373398Selad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 227ae1f6b9eSfredette return (EBUSY); 228ae1f6b9eSfredette 229ae1f6b9eSfredette s = spltty(); 230ae1f6b9eSfredette 231ae1f6b9eSfredette if ((tp->t_state & TS_ISOPEN) == 0) { 232ae1f6b9eSfredette /* First open. */ 233ae1f6b9eSfredette 234ae1f6b9eSfredette /* Notify the input device that serves us */ 235ae1f6b9eSfredette struct cons_channel *cc = kd->kd_in; 236ae1f6b9eSfredette if (cc != NULL && 237ae1f6b9eSfredette (error = (*cc->cc_iopen)(cc)) != 0) { 238ae1f6b9eSfredette splx(s); 239ae1f6b9eSfredette return (error); 240ae1f6b9eSfredette } 241ae1f6b9eSfredette 242ae1f6b9eSfredette ttychars(tp); 243ae1f6b9eSfredette tp->t_iflag = TTYDEF_IFLAG; 244ae1f6b9eSfredette tp->t_oflag = TTYDEF_OFLAG; 245ae1f6b9eSfredette tp->t_cflag = TTYDEF_CFLAG; 246ae1f6b9eSfredette tp->t_lflag = TTYDEF_LFLAG; 247ae1f6b9eSfredette tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 248ae1f6b9eSfredette (void) kdparam(tp, &tp->t_termios); 249ae1f6b9eSfredette ttsetwater(tp); 250ae1f6b9eSfredette tp->t_winsize.ws_row = kd->rows; 251ae1f6b9eSfredette tp->t_winsize.ws_col = kd->cols; 252ae1f6b9eSfredette /* Flush pending input? Clear translator? */ 253ae1f6b9eSfredette /* This (pseudo)device always has SOFTCAR */ 254ae1f6b9eSfredette tp->t_state |= TS_CARR_ON; 255ae1f6b9eSfredette } 256ae1f6b9eSfredette 257ae1f6b9eSfredette splx(s); 258ae1f6b9eSfredette 259ae1f6b9eSfredette return ((*tp->t_linesw->l_open)(dev, tp)); 260ae1f6b9eSfredette } 261ae1f6b9eSfredette 262ae1f6b9eSfredette int 26395e1ffb1Schristos kdclose(dev_t dev, int flag, int mode, struct lwp *l) 264ae1f6b9eSfredette { 265ae1f6b9eSfredette struct kd_softc *kd; 266ae1f6b9eSfredette struct tty *tp; 267ae1f6b9eSfredette struct cons_channel *cc; 268ae1f6b9eSfredette 269ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 270ae1f6b9eSfredette tp = kd->kd_tty; 271ae1f6b9eSfredette 272ae1f6b9eSfredette /* XXX This is for cons.c. */ 273ae1f6b9eSfredette if ((tp->t_state & TS_ISOPEN) == 0) 274ae1f6b9eSfredette return 0; 275ae1f6b9eSfredette 276ae1f6b9eSfredette (*tp->t_linesw->l_close)(tp, flag); 277ae1f6b9eSfredette ttyclose(tp); 278ae1f6b9eSfredette 279ae1f6b9eSfredette if ((cc = kd->kd_in) != NULL) 28057801e8fSmartin (void)(*cc->cc_iclose)(cc); 281ae1f6b9eSfredette 282ae1f6b9eSfredette return (0); 283ae1f6b9eSfredette } 284ae1f6b9eSfredette 285ae1f6b9eSfredette int 28610b1a7beSchs kdread(dev_t dev, struct uio *uio, int flag) 287ae1f6b9eSfredette { 288ae1f6b9eSfredette struct kd_softc *kd; 289ae1f6b9eSfredette struct tty *tp; 290ae1f6b9eSfredette 291ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 292ae1f6b9eSfredette tp = kd->kd_tty; 293ae1f6b9eSfredette 294ae1f6b9eSfredette return ((*tp->t_linesw->l_read)(tp, uio, flag)); 295ae1f6b9eSfredette } 296ae1f6b9eSfredette 297ae1f6b9eSfredette int 29810b1a7beSchs kdwrite(dev_t dev, struct uio *uio, int flag) 299ae1f6b9eSfredette { 300ae1f6b9eSfredette struct kd_softc *kd; 301ae1f6b9eSfredette struct tty *tp; 302ae1f6b9eSfredette 303ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 304ae1f6b9eSfredette tp = kd->kd_tty; 305ae1f6b9eSfredette 306ae1f6b9eSfredette return ((*tp->t_linesw->l_write)(tp, uio, flag)); 307ae1f6b9eSfredette } 308ae1f6b9eSfredette 309ae1f6b9eSfredette int 31095e1ffb1Schristos kdpoll(dev_t dev, int events, struct lwp *l) 311ae1f6b9eSfredette { 312ae1f6b9eSfredette struct kd_softc *kd; 313ae1f6b9eSfredette struct tty *tp; 314ae1f6b9eSfredette 315ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 316ae1f6b9eSfredette tp = kd->kd_tty; 317ae1f6b9eSfredette 31895e1ffb1Schristos return ((*tp->t_linesw->l_poll)(tp, events, l)); 319ae1f6b9eSfredette } 320ae1f6b9eSfredette 321ae1f6b9eSfredette int 32253524e44Schristos kdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 323ae1f6b9eSfredette { 324ae1f6b9eSfredette struct kd_softc *kd; 325ae1f6b9eSfredette struct tty *tp; 326ae1f6b9eSfredette int error; 327ae1f6b9eSfredette 328ae1f6b9eSfredette kd = &kd_softc; /* XXX */ 329ae1f6b9eSfredette tp = kd->kd_tty; 330ae1f6b9eSfredette 33195e1ffb1Schristos error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 332ae1f6b9eSfredette if (error != EPASSTHROUGH) 333ae1f6b9eSfredette return error; 334ae1f6b9eSfredette 33595e1ffb1Schristos error = ttioctl(tp, cmd, data, flag, l); 336ae1f6b9eSfredette if (error != EPASSTHROUGH) 337ae1f6b9eSfredette return error; 338ae1f6b9eSfredette 339ae1f6b9eSfredette /* Handle any ioctl commands specific to kbd/display. */ 340ae1f6b9eSfredette /* XXX - Send KB* ioctls to kbd module? */ 341ae1f6b9eSfredette /* XXX - Send FB* ioctls to fb module? */ 342ae1f6b9eSfredette 343ae1f6b9eSfredette return EPASSTHROUGH; 344ae1f6b9eSfredette } 345ae1f6b9eSfredette 346ae1f6b9eSfredette static int 34710b1a7beSchs kdparam(struct tty *tp, struct termios *t) 348ae1f6b9eSfredette { 349ae1f6b9eSfredette /* XXX - These are ignored... */ 350ae1f6b9eSfredette tp->t_ispeed = t->c_ispeed; 351ae1f6b9eSfredette tp->t_ospeed = t->c_ospeed; 352ae1f6b9eSfredette tp->t_cflag = t->c_cflag; 353ae1f6b9eSfredette return 0; 354ae1f6b9eSfredette } 355ae1f6b9eSfredette 356ae1f6b9eSfredette 357ae1f6b9eSfredette static void kd_putfb(struct tty *); 358ae1f6b9eSfredette 359ae1f6b9eSfredette static void 36010b1a7beSchs kdstart(struct tty *tp) 361ae1f6b9eSfredette { 362ae1f6b9eSfredette struct clist *cl; 36336bb413eSad int s1, s2; 364ae1f6b9eSfredette 36536bb413eSad s1 = splsoftclock(); 36636bb413eSad s2 = spltty(); 367ae1f6b9eSfredette if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 368ae1f6b9eSfredette goto out; 369ae1f6b9eSfredette 370ae1f6b9eSfredette cl = &tp->t_outq; 371*dc26833bSad if (ttypull(tp)) { 372ae1f6b9eSfredette if (kd_is_console) { 373ae1f6b9eSfredette tp->t_state |= TS_BUSY; 37436bb413eSad if (is_spl0(s1)) { 375ae1f6b9eSfredette /* called at level zero - update screen now. */ 37636bb413eSad splx(s2); 377ae1f6b9eSfredette kd_putfb(tp); 37836bb413eSad s2 = spltty(); 379ae1f6b9eSfredette tp->t_state &= ~TS_BUSY; 380ae1f6b9eSfredette } else { 381ae1f6b9eSfredette /* called at interrupt level - do it later */ 382d238692cSjoerg callout_schedule(&tp->t_rstrt_ch, 0); 383ae1f6b9eSfredette } 384ae1f6b9eSfredette } else { 385ae1f6b9eSfredette /* 386ae1f6b9eSfredette * This driver uses the PROM for writing the screen, 387ae1f6b9eSfredette * and that only works if this is the console device. 388ae1f6b9eSfredette * If this is not the console, just flush the output. 389ae1f6b9eSfredette * Sorry. (In that case, use xdm instead of getty.) 390ae1f6b9eSfredette */ 391ae1f6b9eSfredette ndflush(cl, cl->c_cc); 392ae1f6b9eSfredette } 393ae1f6b9eSfredette } 394ae1f6b9eSfredette out: 39536bb413eSad splx(s2); 39636bb413eSad splx(s1); 397ae1f6b9eSfredette } 398ae1f6b9eSfredette 399ae1f6b9eSfredette /* 400ae1f6b9eSfredette * Timeout function to do delayed writes to the screen. 401ae1f6b9eSfredette * Called at splsoftclock when requested by kdstart. 402ae1f6b9eSfredette */ 403ae1f6b9eSfredette static void 40410b1a7beSchs kd_later(void *tpaddr) 405ae1f6b9eSfredette { 406ae1f6b9eSfredette struct tty *tp = tpaddr; 40710b1a7beSchs int s; 408ae1f6b9eSfredette 409ae1f6b9eSfredette kd_putfb(tp); 410ae1f6b9eSfredette 411ae1f6b9eSfredette s = spltty(); 412ae1f6b9eSfredette tp->t_state &= ~TS_BUSY; 413ae1f6b9eSfredette (*tp->t_linesw->l_start)(tp); 414ae1f6b9eSfredette splx(s); 415ae1f6b9eSfredette } 416ae1f6b9eSfredette 417ae1f6b9eSfredette /* 418ae1f6b9eSfredette * Put text on the screen using the PROM monitor. 419ae1f6b9eSfredette * This can take a while, so to avoid missing 420ae1f6b9eSfredette * interrupts, this is called at splsoftclock. 421ae1f6b9eSfredette */ 422ae1f6b9eSfredette static void 42310b1a7beSchs kd_putfb(struct tty *tp) 424ae1f6b9eSfredette { 425ae1f6b9eSfredette char buf[PUT_WSIZE]; 426ae1f6b9eSfredette struct clist *cl = &tp->t_outq; 427ae1f6b9eSfredette char *p, *end; 428ae1f6b9eSfredette int len; 429ae1f6b9eSfredette 430ae1f6b9eSfredette while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 431ae1f6b9eSfredette /* PROM will barf if high bits are set. */ 432ae1f6b9eSfredette p = buf; 433ae1f6b9eSfredette end = buf + len; 434ae1f6b9eSfredette while (p < end) 435ae1f6b9eSfredette *p++ &= 0x7f; 436ae1f6b9eSfredette /* Now let the PROM print it. */ 437ae1f6b9eSfredette prom_putstr(buf, len); 438ae1f6b9eSfredette } 439ae1f6b9eSfredette } 440ae1f6b9eSfredette 441ae1f6b9eSfredette /* 442ae1f6b9eSfredette * Default PROM-based console input stream 443ae1f6b9eSfredette */ 44410b1a7beSchs static int kd_rom_iopen(struct cons_channel *); 44510b1a7beSchs static int kd_rom_iclose(struct cons_channel *); 446ae1f6b9eSfredette 447ae1f6b9eSfredette static struct cons_channel prom_cons_channel; 448ae1f6b9eSfredette 449ae1f6b9eSfredette int 45010b1a7beSchs kd_rom_iopen(struct cons_channel *cc) 451ae1f6b9eSfredette { 452ae1f6b9eSfredette return (0); 453ae1f6b9eSfredette } 454ae1f6b9eSfredette 455ae1f6b9eSfredette int 45610b1a7beSchs kd_rom_iclose(struct cons_channel *cc) 457ae1f6b9eSfredette { 458ae1f6b9eSfredette return (0); 459ae1f6b9eSfredette } 460ae1f6b9eSfredette 461ae1f6b9eSfredette /* 462ae1f6b9eSfredette * Our "interrupt" routine for input. This is called by 463ae1f6b9eSfredette * the keyboard driver (dev/sun/kbd.c) at spltty. 464ae1f6b9eSfredette */ 465ae1f6b9eSfredette void 46610b1a7beSchs kd_cons_input(int c) 467ae1f6b9eSfredette { 468ae1f6b9eSfredette struct kd_softc *kd = &kd_softc; 469ae1f6b9eSfredette struct tty *tp; 470ae1f6b9eSfredette 471ae1f6b9eSfredette /* XXX: Make sure the device is open. */ 472ae1f6b9eSfredette tp = kd->kd_tty; 473ae1f6b9eSfredette if (tp == NULL) 474ae1f6b9eSfredette return; 475ae1f6b9eSfredette if ((tp->t_state & TS_ISOPEN) == 0) 476ae1f6b9eSfredette return; 477ae1f6b9eSfredette 478ae1f6b9eSfredette (*tp->t_linesw->l_rint)(c, tp); 479ae1f6b9eSfredette } 480ae1f6b9eSfredette 481ae1f6b9eSfredette 482ae1f6b9eSfredette /**************************************************************** 483ae1f6b9eSfredette * kd console support 484ae1f6b9eSfredette ****************************************************************/ 485ae1f6b9eSfredette 486ae1f6b9eSfredette /* The debugger gets its own key translation state. */ 487ae1f6b9eSfredette static struct kbd_state *kdcn_state; 488ae1f6b9eSfredette 48910b1a7beSchs static void kdcnprobe(struct consdev *); 49010b1a7beSchs static void kdcninit(struct consdev *); 49110b1a7beSchs static void kdcnputc(dev_t, int); 49210b1a7beSchs static void kdcnpollc(dev_t, int); 493ae1f6b9eSfredette 494ae1f6b9eSfredette /* The keyboard driver uses cn_hw to access the real console driver */ 495ae1f6b9eSfredette extern struct consdev consdev_prom; 496ae1f6b9eSfredette struct consdev consdev_kd = { 497ae1f6b9eSfredette kdcnprobe, 498ae1f6b9eSfredette kdcninit, 499ae1f6b9eSfredette kdcngetc, 500ae1f6b9eSfredette kdcnputc, 501ae1f6b9eSfredette kdcnpollc, 502ae1f6b9eSfredette NULL, 503ae1f6b9eSfredette }; 504ae1f6b9eSfredette struct consdev *cn_hw = &consdev_kd; 505ae1f6b9eSfredette 506ae1f6b9eSfredette void 50710b1a7beSchs cons_attach_input(struct cons_channel *cc, struct consdev *cn) 508ae1f6b9eSfredette { 509ae1f6b9eSfredette struct kd_softc *kd = &kd_softc; 510ae1f6b9eSfredette struct kbd_softc *kds = cc->cc_dev; 511ae1f6b9eSfredette struct kbd_state *ks; 512ae1f6b9eSfredette 513ae1f6b9eSfredette /* Share the keyboard state */ 514ae1f6b9eSfredette kdcn_state = ks = &kds->k_state; 515ae1f6b9eSfredette 516ae1f6b9eSfredette kd->kd_in = cc; 517ae1f6b9eSfredette cc->cc_upstream = kd_cons_input; 518ae1f6b9eSfredette 519ae1f6b9eSfredette /* Attach lower level. */ 520ae1f6b9eSfredette cn_hw->cn_dev = cn->cn_dev; 521ae1f6b9eSfredette cn_hw->cn_pollc = cn->cn_pollc; 522ae1f6b9eSfredette cn_hw->cn_getc = cn->cn_getc; 523ae1f6b9eSfredette 524ae1f6b9eSfredette /* Attach us as console. */ 52577a6b82bSgehenna cn_tab->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 526ae1f6b9eSfredette cn_tab->cn_probe = kdcnprobe; 527ae1f6b9eSfredette cn_tab->cn_init = kdcninit; 528ae1f6b9eSfredette cn_tab->cn_getc = kdcngetc; 529ae1f6b9eSfredette cn_tab->cn_pollc = kdcnpollc; 530ae1f6b9eSfredette cn_tab->cn_pri = CN_INTERNAL; 531ae1f6b9eSfredette 532ae1f6b9eSfredette /* Set up initial PROM input channel for /dev/console */ 533ae1f6b9eSfredette prom_cons_channel.cc_dev = NULL; 534ae1f6b9eSfredette prom_cons_channel.cc_iopen = kd_rom_iopen; 535ae1f6b9eSfredette prom_cons_channel.cc_iclose = kd_rom_iclose; 536ae1f6b9eSfredette 537ae1f6b9eSfredette /* Indicate that it is OK to use the PROM fbwrite */ 538ae1f6b9eSfredette kd_is_console = 1; 539ae1f6b9eSfredette } 540ae1f6b9eSfredette 541ae1f6b9eSfredette 542ae1f6b9eSfredette void kd_attach_input(struct cons_channel *); 543ae1f6b9eSfredette void 54410b1a7beSchs kd_attach_input(struct cons_channel *cc) 545ae1f6b9eSfredette { 546ae1f6b9eSfredette struct kd_softc *kd = &kd_softc; 547ae1f6b9eSfredette 548ae1f6b9eSfredette kd->kd_in = cc; 549ae1f6b9eSfredette cc->cc_upstream = kd_cons_input; 550ae1f6b9eSfredette } 551ae1f6b9eSfredette 552ae1f6b9eSfredette 553ae1f6b9eSfredette /* We never call this. */ 554ae1f6b9eSfredette static void 55510b1a7beSchs kdcnprobe(struct consdev *cn) 556ae1f6b9eSfredette { 557ae1f6b9eSfredette } 558ae1f6b9eSfredette 559ae1f6b9eSfredette static void 56010b1a7beSchs kdcninit(struct consdev *cn) 561ae1f6b9eSfredette { 562ae1f6b9eSfredette #if 0 563ae1f6b9eSfredette struct kbd_state *ks = kdcn_state; 564ae1f6b9eSfredette 56577a6b82bSgehenna cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 566ae1f6b9eSfredette cn->cn_pri = CN_INTERNAL; 567ae1f6b9eSfredette 568ae1f6b9eSfredette /* This prepares kbd_translate() */ 569ae1f6b9eSfredette ks->kbd_id = KBD_MIN_TYPE; 570ae1f6b9eSfredette kbd_xlate_init(ks); 571ae1f6b9eSfredette 572ae1f6b9eSfredette /* Set up initial PROM input channel for /dev/console */ 573ae1f6b9eSfredette prom_cons_channel.cc_dev = NULL; 574ae1f6b9eSfredette prom_cons_channel.cc_iopen = kd_rom_iopen; 575ae1f6b9eSfredette prom_cons_channel.cc_iclose = kd_rom_iclose; 576ae1f6b9eSfredette cons_attach_input(&prom_cons_channel); 577ae1f6b9eSfredette 578ae1f6b9eSfredette /* Indicate that it is OK to use the PROM fbwrite */ 579ae1f6b9eSfredette kd_is_console = 1; 580ae1f6b9eSfredette #endif 581ae1f6b9eSfredette } 582ae1f6b9eSfredette 583ae1f6b9eSfredette static int 58410b1a7beSchs kdcngetc(dev_t dev) 585ae1f6b9eSfredette { 586ae1f6b9eSfredette struct kbd_state *ks = kdcn_state; 587ae1f6b9eSfredette int code, class, data, keysym; 58810b1a7beSchs extern int prom_cngetc(dev_t); 589ae1f6b9eSfredette 590ae1f6b9eSfredette 591ae1f6b9eSfredette if (cn_hw->cn_getc == prom_cngetc) return (*cn_hw->cn_getc)(dev); 592ae1f6b9eSfredette for (;;) { 593ae1f6b9eSfredette code = (*cn_hw->cn_getc)(dev); 594ae1f6b9eSfredette keysym = kbd_code_to_keysym(ks, code); 595ae1f6b9eSfredette class = KEYSYM_CLASS(keysym); 596ae1f6b9eSfredette 597ae1f6b9eSfredette switch (class) { 598ae1f6b9eSfredette case KEYSYM_ASCII: 599ae1f6b9eSfredette goto out; 600ae1f6b9eSfredette 601ae1f6b9eSfredette case KEYSYM_CLRMOD: 602ae1f6b9eSfredette case KEYSYM_SETMOD: 603ae1f6b9eSfredette data = (keysym & 0x1F); 604ae1f6b9eSfredette /* Only allow ctrl or shift. */ 605ae1f6b9eSfredette if (data > KBMOD_SHIFT_R) 606ae1f6b9eSfredette break; 607ae1f6b9eSfredette data = 1 << data; 608ae1f6b9eSfredette if (class == KEYSYM_SETMOD) 609ae1f6b9eSfredette ks->kbd_modbits |= data; 610ae1f6b9eSfredette else 611ae1f6b9eSfredette ks->kbd_modbits &= ~data; 612ae1f6b9eSfredette break; 613ae1f6b9eSfredette 614ae1f6b9eSfredette case KEYSYM_ALL_UP: 615ae1f6b9eSfredette /* No toggle keys here. */ 616ae1f6b9eSfredette ks->kbd_modbits = 0; 617ae1f6b9eSfredette break; 618ae1f6b9eSfredette 619ae1f6b9eSfredette default: /* ignore all other keysyms */ 620ae1f6b9eSfredette break; 621ae1f6b9eSfredette } 622ae1f6b9eSfredette } 623ae1f6b9eSfredette out: 624ae1f6b9eSfredette return (keysym); 625ae1f6b9eSfredette } 626ae1f6b9eSfredette 627ae1f6b9eSfredette static void 62810b1a7beSchs kdcnputc(dev_t dev, int c) 629ae1f6b9eSfredette { 630ae1f6b9eSfredette int s; 631ae1f6b9eSfredette 632ae1f6b9eSfredette s = splhigh(); 633ae1f6b9eSfredette prom_putchar(c); 634ae1f6b9eSfredette splx(s); 635ae1f6b9eSfredette } 636ae1f6b9eSfredette 637ae1f6b9eSfredette static void 63810b1a7beSchs kdcnpollc(dev_t dev, int on) 639ae1f6b9eSfredette { 640ae1f6b9eSfredette struct kbd_state *ks = kdcn_state; 641ae1f6b9eSfredette 642ae1f6b9eSfredette if (on) { 643ae1f6b9eSfredette /* Entering debugger. */ 644ae1f6b9eSfredette #if NFB > 0 645ae1f6b9eSfredette fb_unblank(); 646ae1f6b9eSfredette #endif 647ae1f6b9eSfredette /* Clear shift keys too. */ 648ae1f6b9eSfredette ks->kbd_modbits = 0; 649ae1f6b9eSfredette } else { 650ae1f6b9eSfredette /* Resuming kernel. */ 651ae1f6b9eSfredette } 652ae1f6b9eSfredette (*cn_hw->cn_pollc)(dev, on); 653ae1f6b9eSfredette } 654