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