1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * "Workstation console" multiplexor driver for Sun. 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * Sends output to the primary frame buffer using the PROM monitor; 33*7c478bd9Sstevel@tonic-gate * gets input from a stream linked below us that is the "keyboard 34*7c478bd9Sstevel@tonic-gate * driver", below which is linked the primary keyboard. 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/termios.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/termio.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/tty.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/buf.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/uio.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/strredir.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/console.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 65*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 66*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 67*7c478bd9Sstevel@tonic-gate #include <sys/terminal-emulator.h> 68*7c478bd9Sstevel@tonic-gate #endif 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #define MINLINES 10 71*7c478bd9Sstevel@tonic-gate #define MAXLINES 48 72*7c478bd9Sstevel@tonic-gate #define LOSCREENLINES 34 73*7c478bd9Sstevel@tonic-gate #define HISCREENLINES 48 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate #define MINCOLS 10 76*7c478bd9Sstevel@tonic-gate #define MAXCOLS 120 77*7c478bd9Sstevel@tonic-gate #define LOSCREENCOLS 80 78*7c478bd9Sstevel@tonic-gate #define HISCREENCOLS 120 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate static struct wscons { 81*7c478bd9Sstevel@tonic-gate int wc_flags; /* random flags (protected by */ 82*7c478bd9Sstevel@tonic-gate /* write-side exclusion lock */ 83*7c478bd9Sstevel@tonic-gate dev_t wc_dev; /* major/minor for this device */ 84*7c478bd9Sstevel@tonic-gate tty_common_t wc_ttycommon; /* data common to all tty drivers */ 85*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 86*7c478bd9Sstevel@tonic-gate int wc_pendc; /* pending output character */ 87*7c478bd9Sstevel@tonic-gate int wc_defer_output; /* set if output device is "slow" */ 88*7c478bd9Sstevel@tonic-gate #endif 89*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 90*7c478bd9Sstevel@tonic-gate struct terminal_emulator *wc_tem; /* Terminal emulator state */ 91*7c478bd9Sstevel@tonic-gate #endif 92*7c478bd9Sstevel@tonic-gate queue_t *wc_kbdqueue; /* "console keyboard" device queue */ 93*7c478bd9Sstevel@tonic-gate /* below us */ 94*7c478bd9Sstevel@tonic-gate bufcall_id_t wc_bufcallid; /* id returned by qbufcall */ 95*7c478bd9Sstevel@tonic-gate timeout_id_t wc_timeoutid; /* id returned by qtimeout */ 96*7c478bd9Sstevel@tonic-gate cons_polledio_t wc_polledio; /* polled I/O function pointers */ 97*7c478bd9Sstevel@tonic-gate cons_polledio_t *wc_kb_polledio; /* keyboard's polledio */ 98*7c478bd9Sstevel@tonic-gate unsigned int wc_kb_getpolledio_id; /* id for kb CONSOPENPOLLEDIO */ 99*7c478bd9Sstevel@tonic-gate mblk_t *wc_pending_link; /* I_PLINK pending for kb polledio */ 100*7c478bd9Sstevel@tonic-gate } wscons; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate #define WCS_ISOPEN 0x00000001 /* open is complete */ 103*7c478bd9Sstevel@tonic-gate #define WCS_STOPPED 0x00000002 /* output is stopped */ 104*7c478bd9Sstevel@tonic-gate #define WCS_DELAY 0x00000004 /* waiting for delay to finish */ 105*7c478bd9Sstevel@tonic-gate #define WCS_BUSY 0x00000008 /* waiting for transmission to finish */ 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate static int wcopen(queue_t *, dev_t *, int, int, cred_t *); 108*7c478bd9Sstevel@tonic-gate static int wcclose(queue_t *, int, cred_t *); 109*7c478bd9Sstevel@tonic-gate static int wcuwput(queue_t *, mblk_t *); 110*7c478bd9Sstevel@tonic-gate static int wclrput(queue_t *, mblk_t *); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate static struct module_info wcm_info = { 113*7c478bd9Sstevel@tonic-gate 0, 114*7c478bd9Sstevel@tonic-gate "wc", 115*7c478bd9Sstevel@tonic-gate 0, 116*7c478bd9Sstevel@tonic-gate INFPSZ, 117*7c478bd9Sstevel@tonic-gate 2048, 118*7c478bd9Sstevel@tonic-gate 128 119*7c478bd9Sstevel@tonic-gate }; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate static struct qinit wcurinit = { 122*7c478bd9Sstevel@tonic-gate putq, 123*7c478bd9Sstevel@tonic-gate NULL, 124*7c478bd9Sstevel@tonic-gate wcopen, 125*7c478bd9Sstevel@tonic-gate wcclose, 126*7c478bd9Sstevel@tonic-gate NULL, 127*7c478bd9Sstevel@tonic-gate &wcm_info, 128*7c478bd9Sstevel@tonic-gate NULL 129*7c478bd9Sstevel@tonic-gate }; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate static struct qinit wcuwinit = { 132*7c478bd9Sstevel@tonic-gate wcuwput, 133*7c478bd9Sstevel@tonic-gate NULL, 134*7c478bd9Sstevel@tonic-gate wcopen, 135*7c478bd9Sstevel@tonic-gate wcclose, 136*7c478bd9Sstevel@tonic-gate NULL, 137*7c478bd9Sstevel@tonic-gate &wcm_info, 138*7c478bd9Sstevel@tonic-gate NULL 139*7c478bd9Sstevel@tonic-gate }; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate static struct qinit wclrinit = { 142*7c478bd9Sstevel@tonic-gate wclrput, 143*7c478bd9Sstevel@tonic-gate NULL, 144*7c478bd9Sstevel@tonic-gate NULL, 145*7c478bd9Sstevel@tonic-gate NULL, 146*7c478bd9Sstevel@tonic-gate NULL, 147*7c478bd9Sstevel@tonic-gate &wcm_info, 148*7c478bd9Sstevel@tonic-gate NULL 149*7c478bd9Sstevel@tonic-gate }; 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * We always putnext directly to the underlying queue. 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate static struct qinit wclwinit = { 155*7c478bd9Sstevel@tonic-gate NULL, 156*7c478bd9Sstevel@tonic-gate NULL, 157*7c478bd9Sstevel@tonic-gate NULL, 158*7c478bd9Sstevel@tonic-gate NULL, 159*7c478bd9Sstevel@tonic-gate NULL, 160*7c478bd9Sstevel@tonic-gate &wcm_info, 161*7c478bd9Sstevel@tonic-gate NULL 162*7c478bd9Sstevel@tonic-gate }; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate static struct streamtab wcinfo = { 165*7c478bd9Sstevel@tonic-gate &wcurinit, 166*7c478bd9Sstevel@tonic-gate &wcuwinit, 167*7c478bd9Sstevel@tonic-gate &wclrinit, 168*7c478bd9Sstevel@tonic-gate &wclwinit, 169*7c478bd9Sstevel@tonic-gate }; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate static int wc_info(dev_info_t *, ddi_info_cmd_t, void *, void **result); 172*7c478bd9Sstevel@tonic-gate static int wc_attach(dev_info_t *, ddi_attach_cmd_t); 173*7c478bd9Sstevel@tonic-gate static dev_info_t *wc_dip; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(wc_ops, nulldev, nulldev, wc_attach, nodev, nodev, 176*7c478bd9Sstevel@tonic-gate wc_info, D_MTPERMOD | D_MP, &wcinfo); 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate static void wcreioctl(void *); 179*7c478bd9Sstevel@tonic-gate static void wcioctl(queue_t *, mblk_t *); 180*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 181*7c478bd9Sstevel@tonic-gate static void wcopoll(void *); 182*7c478bd9Sstevel@tonic-gate static void wconsout(void *); 183*7c478bd9Sstevel@tonic-gate #endif 184*7c478bd9Sstevel@tonic-gate static void wcrstrt(void *); 185*7c478bd9Sstevel@tonic-gate static void wcstart(void); 186*7c478bd9Sstevel@tonic-gate static void wc_open_kb_polledio(struct wscons *wc, queue_t *q, mblk_t *mp); 187*7c478bd9Sstevel@tonic-gate static void wc_close_kb_polledio(struct wscons *wc, queue_t *q, mblk_t *mp); 188*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 189*7c478bd9Sstevel@tonic-gate static void wc_putchar(struct cons_polledio_arg *arg, unsigned char c); 190*7c478bd9Sstevel@tonic-gate #endif 191*7c478bd9Sstevel@tonic-gate static boolean_t wc_ischar(struct cons_polledio_arg *arg); 192*7c478bd9Sstevel@tonic-gate static int wc_getchar(struct cons_polledio_arg *arg); 193*7c478bd9Sstevel@tonic-gate static void wc_polled_enter(struct cons_polledio_arg *arg); 194*7c478bd9Sstevel@tonic-gate static void wc_polled_exit(struct cons_polledio_arg *arg); 195*7c478bd9Sstevel@tonic-gate static void wc_get_size(struct wscons *wscons); 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 198*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 199*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 200*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 201*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 202*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate static struct dev_ops wc_ops; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * Debug printing 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate #ifndef DPRINTF 210*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 211*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 212*7c478bd9Sstevel@tonic-gate static void wc_dprintf(const char *fmt, ...) __KPRINTFLIKE(1); 213*7c478bd9Sstevel@tonic-gate #define DPRINTF(l, m, args) \ 214*7c478bd9Sstevel@tonic-gate (((l) >= wc_errlevel) && ((m) & wc_errmask) ? \ 215*7c478bd9Sstevel@tonic-gate wc_dprintf args : \ 216*7c478bd9Sstevel@tonic-gate (void) 0) 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate /* 219*7c478bd9Sstevel@tonic-gate * Severity levels for printing 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate #define PRINT_L0 0 /* print every message */ 222*7c478bd9Sstevel@tonic-gate #define PRINT_L1 1 /* debug */ 223*7c478bd9Sstevel@tonic-gate #define PRINT_L2 2 /* quiet */ 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * Masks 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate #define PRINT_MASK_ALL 0xFFFFFFFFU 229*7c478bd9Sstevel@tonic-gate uint_t wc_errmask = PRINT_MASK_ALL; 230*7c478bd9Sstevel@tonic-gate uint_t wc_errlevel = PRINT_L2; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate #else 233*7c478bd9Sstevel@tonic-gate #define DPRINTF(l, m, args) /* NOTHING */ 234*7c478bd9Sstevel@tonic-gate #endif 235*7c478bd9Sstevel@tonic-gate #endif 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 239*7c478bd9Sstevel@tonic-gate */ 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 242*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 243*7c478bd9Sstevel@tonic-gate "Workstation multiplexer Driver 'wc' %I%", 244*7c478bd9Sstevel@tonic-gate &wc_ops, /* driver ops */ 245*7c478bd9Sstevel@tonic-gate }; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 248*7c478bd9Sstevel@tonic-gate MODREV_1, 249*7c478bd9Sstevel@tonic-gate &modldrv, 250*7c478bd9Sstevel@tonic-gate NULL 251*7c478bd9Sstevel@tonic-gate }; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate int 254*7c478bd9Sstevel@tonic-gate _init(void) 255*7c478bd9Sstevel@tonic-gate { 256*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate int 260*7c478bd9Sstevel@tonic-gate _fini(void) 261*7c478bd9Sstevel@tonic-gate { 262*7c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate int 266*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 272*7c478bd9Sstevel@tonic-gate static int 273*7c478bd9Sstevel@tonic-gate wc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 274*7c478bd9Sstevel@tonic-gate { 275*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "wscons", S_IFCHR, 276*7c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 277*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 278*7c478bd9Sstevel@tonic-gate return (-1); 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate wc_dip = devi; 281*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 285*7c478bd9Sstevel@tonic-gate static int 286*7c478bd9Sstevel@tonic-gate wc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 287*7c478bd9Sstevel@tonic-gate void **result) 288*7c478bd9Sstevel@tonic-gate { 289*7c478bd9Sstevel@tonic-gate int error; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate switch (infocmd) { 292*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 293*7c478bd9Sstevel@tonic-gate if (wc_dip == NULL) { 294*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 295*7c478bd9Sstevel@tonic-gate } else { 296*7c478bd9Sstevel@tonic-gate *result = (void *) wc_dip; 297*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate break; 300*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 301*7c478bd9Sstevel@tonic-gate *result = (void *)0; 302*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 303*7c478bd9Sstevel@tonic-gate break; 304*7c478bd9Sstevel@tonic-gate default: 305*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate return (error); 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 311*7c478bd9Sstevel@tonic-gate /* 312*7c478bd9Sstevel@tonic-gate * Output buffer. Protected by the per-module inner perimeter. 313*7c478bd9Sstevel@tonic-gate */ 314*7c478bd9Sstevel@tonic-gate #define MAXHIWAT 2000 315*7c478bd9Sstevel@tonic-gate static char obuf[MAXHIWAT]; 316*7c478bd9Sstevel@tonic-gate #endif 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 319*7c478bd9Sstevel@tonic-gate static int 320*7c478bd9Sstevel@tonic-gate wcopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 321*7c478bd9Sstevel@tonic-gate { 322*7c478bd9Sstevel@tonic-gate struct termios *termiosp; 323*7c478bd9Sstevel@tonic-gate int len; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate if (getminor(*devp) != 0) 326*7c478bd9Sstevel@tonic-gate return (ENXIO); /* sorry, only one per customer */ 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate if (!(wscons.wc_flags & WCS_ISOPEN)) { 329*7c478bd9Sstevel@tonic-gate mutex_init(&wscons.wc_ttycommon.t_excl, NULL, MUTEX_DEFAULT, 330*7c478bd9Sstevel@tonic-gate NULL); 331*7c478bd9Sstevel@tonic-gate wscons.wc_ttycommon.t_iflag = 0; 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Get the default termios settings (cflag). 334*7c478bd9Sstevel@tonic-gate * These are stored as a property in the 335*7c478bd9Sstevel@tonic-gate * "options" node. 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 338*7c478bd9Sstevel@tonic-gate ddi_root_node(), 0, "ttymodes", 339*7c478bd9Sstevel@tonic-gate (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS && 340*7c478bd9Sstevel@tonic-gate len == sizeof (struct termios)) { 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate wscons.wc_ttycommon.t_cflag = termiosp->c_cflag; 343*7c478bd9Sstevel@tonic-gate kmem_free(termiosp, len); 344*7c478bd9Sstevel@tonic-gate } else { 345*7c478bd9Sstevel@tonic-gate /* 346*7c478bd9Sstevel@tonic-gate * Gack! Whine about it. 347*7c478bd9Sstevel@tonic-gate */ 348*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 349*7c478bd9Sstevel@tonic-gate "wc: Couldn't get ttymodes property!\n"); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate wscons.wc_ttycommon.t_iocpending = NULL; 352*7c478bd9Sstevel@tonic-gate wscons.wc_flags = WCS_ISOPEN; 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate wc_get_size(&wscons); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate bzero(&(wscons.wc_polledio), sizeof (wscons.wc_polledio)); 357*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_version = CONSPOLLEDIO_V0; 358*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_argument = 359*7c478bd9Sstevel@tonic-gate (struct cons_polledio_arg *)&wscons; 360*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 361*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_putchar = wc_putchar; 362*7c478bd9Sstevel@tonic-gate #else 363*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_putchar = NULL; 364*7c478bd9Sstevel@tonic-gate #endif 365*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_getchar = wc_getchar; 366*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_ischar = wc_ischar; 367*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_enter = wc_polled_enter; 368*7c478bd9Sstevel@tonic-gate wscons.wc_polledio.cons_polledio_exit = wc_polled_exit; 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * If we're talking directly to a framebuffer, we assume 373*7c478bd9Sstevel@tonic-gate * that it's a "slow" device, so that rendering should be 374*7c478bd9Sstevel@tonic-gate * deferred to a timeout or softcall so that we write 375*7c478bd9Sstevel@tonic-gate * a bunch of characters at once. 376*7c478bd9Sstevel@tonic-gate */ 377*7c478bd9Sstevel@tonic-gate wscons.wc_defer_output = prom_stdout_is_framebuffer(); 378*7c478bd9Sstevel@tonic-gate #endif 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate if (wscons.wc_ttycommon.t_flags & TS_XCLUDE) { 382*7c478bd9Sstevel@tonic-gate if (secpolicy_excl_open(crp) != 0) { 383*7c478bd9Sstevel@tonic-gate return (EBUSY); 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate wscons.wc_ttycommon.t_readq = q; 387*7c478bd9Sstevel@tonic-gate wscons.wc_ttycommon.t_writeq = WR(q); 388*7c478bd9Sstevel@tonic-gate qprocson(q); 389*7c478bd9Sstevel@tonic-gate return (0); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 393*7c478bd9Sstevel@tonic-gate static int 394*7c478bd9Sstevel@tonic-gate wcclose(queue_t *q, int flag, cred_t *crp) 395*7c478bd9Sstevel@tonic-gate { 396*7c478bd9Sstevel@tonic-gate qprocsoff(q); 397*7c478bd9Sstevel@tonic-gate if (wscons.wc_bufcallid != 0) { 398*7c478bd9Sstevel@tonic-gate qunbufcall(q, wscons.wc_bufcallid); 399*7c478bd9Sstevel@tonic-gate wscons.wc_bufcallid = 0; 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate if (wscons.wc_timeoutid != 0) { 402*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, wscons.wc_timeoutid); 403*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid = 0; 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate ttycommon_close(&wscons.wc_ttycommon); 406*7c478bd9Sstevel@tonic-gate wscons.wc_flags = 0; 407*7c478bd9Sstevel@tonic-gate return (0); 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate /* 411*7c478bd9Sstevel@tonic-gate * Put procedure for upper write queue. 412*7c478bd9Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 413*7c478bd9Sstevel@tonic-gate * queue up M_BREAK, M_DELAY, and M_DATA messages for processing by 414*7c478bd9Sstevel@tonic-gate * the start routine, and then call the start routine; discard 415*7c478bd9Sstevel@tonic-gate * everything else. 416*7c478bd9Sstevel@tonic-gate */ 417*7c478bd9Sstevel@tonic-gate static int 418*7c478bd9Sstevel@tonic-gate wcuwput(queue_t *q, mblk_t *mp) 419*7c478bd9Sstevel@tonic-gate { 420*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate case M_STOP: 423*7c478bd9Sstevel@tonic-gate wscons.wc_flags |= WCS_STOPPED; 424*7c478bd9Sstevel@tonic-gate freemsg(mp); 425*7c478bd9Sstevel@tonic-gate break; 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate case M_START: 428*7c478bd9Sstevel@tonic-gate wscons.wc_flags &= ~WCS_STOPPED; 429*7c478bd9Sstevel@tonic-gate wcstart(); 430*7c478bd9Sstevel@tonic-gate freemsg(mp); 431*7c478bd9Sstevel@tonic-gate break; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate case M_IOCTL: { 434*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 435*7c478bd9Sstevel@tonic-gate struct linkblk *linkp; 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 438*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate case I_LINK: /* stupid, but permitted */ 441*7c478bd9Sstevel@tonic-gate case I_PLINK: 442*7c478bd9Sstevel@tonic-gate if (wscons.wc_kbdqueue != NULL) { 443*7c478bd9Sstevel@tonic-gate /* somebody already linked */ 444*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 445*7c478bd9Sstevel@tonic-gate return (0); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr; 448*7c478bd9Sstevel@tonic-gate wscons.wc_kbdqueue = WR(linkp->l_qbot); 449*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 450*7c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 451*7c478bd9Sstevel@tonic-gate wc_open_kb_polledio(&wscons, q, mp); 452*7c478bd9Sstevel@tonic-gate break; 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate case I_UNLINK: /* stupid, but permitted */ 455*7c478bd9Sstevel@tonic-gate case I_PUNLINK: 456*7c478bd9Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr; 457*7c478bd9Sstevel@tonic-gate if (wscons.wc_kbdqueue != WR(linkp->l_qbot)) { 458*7c478bd9Sstevel@tonic-gate /* not us */ 459*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 460*7c478bd9Sstevel@tonic-gate return (0); 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 464*7c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 465*7c478bd9Sstevel@tonic-gate wc_close_kb_polledio(&wscons, q, mp); 466*7c478bd9Sstevel@tonic-gate break; 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate case TCSETSW: 469*7c478bd9Sstevel@tonic-gate case TCSETSF: 470*7c478bd9Sstevel@tonic-gate case TCSETAW: 471*7c478bd9Sstevel@tonic-gate case TCSETAF: 472*7c478bd9Sstevel@tonic-gate case TCSBRK: 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * The changes do not take effect until all 475*7c478bd9Sstevel@tonic-gate * output queued before them is drained. 476*7c478bd9Sstevel@tonic-gate * Put this message on the queue, so that 477*7c478bd9Sstevel@tonic-gate * "wcstart" will see it when it's done 478*7c478bd9Sstevel@tonic-gate * with the output before it. Poke the 479*7c478bd9Sstevel@tonic-gate * start routine, just in case. 480*7c478bd9Sstevel@tonic-gate */ 481*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 482*7c478bd9Sstevel@tonic-gate wcstart(); 483*7c478bd9Sstevel@tonic-gate break; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate case CONSSETABORTENABLE: 486*7c478bd9Sstevel@tonic-gate case CONSGETABORTENABLE: 487*7c478bd9Sstevel@tonic-gate case KIOCSDIRECT: 488*7c478bd9Sstevel@tonic-gate if (wscons.wc_kbdqueue != NULL) { 489*7c478bd9Sstevel@tonic-gate (void) putnext(wscons.wc_kbdqueue, mp); 490*7c478bd9Sstevel@tonic-gate break; 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate /* fall through */ 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate default: 495*7c478bd9Sstevel@tonic-gate /* 496*7c478bd9Sstevel@tonic-gate * Do it now. 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate wcioctl(q, mp); 499*7c478bd9Sstevel@tonic-gate break; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate break; 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate case M_FLUSH: 505*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 506*7c478bd9Sstevel@tonic-gate /* 507*7c478bd9Sstevel@tonic-gate * Flush our write queue. 508*7c478bd9Sstevel@tonic-gate */ 509*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 510*7c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 513*7c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 514*7c478bd9Sstevel@tonic-gate qreply(q, mp); /* give the read queues a crack at it */ 515*7c478bd9Sstevel@tonic-gate } else 516*7c478bd9Sstevel@tonic-gate freemsg(mp); 517*7c478bd9Sstevel@tonic-gate break; 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate case M_BREAK: 520*7c478bd9Sstevel@tonic-gate /* 521*7c478bd9Sstevel@tonic-gate * Ignore these, as they make no sense. 522*7c478bd9Sstevel@tonic-gate */ 523*7c478bd9Sstevel@tonic-gate freemsg(mp); 524*7c478bd9Sstevel@tonic-gate break; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate case M_DELAY: 527*7c478bd9Sstevel@tonic-gate case M_DATA: 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * Queue the message up to be transmitted, 530*7c478bd9Sstevel@tonic-gate * and poke the start routine. 531*7c478bd9Sstevel@tonic-gate */ 532*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 533*7c478bd9Sstevel@tonic-gate wcstart(); 534*7c478bd9Sstevel@tonic-gate break; 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate default: 537*7c478bd9Sstevel@tonic-gate /* 538*7c478bd9Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age, 539*7c478bd9Sstevel@tonic-gate * thank you anyway." 540*7c478bd9Sstevel@tonic-gate */ 541*7c478bd9Sstevel@tonic-gate freemsg(mp); 542*7c478bd9Sstevel@tonic-gate break; 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate return (0); 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate /* 549*7c478bd9Sstevel@tonic-gate * Retry an "ioctl", now that "qbufcall" claims we may be able to allocate 550*7c478bd9Sstevel@tonic-gate * the buffer we need. 551*7c478bd9Sstevel@tonic-gate */ 552*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 553*7c478bd9Sstevel@tonic-gate static void 554*7c478bd9Sstevel@tonic-gate wcreioctl(void *arg) 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate queue_t *q; 557*7c478bd9Sstevel@tonic-gate mblk_t *mp; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate wscons.wc_bufcallid = 0; 560*7c478bd9Sstevel@tonic-gate q = wscons.wc_ttycommon.t_writeq; 561*7c478bd9Sstevel@tonic-gate if ((mp = wscons.wc_ttycommon.t_iocpending) != NULL) { 562*7c478bd9Sstevel@tonic-gate /* not pending any more */ 563*7c478bd9Sstevel@tonic-gate wscons.wc_ttycommon.t_iocpending = NULL; 564*7c478bd9Sstevel@tonic-gate wcioctl(q, mp); 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate /* 569*7c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 570*7c478bd9Sstevel@tonic-gate */ 571*7c478bd9Sstevel@tonic-gate static void 572*7c478bd9Sstevel@tonic-gate wcioctl(queue_t *q, mblk_t *mp) 573*7c478bd9Sstevel@tonic-gate { 574*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 575*7c478bd9Sstevel@tonic-gate size_t datasize; 576*7c478bd9Sstevel@tonic-gate int error; 577*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 578*7c478bd9Sstevel@tonic-gate int len; 579*7c478bd9Sstevel@tonic-gate #endif 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 584*7c478bd9Sstevel@tonic-gate case TIOCSWINSZ: 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate * Ignore all attempts to set the screen size; the 587*7c478bd9Sstevel@tonic-gate * value in the EEPROM is guaranteed (modulo PROM bugs) 588*7c478bd9Sstevel@tonic-gate * to be the value used by the PROM monitor code, so it 589*7c478bd9Sstevel@tonic-gate * is by definition correct. Many programs (e.g., 590*7c478bd9Sstevel@tonic-gate * "login" and "tset") will attempt to reset the size 591*7c478bd9Sstevel@tonic-gate * to (0, 0) or (34, 80), neither of which is 592*7c478bd9Sstevel@tonic-gate * necessarily correct. 593*7c478bd9Sstevel@tonic-gate * We just ACK the message, so as not to disturb 594*7c478bd9Sstevel@tonic-gate * programs that set the sizes. 595*7c478bd9Sstevel@tonic-gate */ 596*7c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 597*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 598*7c478bd9Sstevel@tonic-gate qreply(q, mp); 599*7c478bd9Sstevel@tonic-gate return; 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate case CONSOPENPOLLEDIO: 602*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 603*7c478bd9Sstevel@tonic-gate ("wcioctl: CONSOPENPOLLEDIO\n")); 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct cons_polledio *)); 606*7c478bd9Sstevel@tonic-gate if (error != 0) { 607*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 608*7c478bd9Sstevel@tonic-gate return; 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * If the keyboard driver does not support polled I/O 613*7c478bd9Sstevel@tonic-gate * then NAK this request. 614*7c478bd9Sstevel@tonic-gate */ 615*7c478bd9Sstevel@tonic-gate if (wscons.wc_kb_polledio != NULL) { 616*7c478bd9Sstevel@tonic-gate /* 617*7c478bd9Sstevel@tonic-gate * We are given an appropriate-sized data block, 618*7c478bd9Sstevel@tonic-gate * and return a pointer to our structure in it. 619*7c478bd9Sstevel@tonic-gate */ 620*7c478bd9Sstevel@tonic-gate *(struct cons_polledio **)mp->b_cont->b_rptr = 621*7c478bd9Sstevel@tonic-gate &wscons.wc_polledio; 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 624*7c478bd9Sstevel@tonic-gate } else { 625*7c478bd9Sstevel@tonic-gate /* 626*7c478bd9Sstevel@tonic-gate * The driver does not support polled mode, so NAK 627*7c478bd9Sstevel@tonic-gate * the request. 628*7c478bd9Sstevel@tonic-gate */ 629*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, ENXIO); 630*7c478bd9Sstevel@tonic-gate return; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate qreply(q, mp); 634*7c478bd9Sstevel@tonic-gate break; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 637*7c478bd9Sstevel@tonic-gate case WC_OPEN_FB: 638*7c478bd9Sstevel@tonic-gate /* 639*7c478bd9Sstevel@tonic-gate * Start out pessimistic, so that we can just jump to 640*7c478bd9Sstevel@tonic-gate * the reply to bail out. 641*7c478bd9Sstevel@tonic-gate */ 642*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate /* 645*7c478bd9Sstevel@tonic-gate * First test: really, this should be done only from 646*7c478bd9Sstevel@tonic-gate * inside the kernel. Unfortunately, that information 647*7c478bd9Sstevel@tonic-gate * doesn't seem to be available in a streams ioctl, 648*7c478bd9Sstevel@tonic-gate * so restrict it to root only. (Perhaps we could check 649*7c478bd9Sstevel@tonic-gate * for ioc_cr == kcred.) 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate if ((iocp->ioc_error = secpolicy_console(iocp->ioc_cr)) != 0) 652*7c478bd9Sstevel@tonic-gate goto open_fail; 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate /* 655*7c478bd9Sstevel@tonic-gate * Some miscellaneous checks... 656*7c478bd9Sstevel@tonic-gate */ 657*7c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL; 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* 660*7c478bd9Sstevel@tonic-gate * If we're already open, fail. 661*7c478bd9Sstevel@tonic-gate */ 662*7c478bd9Sstevel@tonic-gate if (wscons.wc_tem != NULL) 663*7c478bd9Sstevel@tonic-gate goto open_fail; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate /* 666*7c478bd9Sstevel@tonic-gate * If we don't have exactly one continuation block, fail. 667*7c478bd9Sstevel@tonic-gate */ 668*7c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL || 669*7c478bd9Sstevel@tonic-gate mp->b_cont->b_cont != NULL) 670*7c478bd9Sstevel@tonic-gate goto open_fail; 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate /* 673*7c478bd9Sstevel@tonic-gate * If there's no null terminator in the string, fail. 674*7c478bd9Sstevel@tonic-gate */ 675*7c478bd9Sstevel@tonic-gate len = mp->b_cont->b_wptr - mp->b_cont->b_rptr; 676*7c478bd9Sstevel@tonic-gate if (memchr(mp->b_cont->b_rptr, 0, len) == NULL) 677*7c478bd9Sstevel@tonic-gate goto open_fail; 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate /* 680*7c478bd9Sstevel@tonic-gate * NOTE: should eventually get default 681*7c478bd9Sstevel@tonic-gate * dimensions from a property, e.g. screen-#rows. 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate iocp->ioc_error = tem_init(&wscons.wc_tem, 684*7c478bd9Sstevel@tonic-gate (char *)mp->b_cont->b_rptr, iocp->ioc_cr, 685*7c478bd9Sstevel@tonic-gate 0, 0); 686*7c478bd9Sstevel@tonic-gate /* 687*7c478bd9Sstevel@tonic-gate * Of course, if the terminal emulator initialization 688*7c478bd9Sstevel@tonic-gate * failed, fail. 689*7c478bd9Sstevel@tonic-gate */ 690*7c478bd9Sstevel@tonic-gate if (iocp->ioc_error != 0) 691*7c478bd9Sstevel@tonic-gate goto open_fail; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * Refresh terminal size with info from terminal emulator. 695*7c478bd9Sstevel@tonic-gate */ 696*7c478bd9Sstevel@tonic-gate wc_get_size(&wscons); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* 699*7c478bd9Sstevel@tonic-gate * ... and succeed. 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate open_fail: 704*7c478bd9Sstevel@tonic-gate qreply(q, mp); 705*7c478bd9Sstevel@tonic-gate break; 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate case WC_CLOSE_FB: 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * There's nothing that can call this, so it's not 710*7c478bd9Sstevel@tonic-gate * really implemented. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 713*7c478bd9Sstevel@tonic-gate /* 714*7c478bd9Sstevel@tonic-gate * However, if it were implemented, it would clearly 715*7c478bd9Sstevel@tonic-gate * be root-only. 716*7c478bd9Sstevel@tonic-gate */ 717*7c478bd9Sstevel@tonic-gate if ((iocp->ioc_error = secpolicy_console(iocp->ioc_cr)) != 0) 718*7c478bd9Sstevel@tonic-gate goto close_fail; 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL; 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate close_fail: 723*7c478bd9Sstevel@tonic-gate qreply(q, mp); 724*7c478bd9Sstevel@tonic-gate break; 725*7c478bd9Sstevel@tonic-gate #endif 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate default: 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate /* 730*7c478bd9Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is 731*7c478bd9Sstevel@tonic-gate * if the "ioctl" requires a response containing data 732*7c478bd9Sstevel@tonic-gate * to be returned to the user, and no mblk could be 733*7c478bd9Sstevel@tonic-gate * allocated for the data. No such "ioctl" alters our 734*7c478bd9Sstevel@tonic-gate * state. Thus, we always go ahead and do any 735*7c478bd9Sstevel@tonic-gate * state-changes the "ioctl" calls for. If we couldn't 736*7c478bd9Sstevel@tonic-gate * allocate the data, "ttycommon_ioctl" has stashed the 737*7c478bd9Sstevel@tonic-gate * "ioctl" away safely, so we just call "qbufcall" to 738*7c478bd9Sstevel@tonic-gate * request that we be called back when we stand a 739*7c478bd9Sstevel@tonic-gate * better chance of allocating the data. 740*7c478bd9Sstevel@tonic-gate */ 741*7c478bd9Sstevel@tonic-gate datasize = ttycommon_ioctl(&wscons.wc_ttycommon, q, mp, &error); 742*7c478bd9Sstevel@tonic-gate if (datasize != 0) { 743*7c478bd9Sstevel@tonic-gate if (wscons.wc_bufcallid != 0) 744*7c478bd9Sstevel@tonic-gate qunbufcall(q, wscons.wc_bufcallid); 745*7c478bd9Sstevel@tonic-gate wscons.wc_bufcallid = qbufcall(q, datasize, BPRI_HI, 746*7c478bd9Sstevel@tonic-gate wcreioctl, NULL); 747*7c478bd9Sstevel@tonic-gate return; 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate if (error < 0) { 751*7c478bd9Sstevel@tonic-gate if (iocp->ioc_cmd == TCSBRK) 752*7c478bd9Sstevel@tonic-gate error = 0; 753*7c478bd9Sstevel@tonic-gate else 754*7c478bd9Sstevel@tonic-gate error = EINVAL; 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate if (error != 0) { 757*7c478bd9Sstevel@tonic-gate iocp->ioc_error = error; 758*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate qreply(q, mp); 761*7c478bd9Sstevel@tonic-gate break; 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate /* 766*7c478bd9Sstevel@tonic-gate * This function gets the polled I/O structures from the lower 767*7c478bd9Sstevel@tonic-gate * keyboard driver. If any initialization or resource allocation 768*7c478bd9Sstevel@tonic-gate * needs to be done by the lower driver, it will be done when 769*7c478bd9Sstevel@tonic-gate * the lower driver services this message. 770*7c478bd9Sstevel@tonic-gate */ 771*7c478bd9Sstevel@tonic-gate static void 772*7c478bd9Sstevel@tonic-gate wc_open_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp) 773*7c478bd9Sstevel@tonic-gate { 774*7c478bd9Sstevel@tonic-gate mblk_t *mp2; 775*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 778*7c478bd9Sstevel@tonic-gate ("wc_open_kb_polledio: sending CONSOPENPOLLEDIO\n")); 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate mp2 = mkiocb(CONSOPENPOLLEDIO); 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate if (mp2 == NULL) { 783*7c478bd9Sstevel@tonic-gate /* 784*7c478bd9Sstevel@tonic-gate * If we can't get an mblk, then wait for it. 785*7c478bd9Sstevel@tonic-gate */ 786*7c478bd9Sstevel@tonic-gate goto nomem; 787*7c478bd9Sstevel@tonic-gate } 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate mp2->b_cont = allocb(sizeof (struct cons_polledio *), BPRI_HI); 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate if (mp2->b_cont == NULL) { 792*7c478bd9Sstevel@tonic-gate /* 793*7c478bd9Sstevel@tonic-gate * If we can't get an mblk, then wait for it, and release 794*7c478bd9Sstevel@tonic-gate * the mblk that we have already allocated. 795*7c478bd9Sstevel@tonic-gate */ 796*7c478bd9Sstevel@tonic-gate freemsg(mp2); 797*7c478bd9Sstevel@tonic-gate goto nomem; 798*7c478bd9Sstevel@tonic-gate } 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp2->b_rptr; 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct cons_polledio *); 803*7c478bd9Sstevel@tonic-gate mp2->b_cont->b_wptr = mp2->b_cont->b_rptr + 804*7c478bd9Sstevel@tonic-gate sizeof (struct cons_polledio *); 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate wscons->wc_pending_link = mp; 807*7c478bd9Sstevel@tonic-gate wscons->wc_kb_getpolledio_id = iocp->ioc_id; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate putnext(wscons->wc_kbdqueue, mp2); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate return; 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate nomem: 814*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 815*7c478bd9Sstevel@tonic-gate iocp->ioc_error = ENOMEM; 816*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 817*7c478bd9Sstevel@tonic-gate qreply(q, mp); 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate /* 821*7c478bd9Sstevel@tonic-gate * This function releases the polled I/O structures from the lower 822*7c478bd9Sstevel@tonic-gate * keyboard driver. If any de-initialization needs to be done, or 823*7c478bd9Sstevel@tonic-gate * any resources need to be released, it will be done when the lower 824*7c478bd9Sstevel@tonic-gate * driver services this message. 825*7c478bd9Sstevel@tonic-gate */ 826*7c478bd9Sstevel@tonic-gate static void 827*7c478bd9Sstevel@tonic-gate wc_close_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp) 828*7c478bd9Sstevel@tonic-gate { 829*7c478bd9Sstevel@tonic-gate mblk_t *mp2; 830*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 833*7c478bd9Sstevel@tonic-gate ("wc_close_kb_polledio: sending CONSCLOSEPOLLEDIO\n")); 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate mp2 = mkiocb(CONSCLOSEPOLLEDIO); 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate if (mp2 == NULL) { 838*7c478bd9Sstevel@tonic-gate /* 839*7c478bd9Sstevel@tonic-gate * If we can't get an mblk, then wait for it. 840*7c478bd9Sstevel@tonic-gate */ 841*7c478bd9Sstevel@tonic-gate goto nomem; 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate mp2->b_cont = allocb(sizeof (struct cons_polledio *), BPRI_HI); 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate if (mp2->b_cont == NULL) { 847*7c478bd9Sstevel@tonic-gate /* 848*7c478bd9Sstevel@tonic-gate * If we can't get an mblk, then wait for it, and release 849*7c478bd9Sstevel@tonic-gate * the mblk that we have already allocated. 850*7c478bd9Sstevel@tonic-gate */ 851*7c478bd9Sstevel@tonic-gate freemsg(mp2); 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate goto nomem; 854*7c478bd9Sstevel@tonic-gate } 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp2->b_rptr; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate wscons->wc_pending_link = mp; 861*7c478bd9Sstevel@tonic-gate wscons->wc_kb_getpolledio_id = iocp->ioc_id; 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate putnext(wscons->wc_kbdqueue, mp2); 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate return; 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate nomem: 868*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 869*7c478bd9Sstevel@tonic-gate iocp->ioc_error = ENOMEM; 870*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 871*7c478bd9Sstevel@tonic-gate qreply(q, mp); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 875*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 876*7c478bd9Sstevel@tonic-gate static void 877*7c478bd9Sstevel@tonic-gate wcopoll(void *arg) 878*7c478bd9Sstevel@tonic-gate { 879*7c478bd9Sstevel@tonic-gate queue_t *q; 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate q = wscons.wc_ttycommon.t_writeq; 882*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid = 0; 883*7c478bd9Sstevel@tonic-gate /* See if we can continue output */ 884*7c478bd9Sstevel@tonic-gate if ((wscons.wc_flags & WCS_BUSY) && wscons.wc_pendc != -1) { 885*7c478bd9Sstevel@tonic-gate if (prom_mayput((char)wscons.wc_pendc) == 0) { 886*7c478bd9Sstevel@tonic-gate wscons.wc_pendc = -1; 887*7c478bd9Sstevel@tonic-gate wscons.wc_flags &= ~WCS_BUSY; 888*7c478bd9Sstevel@tonic-gate if (!(wscons.wc_flags&(WCS_DELAY|WCS_STOPPED))) 889*7c478bd9Sstevel@tonic-gate wcstart(); 890*7c478bd9Sstevel@tonic-gate } else 891*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid = qtimeout(q, wcopoll, NULL, 1); 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate } 894*7c478bd9Sstevel@tonic-gate #endif /* _CONSOLE_OUTPUT_VIA_FIRMWARE */ 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* 897*7c478bd9Sstevel@tonic-gate * Restart output on the console after a timeout. 898*7c478bd9Sstevel@tonic-gate */ 899*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 900*7c478bd9Sstevel@tonic-gate static void 901*7c478bd9Sstevel@tonic-gate wcrstrt(void *arg) 902*7c478bd9Sstevel@tonic-gate { 903*7c478bd9Sstevel@tonic-gate ASSERT(wscons.wc_ttycommon.t_writeq != NULL); 904*7c478bd9Sstevel@tonic-gate wscons.wc_flags &= ~WCS_DELAY; 905*7c478bd9Sstevel@tonic-gate wcstart(); 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* 909*7c478bd9Sstevel@tonic-gate * Start console output 910*7c478bd9Sstevel@tonic-gate */ 911*7c478bd9Sstevel@tonic-gate static void 912*7c478bd9Sstevel@tonic-gate wcstart(void) 913*7c478bd9Sstevel@tonic-gate { 914*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 915*7c478bd9Sstevel@tonic-gate int c; 916*7c478bd9Sstevel@tonic-gate ssize_t cc; 917*7c478bd9Sstevel@tonic-gate #endif 918*7c478bd9Sstevel@tonic-gate queue_t *q; 919*7c478bd9Sstevel@tonic-gate mblk_t *bp; 920*7c478bd9Sstevel@tonic-gate mblk_t *nbp; 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate /* 923*7c478bd9Sstevel@tonic-gate * If we're waiting for something to happen (delay timeout to 924*7c478bd9Sstevel@tonic-gate * expire, current transmission to finish, output to be 925*7c478bd9Sstevel@tonic-gate * restarted, output to finish draining), don't grab anything 926*7c478bd9Sstevel@tonic-gate * new. 927*7c478bd9Sstevel@tonic-gate */ 928*7c478bd9Sstevel@tonic-gate if (wscons.wc_flags & (WCS_DELAY|WCS_BUSY|WCS_STOPPED)) 929*7c478bd9Sstevel@tonic-gate goto out; 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate q = wscons.wc_ttycommon.t_writeq; 932*7c478bd9Sstevel@tonic-gate /* 933*7c478bd9Sstevel@tonic-gate * assumes that we have been called by whoever holds the 934*7c478bd9Sstevel@tonic-gate * exclusionary lock on the write-side queue (protects 935*7c478bd9Sstevel@tonic-gate * wc_flags and wc_pendc). 936*7c478bd9Sstevel@tonic-gate */ 937*7c478bd9Sstevel@tonic-gate for (;;) { 938*7c478bd9Sstevel@tonic-gate if ((bp = getq(q)) == NULL) 939*7c478bd9Sstevel@tonic-gate goto out; /* nothing to transmit */ 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate /* 942*7c478bd9Sstevel@tonic-gate * We have a new message to work on. 943*7c478bd9Sstevel@tonic-gate * Check whether it's a delay or an ioctl (the latter 944*7c478bd9Sstevel@tonic-gate * occurs if the ioctl in question was waiting for the output 945*7c478bd9Sstevel@tonic-gate * to drain). If it's one of those, process it immediately. 946*7c478bd9Sstevel@tonic-gate */ 947*7c478bd9Sstevel@tonic-gate switch (bp->b_datap->db_type) { 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate case M_DELAY: 950*7c478bd9Sstevel@tonic-gate /* 951*7c478bd9Sstevel@tonic-gate * Arrange for "wcrstrt" to be called when the 952*7c478bd9Sstevel@tonic-gate * delay expires; it will turn WCS_DELAY off, 953*7c478bd9Sstevel@tonic-gate * and call "wcstart" to grab the next message. 954*7c478bd9Sstevel@tonic-gate */ 955*7c478bd9Sstevel@tonic-gate if (wscons.wc_timeoutid != 0) 956*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, wscons.wc_timeoutid); 957*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid = qtimeout(q, wcrstrt, NULL, 958*7c478bd9Sstevel@tonic-gate (clock_t)(*(unsigned char *)bp->b_rptr + 6)); 959*7c478bd9Sstevel@tonic-gate wscons.wc_flags |= WCS_DELAY; 960*7c478bd9Sstevel@tonic-gate freemsg(bp); 961*7c478bd9Sstevel@tonic-gate goto out; /* wait for this to finish */ 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate case M_IOCTL: 964*7c478bd9Sstevel@tonic-gate /* 965*7c478bd9Sstevel@tonic-gate * This ioctl was waiting for the output ahead of 966*7c478bd9Sstevel@tonic-gate * it to drain; obviously, it has. Do it, and 967*7c478bd9Sstevel@tonic-gate * then grab the next message after it. 968*7c478bd9Sstevel@tonic-gate */ 969*7c478bd9Sstevel@tonic-gate wcioctl(q, bp); 970*7c478bd9Sstevel@tonic-gate continue; 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 974*7c478bd9Sstevel@tonic-gate if (wscons.wc_tem != NULL) { 975*7c478bd9Sstevel@tonic-gate for (nbp = bp; nbp != NULL; nbp = nbp->b_cont) { 976*7c478bd9Sstevel@tonic-gate if (nbp->b_wptr > nbp->b_rptr) { 977*7c478bd9Sstevel@tonic-gate (void) tem_write(wscons.wc_tem, 978*7c478bd9Sstevel@tonic-gate nbp->b_rptr, nbp->b_wptr - nbp->b_rptr, 979*7c478bd9Sstevel@tonic-gate kcred); 980*7c478bd9Sstevel@tonic-gate } 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate freemsg(bp); 984*7c478bd9Sstevel@tonic-gate #else /* _CONSOLE_OUTPUT_VIA_FIRMWARE */ 985*7c478bd9Sstevel@tonic-gate if ((cc = bp->b_wptr - bp->b_rptr) == 0) { 986*7c478bd9Sstevel@tonic-gate freemsg(bp); 987*7c478bd9Sstevel@tonic-gate continue; 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate /* 991*7c478bd9Sstevel@tonic-gate * Direct output to the frame buffer if this device 992*7c478bd9Sstevel@tonic-gate * is not the "hardware" console. 993*7c478bd9Sstevel@tonic-gate */ 994*7c478bd9Sstevel@tonic-gate if (wscons.wc_defer_output) { 995*7c478bd9Sstevel@tonic-gate /* 996*7c478bd9Sstevel@tonic-gate * Never do output here; 997*7c478bd9Sstevel@tonic-gate * it takes forever. 998*7c478bd9Sstevel@tonic-gate */ 999*7c478bd9Sstevel@tonic-gate wscons.wc_flags |= WCS_BUSY; 1000*7c478bd9Sstevel@tonic-gate wscons.wc_pendc = -1; 1001*7c478bd9Sstevel@tonic-gate (void) putbq(q, bp); 1002*7c478bd9Sstevel@tonic-gate if (q->q_count > 128) { /* do it soon */ 1003*7c478bd9Sstevel@tonic-gate softcall(wconsout, NULL); 1004*7c478bd9Sstevel@tonic-gate } else { /* wait a bit */ 1005*7c478bd9Sstevel@tonic-gate if (wscons.wc_timeoutid != 0) 1006*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, 1007*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid); 1008*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid = qtimeout(q, wconsout, 1009*7c478bd9Sstevel@tonic-gate NULL, hz / 30); 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate goto out; 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate for (;;) { 1015*7c478bd9Sstevel@tonic-gate c = *bp->b_rptr++; 1016*7c478bd9Sstevel@tonic-gate cc--; 1017*7c478bd9Sstevel@tonic-gate if (prom_mayput((char)c) != 0) { 1018*7c478bd9Sstevel@tonic-gate wscons.wc_flags |= WCS_BUSY; 1019*7c478bd9Sstevel@tonic-gate wscons.wc_pendc = c; 1020*7c478bd9Sstevel@tonic-gate if (wscons.wc_timeoutid != 0) 1021*7c478bd9Sstevel@tonic-gate (void) quntimeout(q, 1022*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid); 1023*7c478bd9Sstevel@tonic-gate wscons.wc_timeoutid = qtimeout(q, wcopoll, 1024*7c478bd9Sstevel@tonic-gate NULL, 1); 1025*7c478bd9Sstevel@tonic-gate if (bp != NULL) 1026*7c478bd9Sstevel@tonic-gate /* not done with this message yet */ 1027*7c478bd9Sstevel@tonic-gate (void) putbq(q, bp); 1028*7c478bd9Sstevel@tonic-gate goto out; 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate while (cc <= 0) { 1031*7c478bd9Sstevel@tonic-gate nbp = bp; 1032*7c478bd9Sstevel@tonic-gate bp = bp->b_cont; 1033*7c478bd9Sstevel@tonic-gate freeb(nbp); 1034*7c478bd9Sstevel@tonic-gate if (bp == NULL) 1035*7c478bd9Sstevel@tonic-gate goto out; 1036*7c478bd9Sstevel@tonic-gate cc = bp->b_wptr - bp->b_rptr; 1037*7c478bd9Sstevel@tonic-gate } 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate #endif 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate out: 1042*7c478bd9Sstevel@tonic-gate ; 1043*7c478bd9Sstevel@tonic-gate } 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 1046*7c478bd9Sstevel@tonic-gate /* 1047*7c478bd9Sstevel@tonic-gate * Output to frame buffer console. 1048*7c478bd9Sstevel@tonic-gate * It takes a long time to scroll. 1049*7c478bd9Sstevel@tonic-gate */ 1050*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1051*7c478bd9Sstevel@tonic-gate static void 1052*7c478bd9Sstevel@tonic-gate wconsout(void *dummy) 1053*7c478bd9Sstevel@tonic-gate { 1054*7c478bd9Sstevel@tonic-gate uchar_t *cp; 1055*7c478bd9Sstevel@tonic-gate ssize_t cc; 1056*7c478bd9Sstevel@tonic-gate queue_t *q; 1057*7c478bd9Sstevel@tonic-gate mblk_t *bp; 1058*7c478bd9Sstevel@tonic-gate mblk_t *nbp; 1059*7c478bd9Sstevel@tonic-gate char *current_position; 1060*7c478bd9Sstevel@tonic-gate ssize_t bytes_left; 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate if ((q = wscons.wc_ttycommon.t_writeq) == NULL) { 1063*7c478bd9Sstevel@tonic-gate return; /* not attached to a stream */ 1064*7c478bd9Sstevel@tonic-gate } 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate /* 1067*7c478bd9Sstevel@tonic-gate * Set up to copy up to MAXHIWAT bytes. 1068*7c478bd9Sstevel@tonic-gate */ 1069*7c478bd9Sstevel@tonic-gate current_position = &obuf[0]; 1070*7c478bd9Sstevel@tonic-gate bytes_left = MAXHIWAT; 1071*7c478bd9Sstevel@tonic-gate while ((bp = getq(q)) != NULL) { 1072*7c478bd9Sstevel@tonic-gate if (bp->b_datap->db_type == M_IOCTL) { 1073*7c478bd9Sstevel@tonic-gate /* 1074*7c478bd9Sstevel@tonic-gate * This ioctl was waiting for the output ahead of 1075*7c478bd9Sstevel@tonic-gate * it to drain; obviously, it has. Put it back 1076*7c478bd9Sstevel@tonic-gate * so that "wcstart" can handle it, and transmit 1077*7c478bd9Sstevel@tonic-gate * what we've got. 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate (void) putbq(q, bp); 1080*7c478bd9Sstevel@tonic-gate goto transmit; 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate do { 1084*7c478bd9Sstevel@tonic-gate cp = bp->b_rptr; 1085*7c478bd9Sstevel@tonic-gate cc = bp->b_wptr - cp; 1086*7c478bd9Sstevel@tonic-gate while (cc != 0) { 1087*7c478bd9Sstevel@tonic-gate if (bytes_left == 0) { 1088*7c478bd9Sstevel@tonic-gate /* 1089*7c478bd9Sstevel@tonic-gate * Out of buffer space; put this 1090*7c478bd9Sstevel@tonic-gate * buffer back on the queue, and 1091*7c478bd9Sstevel@tonic-gate * transmit what we have. 1092*7c478bd9Sstevel@tonic-gate */ 1093*7c478bd9Sstevel@tonic-gate bp->b_rptr = cp; 1094*7c478bd9Sstevel@tonic-gate (void) putbq(q, bp); 1095*7c478bd9Sstevel@tonic-gate goto transmit; 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate *current_position++ = *cp++; 1098*7c478bd9Sstevel@tonic-gate cc--; 1099*7c478bd9Sstevel@tonic-gate bytes_left--; 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate nbp = bp; 1102*7c478bd9Sstevel@tonic-gate bp = bp->b_cont; 1103*7c478bd9Sstevel@tonic-gate freeb(nbp); 1104*7c478bd9Sstevel@tonic-gate } while (bp != NULL); 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate transmit: 1108*7c478bd9Sstevel@tonic-gate if ((cc = MAXHIWAT - bytes_left) != 0) 1109*7c478bd9Sstevel@tonic-gate console_puts(obuf, cc); 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate wscons.wc_flags &= ~WCS_BUSY; 1112*7c478bd9Sstevel@tonic-gate wcstart(); 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate #endif 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate /* 1117*7c478bd9Sstevel@tonic-gate * Put procedure for lower read queue. 1118*7c478bd9Sstevel@tonic-gate * Pass everything up to queue above "upper half". 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate static int 1121*7c478bd9Sstevel@tonic-gate wclrput(queue_t *q, mblk_t *mp) 1122*7c478bd9Sstevel@tonic-gate { 1123*7c478bd9Sstevel@tonic-gate queue_t *upq; 1124*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1127*7c478bd9Sstevel@tonic-gate ("wclrput: wclrput type = 0x%x\n", mp->b_datap->db_type)); 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate case M_FLUSH: 1132*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr == FLUSHW || *mp->b_rptr == FLUSHRW) { 1133*7c478bd9Sstevel@tonic-gate /* 1134*7c478bd9Sstevel@tonic-gate * Flush our write queue. 1135*7c478bd9Sstevel@tonic-gate */ 1136*7c478bd9Sstevel@tonic-gate /* XXX doesn't flush M_DELAY */ 1137*7c478bd9Sstevel@tonic-gate flushq(WR(q), FLUSHDATA); 1138*7c478bd9Sstevel@tonic-gate *mp->b_rptr = FLUSHR; /* it has been flushed */ 1139*7c478bd9Sstevel@tonic-gate } 1140*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr == FLUSHR || *mp->b_rptr == FLUSHRW) { 1141*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 1142*7c478bd9Sstevel@tonic-gate *mp->b_rptr = FLUSHW; /* it has been flushed */ 1143*7c478bd9Sstevel@tonic-gate qreply(q, mp); /* give the read queues a crack at it */ 1144*7c478bd9Sstevel@tonic-gate } else 1145*7c478bd9Sstevel@tonic-gate freemsg(mp); 1146*7c478bd9Sstevel@tonic-gate break; 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate case M_DATA: 1149*7c478bd9Sstevel@tonic-gate if ((upq = wscons.wc_ttycommon.t_readq) != NULL) { 1150*7c478bd9Sstevel@tonic-gate if (!canput(upq->q_next)) { 1151*7c478bd9Sstevel@tonic-gate ttycommon_qfull(&wscons.wc_ttycommon, upq); 1152*7c478bd9Sstevel@tonic-gate wcstart(); 1153*7c478bd9Sstevel@tonic-gate freemsg(mp); 1154*7c478bd9Sstevel@tonic-gate } else 1155*7c478bd9Sstevel@tonic-gate putnext(upq, mp); 1156*7c478bd9Sstevel@tonic-gate } else 1157*7c478bd9Sstevel@tonic-gate freemsg(mp); 1158*7c478bd9Sstevel@tonic-gate break; 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate case M_IOCACK: 1161*7c478bd9Sstevel@tonic-gate case M_IOCNAK: 1162*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 1163*7c478bd9Sstevel@tonic-gate if (wscons.wc_pending_link != NULL && 1164*7c478bd9Sstevel@tonic-gate iocp->ioc_id == wscons.wc_kb_getpolledio_id) { 1165*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate case M_IOCACK: 1168*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate case CONSOPENPOLLEDIO: 1172*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1173*7c478bd9Sstevel@tonic-gate ("wclrput: " 1174*7c478bd9Sstevel@tonic-gate "ACK CONSOPENPOLLEDIO\n")); 1175*7c478bd9Sstevel@tonic-gate wscons.wc_kb_polledio = 1176*7c478bd9Sstevel@tonic-gate *(struct cons_polledio **) 1177*7c478bd9Sstevel@tonic-gate mp->b_cont->b_rptr; 1178*7c478bd9Sstevel@tonic-gate break; 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate case CONSCLOSEPOLLEDIO: 1181*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1182*7c478bd9Sstevel@tonic-gate ("wclrput: " 1183*7c478bd9Sstevel@tonic-gate "ACK CONSCLOSEPOLLEDIO\n")); 1184*7c478bd9Sstevel@tonic-gate wscons.wc_kb_polledio = NULL; 1185*7c478bd9Sstevel@tonic-gate wscons.wc_kbdqueue = NULL; 1186*7c478bd9Sstevel@tonic-gate break; 1187*7c478bd9Sstevel@tonic-gate default: 1188*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1189*7c478bd9Sstevel@tonic-gate ("wclrput: " 1190*7c478bd9Sstevel@tonic-gate "ACK UNKNOWN\n")); 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate break; 1194*7c478bd9Sstevel@tonic-gate case M_IOCNAK: 1195*7c478bd9Sstevel@tonic-gate /* 1196*7c478bd9Sstevel@tonic-gate * Keyboard may or may not support polled I/O. 1197*7c478bd9Sstevel@tonic-gate * This ioctl may have been rejected because 1198*7c478bd9Sstevel@tonic-gate * we only have the wc->conskbd chain built, 1199*7c478bd9Sstevel@tonic-gate * and the keyboard driver has not been linked 1200*7c478bd9Sstevel@tonic-gate * underneath conskbd yet. 1201*7c478bd9Sstevel@tonic-gate */ 1202*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1203*7c478bd9Sstevel@tonic-gate ("wclrput: NAK\n")); 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate case CONSCLOSEPOLLEDIO: 1208*7c478bd9Sstevel@tonic-gate wscons.wc_kb_polledio = NULL; 1209*7c478bd9Sstevel@tonic-gate wscons.wc_kbdqueue = NULL; 1210*7c478bd9Sstevel@tonic-gate break; 1211*7c478bd9Sstevel@tonic-gate } 1212*7c478bd9Sstevel@tonic-gate break; 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* 1216*7c478bd9Sstevel@tonic-gate * Discard the response, replace it with the 1217*7c478bd9Sstevel@tonic-gate * pending response to the I_PLINK, then let it 1218*7c478bd9Sstevel@tonic-gate * flow upward. 1219*7c478bd9Sstevel@tonic-gate */ 1220*7c478bd9Sstevel@tonic-gate freemsg(mp); 1221*7c478bd9Sstevel@tonic-gate mp = wscons.wc_pending_link; 1222*7c478bd9Sstevel@tonic-gate wscons.wc_pending_link = NULL; 1223*7c478bd9Sstevel@tonic-gate wscons.wc_kb_getpolledio_id = 0; 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate default: /* inc M_ERROR, M_HANGUP, M_IOCACK, M_IOCNAK, ... */ 1228*7c478bd9Sstevel@tonic-gate DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1229*7c478bd9Sstevel@tonic-gate ("wclrput: Message DISCARDED\n")); 1230*7c478bd9Sstevel@tonic-gate if ((upq = wscons.wc_ttycommon.t_readq) != NULL) { 1231*7c478bd9Sstevel@tonic-gate putnext(upq, mp); 1232*7c478bd9Sstevel@tonic-gate } else { 1233*7c478bd9Sstevel@tonic-gate freemsg(mp); 1234*7c478bd9Sstevel@tonic-gate } 1235*7c478bd9Sstevel@tonic-gate break; 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate return (0); 1239*7c478bd9Sstevel@tonic-gate } 1240*7c478bd9Sstevel@tonic-gate 1241*7c478bd9Sstevel@tonic-gate /* 1242*7c478bd9Sstevel@tonic-gate * Auxiliary routines, for allowing the workstation console to be redirected. 1243*7c478bd9Sstevel@tonic-gate */ 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate /* 1246*7c478bd9Sstevel@tonic-gate * Given a minor device number for a wscons instance, return a held vnode for 1247*7c478bd9Sstevel@tonic-gate * it. 1248*7c478bd9Sstevel@tonic-gate * 1249*7c478bd9Sstevel@tonic-gate * We currently support only one instance, for the "workstation console". 1250*7c478bd9Sstevel@tonic-gate */ 1251*7c478bd9Sstevel@tonic-gate int 1252*7c478bd9Sstevel@tonic-gate wcvnget(minor_t unit, vnode_t **vpp) 1253*7c478bd9Sstevel@tonic-gate { 1254*7c478bd9Sstevel@tonic-gate if (unit != 0 || rwsconsvp == NULL) 1255*7c478bd9Sstevel@tonic-gate return (ENXIO); 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate /* 1258*7c478bd9Sstevel@tonic-gate * rwsconsvp is already held, so we don't have to do it here. 1259*7c478bd9Sstevel@tonic-gate */ 1260*7c478bd9Sstevel@tonic-gate *vpp = rwsconsvp; 1261*7c478bd9Sstevel@tonic-gate return (0); 1262*7c478bd9Sstevel@tonic-gate } 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate /* 1265*7c478bd9Sstevel@tonic-gate * Release the vnode that wcvnget returned. 1266*7c478bd9Sstevel@tonic-gate */ 1267*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1268*7c478bd9Sstevel@tonic-gate void 1269*7c478bd9Sstevel@tonic-gate wcvnrele(minor_t unit, vnode_t *vp) 1270*7c478bd9Sstevel@tonic-gate { 1271*7c478bd9Sstevel@tonic-gate /* 1272*7c478bd9Sstevel@tonic-gate * Nothing to do, since we only support the workstation console 1273*7c478bd9Sstevel@tonic-gate * instance that's held throughout the system's lifetime. 1274*7c478bd9Sstevel@tonic-gate */ 1275*7c478bd9Sstevel@tonic-gate } 1276*7c478bd9Sstevel@tonic-gate 1277*7c478bd9Sstevel@tonic-gate /* 1278*7c478bd9Sstevel@tonic-gate * The declaration and initialization of the wscons_srvnops has been 1279*7c478bd9Sstevel@tonic-gate * moved to space.c to allow "wc" to become a loadable module. 1280*7c478bd9Sstevel@tonic-gate */ 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_SOFTWARE) 1283*7c478bd9Sstevel@tonic-gate /* 1284*7c478bd9Sstevel@tonic-gate * This is for systems without OBP. 1285*7c478bd9Sstevel@tonic-gate */ 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate static void 1288*7c478bd9Sstevel@tonic-gate wc_putchar(struct cons_polledio_arg *arg, unsigned char c) 1289*7c478bd9Sstevel@tonic-gate { 1290*7c478bd9Sstevel@tonic-gate if (c == '\n') 1291*7c478bd9Sstevel@tonic-gate wc_putchar(arg, '\r'); 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate if (wscons.wc_tem == NULL) { 1294*7c478bd9Sstevel@tonic-gate /* 1295*7c478bd9Sstevel@tonic-gate * We have no terminal emulator configured. We have no 1296*7c478bd9Sstevel@tonic-gate * recourse but to drop the output on the floor. 1297*7c478bd9Sstevel@tonic-gate */ 1298*7c478bd9Sstevel@tonic-gate return; 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate /* 1302*7c478bd9Sstevel@tonic-gate * We ignore the result code. After all, what could we do? 1303*7c478bd9Sstevel@tonic-gate * Write something to the console?? 1304*7c478bd9Sstevel@tonic-gate */ 1305*7c478bd9Sstevel@tonic-gate (void) tem_polled_write(wscons.wc_tem, &c, 1); 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate #endif /* _CONSOLE_OUTPUT_VIA_SOFTWARE */ 1308*7c478bd9Sstevel@tonic-gate 1309*7c478bd9Sstevel@tonic-gate /* 1310*7c478bd9Sstevel@tonic-gate * These are for systems without OBP, and for devices that cannot be 1311*7c478bd9Sstevel@tonic-gate * shared between Solaris and the OBP. 1312*7c478bd9Sstevel@tonic-gate */ 1313*7c478bd9Sstevel@tonic-gate static int 1314*7c478bd9Sstevel@tonic-gate wc_getchar(struct cons_polledio_arg *arg) 1315*7c478bd9Sstevel@tonic-gate { 1316*7c478bd9Sstevel@tonic-gate struct wscons *wscons = (struct wscons *)arg; 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate if (wscons->wc_kb_polledio == NULL) { 1319*7c478bd9Sstevel@tonic-gate prom_printf("wscons: getchar with no keyboard support"); 1320*7c478bd9Sstevel@tonic-gate prom_printf("Halted..."); 1321*7c478bd9Sstevel@tonic-gate for (;;) 1322*7c478bd9Sstevel@tonic-gate /* HANG FOREVER */; 1323*7c478bd9Sstevel@tonic-gate } 1324*7c478bd9Sstevel@tonic-gate 1325*7c478bd9Sstevel@tonic-gate return (wscons->wc_kb_polledio->cons_polledio_getchar( 1326*7c478bd9Sstevel@tonic-gate wscons->wc_kb_polledio->cons_polledio_argument)); 1327*7c478bd9Sstevel@tonic-gate } 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate static boolean_t 1330*7c478bd9Sstevel@tonic-gate wc_ischar(struct cons_polledio_arg *arg) 1331*7c478bd9Sstevel@tonic-gate { 1332*7c478bd9Sstevel@tonic-gate struct wscons *wscons = (struct wscons *)arg; 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate if (wscons->wc_kb_polledio == NULL) 1335*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate return (wscons->wc_kb_polledio->cons_polledio_ischar( 1338*7c478bd9Sstevel@tonic-gate wscons->wc_kb_polledio->cons_polledio_argument)); 1339*7c478bd9Sstevel@tonic-gate } 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate static void 1342*7c478bd9Sstevel@tonic-gate wc_polled_enter(struct cons_polledio_arg *arg) 1343*7c478bd9Sstevel@tonic-gate { 1344*7c478bd9Sstevel@tonic-gate struct wscons *wscons = (struct wscons *)arg; 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate if (wscons->wc_kb_polledio == NULL) 1347*7c478bd9Sstevel@tonic-gate return; 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate if (wscons->wc_kb_polledio->cons_polledio_enter != NULL) { 1350*7c478bd9Sstevel@tonic-gate wscons->wc_kb_polledio->cons_polledio_enter( 1351*7c478bd9Sstevel@tonic-gate wscons->wc_kb_polledio->cons_polledio_argument); 1352*7c478bd9Sstevel@tonic-gate } 1353*7c478bd9Sstevel@tonic-gate } 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate static void 1356*7c478bd9Sstevel@tonic-gate wc_polled_exit(struct cons_polledio_arg *arg) 1357*7c478bd9Sstevel@tonic-gate { 1358*7c478bd9Sstevel@tonic-gate struct wscons *wscons = (struct wscons *)arg; 1359*7c478bd9Sstevel@tonic-gate 1360*7c478bd9Sstevel@tonic-gate if (wscons->wc_kb_polledio == NULL) 1361*7c478bd9Sstevel@tonic-gate return; 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate if (wscons->wc_kb_polledio->cons_polledio_exit != NULL) { 1364*7c478bd9Sstevel@tonic-gate wscons->wc_kb_polledio->cons_polledio_exit( 1365*7c478bd9Sstevel@tonic-gate wscons->wc_kb_polledio->cons_polledio_argument); 1366*7c478bd9Sstevel@tonic-gate } 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1371*7c478bd9Sstevel@tonic-gate static void 1372*7c478bd9Sstevel@tonic-gate wc_dprintf(const char *fmt, ...) 1373*7c478bd9Sstevel@tonic-gate { 1374*7c478bd9Sstevel@tonic-gate char buf[256]; 1375*7c478bd9Sstevel@tonic-gate va_list ap; 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 1378*7c478bd9Sstevel@tonic-gate (void) vsprintf(buf, fmt, ap); 1379*7c478bd9Sstevel@tonic-gate va_end(ap); 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "wc: %s", buf); 1382*7c478bd9Sstevel@tonic-gate } 1383*7c478bd9Sstevel@tonic-gate #endif 1384*7c478bd9Sstevel@tonic-gate 1385*7c478bd9Sstevel@tonic-gate #if defined(_CONSOLE_OUTPUT_VIA_FIRMWARE) 1386*7c478bd9Sstevel@tonic-gate static int 1387*7c478bd9Sstevel@tonic-gate atou_n(char *s, int n) 1388*7c478bd9Sstevel@tonic-gate { 1389*7c478bd9Sstevel@tonic-gate int res; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate res = 0; 1392*7c478bd9Sstevel@tonic-gate while (n > 0 && *s != '\0') { 1393*7c478bd9Sstevel@tonic-gate if (*s < '0' || *s > '9') 1394*7c478bd9Sstevel@tonic-gate return (0); 1395*7c478bd9Sstevel@tonic-gate res *= 10; 1396*7c478bd9Sstevel@tonic-gate res += *s - '0'; 1397*7c478bd9Sstevel@tonic-gate s++; 1398*7c478bd9Sstevel@tonic-gate n--; 1399*7c478bd9Sstevel@tonic-gate } 1400*7c478bd9Sstevel@tonic-gate return (res); 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate static int 1404*7c478bd9Sstevel@tonic-gate get_option_string_int(char *name) 1405*7c478bd9Sstevel@tonic-gate { 1406*7c478bd9Sstevel@tonic-gate char *data; 1407*7c478bd9Sstevel@tonic-gate uint_t len; 1408*7c478bd9Sstevel@tonic-gate int res; 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 0, 1411*7c478bd9Sstevel@tonic-gate name, (uchar_t **)&data, &len) != DDI_PROP_SUCCESS) 1412*7c478bd9Sstevel@tonic-gate return (0); 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate res = atou_n(data, len); 1415*7c478bd9Sstevel@tonic-gate ddi_prop_free(data); 1416*7c478bd9Sstevel@tonic-gate return (res); 1417*7c478bd9Sstevel@tonic-gate } 1418*7c478bd9Sstevel@tonic-gate #endif 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate /* 1421*7c478bd9Sstevel@tonic-gate * Gets the number of text rows and columns and the 1422*7c478bd9Sstevel@tonic-gate * width and height (in pixels) of the console. 1423*7c478bd9Sstevel@tonic-gate */ 1424*7c478bd9Sstevel@tonic-gate static void 1425*7c478bd9Sstevel@tonic-gate wc_get_size(struct wscons *wscons) 1426*7c478bd9Sstevel@tonic-gate { 1427*7c478bd9Sstevel@tonic-gate #if defined _CONSOLE_OUTPUT_VIA_FIRMWARE 1428*7c478bd9Sstevel@tonic-gate static char *cols = "screen-#columns"; 1429*7c478bd9Sstevel@tonic-gate static char *rows = "screen-#rows"; 1430*7c478bd9Sstevel@tonic-gate static char *width = "screen-width"; 1431*7c478bd9Sstevel@tonic-gate static char *height = "screen-height"; 1432*7c478bd9Sstevel@tonic-gate struct winsize *t; 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate t = &wscons->wc_ttycommon.t_size; 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate /* 1437*7c478bd9Sstevel@tonic-gate * Get the number of columns 1438*7c478bd9Sstevel@tonic-gate */ 1439*7c478bd9Sstevel@tonic-gate t->ws_col = (unsigned short)get_option_string_int(cols); 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate if (t->ws_col < MINCOLS) 1442*7c478bd9Sstevel@tonic-gate t->ws_col = LOSCREENCOLS; 1443*7c478bd9Sstevel@tonic-gate else if (t->ws_col > MAXCOLS) 1444*7c478bd9Sstevel@tonic-gate t->ws_col = HISCREENCOLS; 1445*7c478bd9Sstevel@tonic-gate 1446*7c478bd9Sstevel@tonic-gate /* 1447*7c478bd9Sstevel@tonic-gate * Get the number of rows 1448*7c478bd9Sstevel@tonic-gate */ 1449*7c478bd9Sstevel@tonic-gate t->ws_row = (unsigned short)get_option_string_int(rows); 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate if (t->ws_row < MINLINES) 1452*7c478bd9Sstevel@tonic-gate t->ws_row = LOSCREENLINES; 1453*7c478bd9Sstevel@tonic-gate else if (t->ws_row > MAXLINES) 1454*7c478bd9Sstevel@tonic-gate t->ws_row = HISCREENLINES; 1455*7c478bd9Sstevel@tonic-gate 1456*7c478bd9Sstevel@tonic-gate /* 1457*7c478bd9Sstevel@tonic-gate * Get the size in pixels. 1458*7c478bd9Sstevel@tonic-gate */ 1459*7c478bd9Sstevel@tonic-gate t->ws_xpixel = (unsigned short)get_option_string_int(width); 1460*7c478bd9Sstevel@tonic-gate t->ws_ypixel = (unsigned short)get_option_string_int(height); 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate #else /* _CONSOLE_OUTPUT_VIA_SOFTWARE */ 1463*7c478bd9Sstevel@tonic-gate struct winsize *t; 1464*7c478bd9Sstevel@tonic-gate int r, c, x, y; 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate t = &wscons->wc_ttycommon.t_size; 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate if (wscons->wc_tem != NULL) { 1469*7c478bd9Sstevel@tonic-gate tem_get_size(wscons->wc_tem, &r, &c, &x, &y); 1470*7c478bd9Sstevel@tonic-gate t->ws_row = (unsigned short)r; 1471*7c478bd9Sstevel@tonic-gate t->ws_col = (unsigned short)c; 1472*7c478bd9Sstevel@tonic-gate t->ws_xpixel = (unsigned short)x; 1473*7c478bd9Sstevel@tonic-gate t->ws_ypixel = (unsigned short)y; 1474*7c478bd9Sstevel@tonic-gate } else { 1475*7c478bd9Sstevel@tonic-gate t->ws_row = LOSCREENLINES; 1476*7c478bd9Sstevel@tonic-gate t->ws_col = LOSCREENCOLS; 1477*7c478bd9Sstevel@tonic-gate t->ws_xpixel = 0; 1478*7c478bd9Sstevel@tonic-gate t->ws_ypixel = 0; 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate #endif 1481*7c478bd9Sstevel@tonic-gate } 1482