10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51253Slq150181 * Common Development and Distribution License (the "License"). 61253Slq150181 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211253Slq150181 220Sstevel@tonic-gate /* 23*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Indirect console driver for Sun. 300Sstevel@tonic-gate * 310Sstevel@tonic-gate * Redirects all I/O to the device designated as the underlying "hardware" 320Sstevel@tonic-gate * console, as given by the value of rconsvp. The implementation assumes that 330Sstevel@tonic-gate * rconsvp denotes a STREAMS device; the assumption is justified since 340Sstevel@tonic-gate * consoles must be capable of effecting tty semantics. 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * rconsvp is set in autoconf.c:consconfig(), based on information obtained 370Sstevel@tonic-gate * from the EEPROM. 380Sstevel@tonic-gate * 390Sstevel@tonic-gate * XXX: The driver still needs to be converted to use ANSI C consistently 400Sstevel@tonic-gate * throughout. 410Sstevel@tonic-gate */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include <sys/types.h> 440Sstevel@tonic-gate #include <sys/open.h> 450Sstevel@tonic-gate #include <sys/param.h> 460Sstevel@tonic-gate #include <sys/systm.h> 470Sstevel@tonic-gate #include <sys/signal.h> 480Sstevel@tonic-gate #include <sys/cred.h> 490Sstevel@tonic-gate #include <sys/user.h> 500Sstevel@tonic-gate #include <sys/proc.h> 510Sstevel@tonic-gate #include <sys/disp.h> 520Sstevel@tonic-gate #include <sys/file.h> 530Sstevel@tonic-gate #include <sys/taskq.h> 540Sstevel@tonic-gate #include <sys/log.h> 550Sstevel@tonic-gate #include <sys/vnode.h> 560Sstevel@tonic-gate #include <sys/uio.h> 570Sstevel@tonic-gate #include <sys/stat.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <sys/console.h> 600Sstevel@tonic-gate #include <sys/consdev.h> 610Sstevel@tonic-gate 620Sstevel@tonic-gate #include <sys/stream.h> 630Sstevel@tonic-gate #include <sys/strsubr.h> 640Sstevel@tonic-gate #include <sys/poll.h> 650Sstevel@tonic-gate 660Sstevel@tonic-gate #include <sys/debug.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate #include <sys/conf.h> 690Sstevel@tonic-gate #include <sys/ddi.h> 700Sstevel@tonic-gate #include <sys/sunddi.h> 710Sstevel@tonic-gate 720Sstevel@tonic-gate static int cnopen(dev_t *, int, int, struct cred *); 730Sstevel@tonic-gate static int cnclose(dev_t, int, int, struct cred *); 740Sstevel@tonic-gate static int cnread(dev_t, struct uio *, struct cred *); 750Sstevel@tonic-gate static int cnwrite(dev_t, struct uio *, struct cred *); 760Sstevel@tonic-gate static int cnioctl(dev_t, int, intptr_t, int, struct cred *, int *); 770Sstevel@tonic-gate static int cnpoll(dev_t, short, int, short *, struct pollhead **); 780Sstevel@tonic-gate static int cn_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 790Sstevel@tonic-gate static int cn_attach(dev_info_t *, ddi_attach_cmd_t); 800Sstevel@tonic-gate static int cn_detach(dev_info_t *, ddi_detach_cmd_t); 810Sstevel@tonic-gate 820Sstevel@tonic-gate static dev_info_t *cn_dip; /* private copy of devinfo pointer */ 830Sstevel@tonic-gate 840Sstevel@tonic-gate static struct cb_ops cn_cb_ops = { 850Sstevel@tonic-gate 860Sstevel@tonic-gate cnopen, /* open */ 870Sstevel@tonic-gate cnclose, /* close */ 880Sstevel@tonic-gate nodev, /* strategy */ 890Sstevel@tonic-gate nodev, /* print */ 900Sstevel@tonic-gate nodev, /* dump */ 910Sstevel@tonic-gate cnread, /* read */ 920Sstevel@tonic-gate cnwrite, /* write */ 930Sstevel@tonic-gate cnioctl, /* ioctl */ 940Sstevel@tonic-gate nodev, /* devmap */ 950Sstevel@tonic-gate nodev, /* mmap */ 960Sstevel@tonic-gate nodev, /* segmap */ 970Sstevel@tonic-gate cnpoll, /* poll */ 980Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 990Sstevel@tonic-gate 0, /* streamtab */ 1000Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate }; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate static struct dev_ops cn_ops = { 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1070Sstevel@tonic-gate 0, /* refcnt */ 1080Sstevel@tonic-gate cn_info, /* info */ 1090Sstevel@tonic-gate nulldev, /* identify */ 1100Sstevel@tonic-gate nulldev, /* probe */ 1110Sstevel@tonic-gate cn_attach, /* attach */ 1120Sstevel@tonic-gate cn_detach, /* detach */ 1130Sstevel@tonic-gate nodev, /* reset */ 1140Sstevel@tonic-gate &cn_cb_ops, /* driver operations */ 115*7656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* bus operations */ 116*7656SSherry.Moore@Sun.COM NULL, /* power */ 117*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate }; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Global variables associated with the console device: 1230Sstevel@tonic-gate * 1240Sstevel@tonic-gate * XXX: There are too many of these! 1255331Samw * moved to space.c to become resident in the kernel so that cons 1260Sstevel@tonic-gate * can be loadable. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate extern dev_t rconsdev; /* "hardware" console */ 1300Sstevel@tonic-gate extern vnode_t *rconsvp; /* pointer to vnode for that device */ 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * XXX: consulted in prsubr.c, for /proc entry point for obtaining ps info. 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate extern dev_t uconsdev; /* What the user thinks is the console device */ 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Private driver state: 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* 1420Sstevel@tonic-gate * The underlying console device potentially can be opened through (at least) 1430Sstevel@tonic-gate * two paths: through this driver and through the underlying device's driver. 1440Sstevel@tonic-gate * To ensure that reference counts are meaningful and therefore that close 1450Sstevel@tonic-gate * routines are called at the right time, it's important to make sure that 1460Sstevel@tonic-gate * rconsvp's s_count field (i.e., the count on the underlying device) never 1470Sstevel@tonic-gate * has a contribution of more than one through this driver, regardless of how 1480Sstevel@tonic-gate * many times this driver's been opened. rconsopen keeps track of the 1490Sstevel@tonic-gate * necessary information to ensure this property. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate static uint_t rconsopen; 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate #include <sys/types.h> 1550Sstevel@tonic-gate #include <sys/conf.h> 1560Sstevel@tonic-gate #include <sys/param.h> 1570Sstevel@tonic-gate #include <sys/systm.h> 1580Sstevel@tonic-gate #include <sys/errno.h> 1590Sstevel@tonic-gate #include <sys/modctl.h> 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate extern int nodev(), nulldev(); 1630Sstevel@tonic-gate extern int dseekneg_flag; 1640Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1650Sstevel@tonic-gate extern struct dev_ops cn_ops; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * Module linkage information for the kernel. 1690Sstevel@tonic-gate */ 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate static struct modldrv modldrv = { 1720Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 173*7656SSherry.Moore@Sun.COM "Console redirection driver", 1740Sstevel@tonic-gate &cn_ops, /* driver ops */ 1750Sstevel@tonic-gate }; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate static struct modlinkage modlinkage = { 1780Sstevel@tonic-gate MODREV_1, 1790Sstevel@tonic-gate &modldrv, 1800Sstevel@tonic-gate NULL 1810Sstevel@tonic-gate }; 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate int 1840Sstevel@tonic-gate _init(void) 1850Sstevel@tonic-gate { 1860Sstevel@tonic-gate return (mod_install(&modlinkage)); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate int 1900Sstevel@tonic-gate _fini(void) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate return (EBUSY); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate int 1960Sstevel@tonic-gate _info(struct modinfo *modinfop) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * DDI glue routines 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate static int 2050Sstevel@tonic-gate cn_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2080Sstevel@tonic-gate return (DDI_FAILURE); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate if (ddi_create_minor_node(devi, "syscon", S_IFCHR, 2110Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2120Sstevel@tonic-gate return (DDI_FAILURE); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate if (ddi_create_minor_node(devi, "systty", S_IFCHR, 2150Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2160Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2170Sstevel@tonic-gate return (DDI_FAILURE); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate if (ddi_create_minor_node(devi, "console", S_IFCHR, 2200Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2210Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2220Sstevel@tonic-gate return (DDI_FAILURE); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate cn_dip = devi; 2250Sstevel@tonic-gate return (DDI_SUCCESS); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate static int 2290Sstevel@tonic-gate cn_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 2300Sstevel@tonic-gate { 2310Sstevel@tonic-gate if (cmd != DDI_DETACH) 2320Sstevel@tonic-gate return (DDI_FAILURE); 2330Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2340Sstevel@tonic-gate uconsdev = NODEV; 2350Sstevel@tonic-gate return (DDI_SUCCESS); 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* ARGSUSED */ 2390Sstevel@tonic-gate static int 2400Sstevel@tonic-gate cn_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2410Sstevel@tonic-gate { 2420Sstevel@tonic-gate int error = DDI_FAILURE; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate switch (infocmd) { 2450Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2460Sstevel@tonic-gate if (getminor((dev_t)arg) == 0 && cn_dip != NULL) { 2470Sstevel@tonic-gate *result = (void *) cn_dip; 2480Sstevel@tonic-gate error = DDI_SUCCESS; 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate break; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2530Sstevel@tonic-gate if (getminor((dev_t)arg) == 0) { 2540Sstevel@tonic-gate *result = (void *)0; 2550Sstevel@tonic-gate error = DDI_SUCCESS; 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate break; 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate default: 2600Sstevel@tonic-gate break; 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate return (error); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * XXX Caution: before allowing more than 256 minor devices on the 2680Sstevel@tonic-gate * console, make sure you understand the 'compatibility' hack 2690Sstevel@tonic-gate * in ufs_iget() that translates old dev_t's to new dev_t's. 2700Sstevel@tonic-gate * See bugid 1098104 for the sordid details. 2710Sstevel@tonic-gate */ 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* ARGSUSED */ 2740Sstevel@tonic-gate static int 2750Sstevel@tonic-gate cnopen(dev_t *dev, int flag, int state, struct cred *cred) 2760Sstevel@tonic-gate { 2770Sstevel@tonic-gate int err; 2780Sstevel@tonic-gate static int been_here; 2790Sstevel@tonic-gate vnode_t *vp = rconsvp; 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate ASSERT(cred != NULL); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate if (rconsvp == NULL) 2840Sstevel@tonic-gate return (0); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * XXX: Clean up inactive PIDs from previous opens if any. 2890Sstevel@tonic-gate * These would have been created as a result of an I_SETSIG 2900Sstevel@tonic-gate * issued against console. This is a workaround, and 2910Sstevel@tonic-gate * console driver must be correctly redesigned not to need 2920Sstevel@tonic-gate * this hook. 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate if (vp->v_stream) { 2950Sstevel@tonic-gate str_cn_clean(vp); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate /* 2990Sstevel@tonic-gate * XXX: Set hook to tell /proc about underlying console. (There's 3000Sstevel@tonic-gate * gotta be a better way...) 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate if (state != OTYP_CHR || getminor(*dev) != 0) 3030Sstevel@tonic-gate return (ENXIO); 3040Sstevel@tonic-gate if (been_here == 0) { 3050Sstevel@tonic-gate uconsdev = *dev; 3060Sstevel@tonic-gate been_here = 1; 3070Sstevel@tonic-gate if (vn_open("/dev/console", UIO_SYSSPACE, FWRITE | FNOCTTY, 3080Sstevel@tonic-gate 0, &console_vnode, 0, 0) == 0) 3090Sstevel@tonic-gate console_taskq = taskq_create("console_taskq", 3100Sstevel@tonic-gate 1, maxclsyspri - 1, LOG_LOWAT / LOG_MSGSIZE, 3110Sstevel@tonic-gate LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3145331Samw if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0) 3150Sstevel@tonic-gate return (err); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * The underlying driver is not allowed to have cloned itself 3190Sstevel@tonic-gate * for this open. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate if (vp != rconsvp) { 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * It might happen that someone set rconsvp to NULL 3240Sstevel@tonic-gate * whilst we were in the middle of the open. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate if (rconsvp == NULL) { 3275331Samw (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL); 3280Sstevel@tonic-gate return (0); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate cmn_err(CE_PANIC, "cnopen: cloned open"); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate rconsopen++; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate return (0); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* ARGSUSED */ 3390Sstevel@tonic-gate static int 3400Sstevel@tonic-gate cnclose(dev_t dev, int flag, int state, struct cred *cred) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate int err = 0; 3430Sstevel@tonic-gate vnode_t *vp; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * Since this is the _last_ close, it's our last chance to close the 3470Sstevel@tonic-gate * underlying device. (Note that if someone else has the underlying 3480Sstevel@tonic-gate * hardware console device open, we won't get here, since spec_close 3490Sstevel@tonic-gate * will see s_count > 1.) 3500Sstevel@tonic-gate */ 3510Sstevel@tonic-gate if (state != OTYP_CHR) 3520Sstevel@tonic-gate return (ENXIO); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (rconsvp == NULL) 3550Sstevel@tonic-gate return (0); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) { 3585331Samw err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL); 3590Sstevel@tonic-gate if (!err) { 3600Sstevel@tonic-gate vp->v_stream = NULL; 3610Sstevel@tonic-gate rconsopen--; 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate return (err); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate /* ARGSUSED */ 3680Sstevel@tonic-gate static int 3690Sstevel@tonic-gate cnread(dev_t dev, struct uio *uio, struct cred *cred) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate kcondvar_t sleep_forever; 3720Sstevel@tonic-gate kmutex_t sleep_forever_mutex; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (rconsvp == NULL) { 3750Sstevel@tonic-gate /* 3760Sstevel@tonic-gate * Go to sleep forever. This seems like the least 3770Sstevel@tonic-gate * harmful thing to do if there's no console. 3780Sstevel@tonic-gate * EOF might be better if we're ending up single-user 3790Sstevel@tonic-gate * mode. 3800Sstevel@tonic-gate */ 3810Sstevel@tonic-gate cv_init(&sleep_forever, NULL, CV_DRIVER, NULL); 3820Sstevel@tonic-gate mutex_init(&sleep_forever_mutex, NULL, MUTEX_DRIVER, NULL); 3830Sstevel@tonic-gate mutex_enter(&sleep_forever_mutex); 3840Sstevel@tonic-gate (void) cv_wait_sig(&sleep_forever, &sleep_forever_mutex); 3850Sstevel@tonic-gate mutex_exit(&sleep_forever_mutex); 3860Sstevel@tonic-gate return (EIO); 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate if (rconsvp->v_stream != NULL) 3900Sstevel@tonic-gate return (strread(rconsvp, uio, cred)); 3910Sstevel@tonic-gate else 3920Sstevel@tonic-gate return (cdev_read(rconsdev, uio, cred)); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate /* ARGSUSED */ 3960Sstevel@tonic-gate static int 3970Sstevel@tonic-gate cnwrite(dev_t dev, struct uio *uio, struct cred *cred) 3980Sstevel@tonic-gate { 3990Sstevel@tonic-gate if (rconsvp == NULL) { 4000Sstevel@tonic-gate uio->uio_resid = 0; 4010Sstevel@tonic-gate return (0); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate if (rconsvp->v_stream != NULL) 4050Sstevel@tonic-gate return (strwrite(rconsvp, uio, cred)); 4060Sstevel@tonic-gate else 4070Sstevel@tonic-gate return (cdev_write(rconsdev, uio, cred)); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* ARGSUSED */ 4110Sstevel@tonic-gate static int 4121253Slq150181 cnprivateioc(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred, 4131253Slq150181 int *rvalp) 4141253Slq150181 { 4151253Slq150181 4161253Slq150181 /* currently we only support one ioctl */ 4171253Slq150181 if (cmd != CONS_GETTERM) 4181253Slq150181 return (EINVAL); 4191253Slq150181 4201253Slq150181 /* Confirm iwscn is immediate target of cn redirection */ 4211253Slq150181 if (rconsvp != wsconsvp) 4221253Slq150181 return (ENODEV); 4231253Slq150181 4241253Slq150181 /* 4251253Slq150181 * If the redirection client is not wc, it should return 4261253Slq150181 * error upon receiving the CONS_GETTERM ioctl. 4271253Slq150181 * 4281253Slq150181 * if it is wc, we know that the target supports the CONS_GETTERM 4291253Slq150181 * ioctl, which very conviently has the exact same data 4301253Slq150181 * format as this ioctl... so let's just pass it on. 4311253Slq150181 */ 4321253Slq150181 return (cdev_ioctl(rconsdev, CONS_GETTERM, arg, flag, cred, rvalp)); 4331253Slq150181 } 4341253Slq150181 4351253Slq150181 /* ARGSUSED */ 4361253Slq150181 static int 4370Sstevel@tonic-gate cnioctl(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred, 4380Sstevel@tonic-gate int *rvalp) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate if (rconsvp == NULL) 4410Sstevel@tonic-gate return (0); 4420Sstevel@tonic-gate 4431253Slq150181 if ((cmd & _CNIOC_MASK) == _CNIOC) 4441253Slq150181 return (cnprivateioc(dev, cmd, arg, flag, cred, rvalp)); 4451253Slq150181 else if (rconsvp->v_stream != NULL) 4460Sstevel@tonic-gate return (strioctl(rconsvp, cmd, arg, flag, U_TO_K, cred, 4470Sstevel@tonic-gate rvalp)); 4480Sstevel@tonic-gate else 4490Sstevel@tonic-gate return (cdev_ioctl(rconsdev, cmd, arg, flag, cred, rvalp)); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /* ARGSUSED */ 4530Sstevel@tonic-gate static int 4540Sstevel@tonic-gate cnpoll(dev_t dev, short events, int anyyet, short *reventsp, 4550Sstevel@tonic-gate struct pollhead **phpp) 4560Sstevel@tonic-gate { 4570Sstevel@tonic-gate if (rconsvp == NULL) 4580Sstevel@tonic-gate return (nochpoll(dev, events, anyyet, reventsp, phpp)); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate if (rconsvp->v_stream != NULL) 4610Sstevel@tonic-gate return (strpoll(rconsvp->v_stream, events, anyyet, reventsp, 4620Sstevel@tonic-gate phpp)); 4630Sstevel@tonic-gate else 4640Sstevel@tonic-gate return (cdev_poll(rconsdev, events, anyyet, reventsp, phpp)); 4650Sstevel@tonic-gate } 466