cons.c revision 361ed64a5abddd9ed26f47e25824bbce82557ab4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Indirect console driver for Sun.
*
* Redirects all I/O to the device designated as the underlying "hardware"
* console, as given by the value of rconsvp. The implementation assumes that
* rconsvp denotes a STREAMS device; the assumption is justified since
* consoles must be capable of effecting tty semantics.
*
* rconsvp is set in autoconf.c:consconfig(), based on information obtained
* from the EEPROM.
*
* XXX: The driver still needs to be converted to use ANSI C consistently
* throughout.
*/
cnopen, /* open */
cnclose, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
cnread, /* read */
cnwrite, /* write */
cnioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
cnpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
};
DEVO_REV, /* devo_rev, */
0, /* refcnt */
cn_info, /* info */
nulldev, /* identify */
nulldev, /* probe */
cn_attach, /* attach */
cn_detach, /* detach */
nodev, /* reset */
&cn_cb_ops, /* driver operations */
(struct bus_ops *)0, /* bus operations */
NULL, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
/*
* Global variables associated with the console device:
*
* XXX: There are too many of these!
* moved to space.c to become resident in the kernel so that cons
* can be loadable.
*/
/*
* XXX: consulted in prsubr.c, for /proc entry point for obtaining ps info.
*/
/*
* Private driver state:
*/
/*
* The underlying console device potentially can be opened through (at least)
* two paths: through this driver and through the underlying device's driver.
* To ensure that reference counts are meaningful and therefore that close
* routines are called at the right time, it's important to make sure that
* rconsvp's s_count field (i.e., the count on the underlying device) never
* has a contribution of more than one through this driver, regardless of how
* many times this driver's been opened. rconsopen keeps track of the
* necessary information to ensure this property.
*/
extern int dseekneg_flag;
extern struct mod_ops mod_driverops;
/*
* Module linkage information for the kernel.
*/
&mod_driverops, /* Type of module. This one is a pseudo driver */
"Console redirection driver",
&cn_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
&modldrv,
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (EBUSY);
}
int
{
}
/*
* DDI glue routines
*/
static int
{
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
{
int error = DDI_FAILURE;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)0;
error = DDI_SUCCESS;
}
break;
default:
break;
}
return (error);
}
/*
* XXX Caution: before allowing more than 256 minor devices on the
* console, make sure you understand the 'compatibility' hack
* in ufs_iget() that translates old dev_t's to new dev_t's.
* See bugid 1098104 for the sordid details.
*/
/* ARGSUSED */
static int
{
int err;
static int been_here;
return (0);
/*
* Enable virtual console I/O for console logging if needed.
*/
"for virtual console logging");
}
}
/*
* XXX: Clean up inactive PIDs from previous opens if any.
* These would have been created as a result of an I_SETSIG
* issued against console. This is a workaround, and
* console driver must be correctly redesigned not to need
* this hook.
*/
}
/*
* XXX: Set hook to tell /proc about underlying console. (There's
* gotta be a better way...)
*/
return (ENXIO);
if (been_here == 0) {
been_here = 1;
0, &console_vnode, 0, 0) == 0)
}
return (err);
/*
* The underlying driver is not allowed to have cloned itself
* for this open.
*/
/*
* It might happen that someone set rconsvp to NULL
* whilst we were in the middle of the open.
*/
return (0);
}
}
rconsopen++;
return (0);
}
/* ARGSUSED */
static int
{
int err = 0;
/*
* Since this is the _last_ close, it's our last chance to close the
* underlying device. (Note that if someone else has the underlying
* hardware console device open, we won't get here, since spec_close
* will see s_count > 1.)
*/
return (ENXIO);
return (0);
if (!err) {
rconsopen--;
}
}
return (err);
}
/* ARGSUSED */
static int
{
/*
* Go to sleep forever. This seems like the least
* harmful thing to do if there's no console.
* EOF might be better if we're ending up single-user
* mode.
*/
return (EIO);
}
else
}
/* ARGSUSED */
static int
{
return (0);
}
/*
* Output to virtual console for logging if enabled.
*/
/*
* strwrite modifies uio so need to make copy.
*/
}
else
}
/* ARGSUSED */
static int
int *rvalp)
{
/* currently we only support one ioctl */
if (cmd != CONS_GETTERM)
return (EINVAL);
/* Confirm iwscn is immediate target of cn redirection */
return (ENODEV);
/*
* If the redirection client is not wc, it should return
* error upon receiving the CONS_GETTERM ioctl.
*
* if it is wc, we know that the target supports the CONS_GETTERM
* ioctl, which very conviently has the exact same data
* format as this ioctl... so let's just pass it on.
*/
}
/* ARGSUSED */
static int
int *rvalp)
{
return (0);
rvalp));
else
}
/* ARGSUSED */
static int
{
phpp));
else
}