OpenSolaris_b135/uts/intel/io/polled_io.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/stropts.h>
#include <sys/devops.h>
#include <sys/modctl.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/promif.h>
#include <sys/note.h>
#include <sys/consdev.h>
#include <sys/polled_io.h>

/*
 * consconfig is aware of which devices are the stdin and stout.  The
 * post-attach/pre-detach functions are an extension of consconfig because
 * they know about the dynamic changes to the stdin device.  Neither an
 * individual driver nor the DDI framework knows what device is really the
 * stdin.
 */
/*
 * Issues:
 *	o There are probably race conditions between vx_handler for "read"
 *	  being called by OBP and the update of the polled_input_t
 *	  structure.  We need to be careful how the structure is updated.
 *
 * Solaris/Intel note:  While OBP is not in the picture, there are probably
 * similar issues with kmdb.
 */

#if	defined(MAYBE_SOMETIME)
static void	polled_give_input(void);
static void	polled_take_input(void);
static void	polled_give_output(void);
static void	polled_take_output(void);

static void	polled_io_register(cons_polledio_t *,
			polled_io_console_type_t, int);

static void	polled_io_unregister(polled_io_console_type_t, int);


/*
 * Make the registered device become the console for OBP
 */
static int	polled_io_take_console(polled_io_console_type_t, int);

/*
 * Restore the old console device for OBP.
 */
static int	polled_io_release_console(polled_io_console_type_t, int);
#endif	/* MAYBE_SOMETIME */

static polled_device_t	polled_input_device;
static polled_device_t	polled_output_device;

/*
 * This routine is called to initialize polled I/O.  We insert our entry
 * points so that OBP will call into this code when the switch is thrown
 * in polled_io_take_console().
 */
void
polled_io_init(void)
{
	/*
	 * Initialize lock to protect multiple thread access to the
	 * polled_input_device structure.  This does not protect
	 * us from access in OBP mode.
	 */
	mutex_init(&polled_input_device.polled_device_lock,
		NULL, MUTEX_DRIVER, NULL);

	/*
	 * Initialize lock to protect multiple thread access to the
	 * polled_output_device structure.  This does not protect
	 * us from access in OBP mode.
	 */
	mutex_init(&polled_output_device.polled_device_lock,
		NULL, MUTEX_DRIVER, NULL);
}

/*
 * Register a device for input or output.  The polled_io structure
 * will be filled in with the callbacks that are appropriate for
 * that device.
 */
int
polled_io_register_callbacks(
cons_polledio_t			*polled_io,
int				flags
)
{
#if	defined(MAYBE_SOMETIME)
	/*
	 * If the input structure entries are filled in, then register this
	 * structure as an input device.
	 */
	if ((polled_io->cons_polledio_getchar != NULL) &&
		(polled_io->cons_polledio_ischar != NULL)) {

		polled_io_register(polled_io,
			POLLED_IO_CONSOLE_INPUT, flags);
	}

	/*
	 * If the output structure entries are filled in, then register this
	 * structure as an output device.
	 */
	if (polled_io->cons_polledio_putchar != NULL) {

		polled_io_register(polled_io,
			POLLED_IO_CONSOLE_OUTPUT, flags);
	}
#else
_NOTE(ARGUNUSED(flags))
	cons_polledio = polled_io;
#endif

	return (DDI_SUCCESS);
}

/*
 * Unregister a device for console input/output.
 */
int
polled_io_unregister_callbacks(
cons_polledio_t			*polled_io,
int				flags
)
{
#if	defined(MAYBE_SOMETIME)
	/*
	 * If polled_io is being used for input, then unregister it.
	 */
	if (polled_io == polled_input_device.polled_io) {

		polled_io_unregister(
			POLLED_IO_CONSOLE_INPUT, flags);
	}

	/*
	 * If polled_io is being used for output, then unregister it.
	 */
	if (polled_io == polled_output_device.polled_io) {

		polled_io_unregister(
			POLLED_IO_CONSOLE_OUTPUT, flags);
	}
#else
_NOTE(ARGUNUSED(polled_io,flags))
#endif	/* MAYBE_SOMETIME */

	return (DDI_SUCCESS);
}

/*
 * This routine is called when we are done handling polled io.  We will
 * remove all of our handlers and destroy any memory that we have allocated.
 */
void
polled_io_fini()
{
	/*
	 * Destroy the mutexes, we will not need them anymore.
	 */
	mutex_destroy(&polled_input_device.polled_device_lock);

	mutex_destroy(&polled_output_device.polled_device_lock);
}

#if	defined(MAYBE_SOMETIME)
/*
 * Generic internal routine for registering a polled input or output device.
 */
/* ARGSUSED */
static void
polled_io_register(
cons_polledio_t			*polled_io,
polled_io_console_type_t	type,
int				flags
)
{
	switch (type) {
	case POLLED_IO_CONSOLE_INPUT:
		/*
		 * Grab the device lock, because we are going to access
		 * protected structure entries.  We do this before the
		 * POLLED_IO_CONSOLE_OPEN_INPUT so that we serialize
		 * registration.
		 */
		mutex_enter(&polled_input_device.polled_device_lock);

		/*
		 * Save the polled_io pointers so that we can access
		 * them later.
		 */
		polled_input_device.polled_io = polled_io;

		mutex_exit(&polled_input_device.polled_device_lock);

		/*
		 * Tell the generic console framework to
		 * repoint OBP's stdin to this keyboard device.
		 */
		(void) polled_io_take_console(type, 0);

		break;

	case POLLED_IO_CONSOLE_OUTPUT:
		/*
		 * Grab the device lock, because we are going to access
		 * protected structure entries. We do this before the
		 * POLLED_IO_CONSOLE_OPEN_OUTPUT so that we serialize
		 * registration.
		 */
		mutex_enter(&polled_output_device.polled_device_lock);

		/*
		 * Save the polled_io pointers so that we can access
		 * them later.
		 */
		polled_input_device.polled_io = polled_io;

		mutex_exit(&polled_output_device.polled_device_lock);

		break;
	}
}

/*
 * Generic internal routine for unregistering a polled input or output device.
 */
/* ARGSUSED */
static void
polled_io_unregister(
polled_io_console_type_t	type,
int				flags
)
{
	switch (type) {
	case POLLED_IO_CONSOLE_INPUT:
		/*
		 * Tell the generic console framework to restore OBP's
		 * old stdin pointers.
		 */
		(void) polled_io_release_console(type, 0);

		/*
		 * Grab the device lock, because we are going to access
		 * protected structure entries.
		 */
		mutex_enter(&polled_input_device.polled_device_lock);

		/*
		 * We are closing the device, so get the value for the op
		 * pointer.  We use the polled_io structure to determine if
		 * there is a device registered,  so null the dev_ops
		 * structure.
		 */
		polled_input_device.polled_io = NULL;

		mutex_exit(&polled_input_device.polled_device_lock);

		break;

	case POLLED_IO_CONSOLE_OUTPUT:
		/*
		 * Grab the device lock, because we are going to access
		 * protected structure entries.
		 */
		mutex_enter(&polled_output_device.polled_device_lock);

		/*
		 * We are closing the device, so get the value for the op
		 * pointer.  We use the polled_io structure to determine if
		 * there is a device registered.
		 */
		polled_output_device.polled_io = NULL;

		mutex_exit(&polled_output_device.polled_device_lock);

		break;
	}
}

/*
 * This is the routine that is called to throw the switch from boot
 * ownership of stdout/stdin to the kernel.
 */
/* ARGSUSED */
static int
polled_io_take_console(
polled_io_console_type_t	type,
int				flags
)
{
	switch (type) {
	case POLLED_IO_CONSOLE_INPUT:
		/*
		 * Perhaps this should be where we switch *sysp
		 */
		break;

	case POLLED_IO_CONSOLE_OUTPUT:
		/*
		 * Perhaps this should be where we switch *sysp
		 */
		break;
	}

	return (DDI_SUCCESS);
}

/*
 * This routine gives control of console input/output back to ???.
 *
 * Solaris/Intel has nobody to give it back to.  Hope we don't get here!
 */
/* ARGSUSED */
static int
polled_io_release_console(
polled_io_console_type_t	type,
int				flags
)
{
	cmn_err(CE_WARN,
	    "polled_io_release_console:  nobody to hand console back to");

	return (DDI_SUCCESS);
}

/*
 * This is the routine that kmdb calls to save any state information
 * before using the input device.  This routine, and all of the
 * routines that it calls, are responsible for saving any state
 * information so that it can be restored when polled mode is over.
 */
static void
polled_give_input(void)
{
	cons_polledio_t		*polled_io;

	/*
	 * We check the dev_ops pointer to see if there is an
	 * input device that has been registered.
	 */
	polled_io = polled_input_device.polled_io;

	if (polled_io == NULL || polled_io->cons_polledio_enter == NULL) {
		return;
	}

	/*
	 * Call down to the lower layers to save the state.
	 */
	polled_io->cons_polledio_enter(
		polled_io->cons_polledio_argument);
}

/*
 * This is the routine that kmdb calls when it is giving up control of the
 * input device.  This routine, and the lower layer routines that it calls,
 * are responsible for restoring the controller state to the state it was
 * in before kmdb took control.
 */
static void
polled_take_input(void)
{
	cons_polledio_t		*polled_io;

	/*
	 * We check the dev_ops pointer to see if there is an
	 * input device that has been registered.
	 */
	polled_io = polled_input_device.polled_io;

	if (polled_io == NULL || polled_io->cons_polledio_exit == NULL) {
		return;
	}

	/*
	 * Call down to the lower layers to save the state.
	 */
	polled_io->cons_polledio_exit(
		polled_io->cons_polledio_argument);
}

/*
 * This is the routine that kmdb calls to save any state information
 * before using the output device.  This routine, and all of the
 * routines that it calls, are responsible for saving any state
 * information so that it can be restored when polled mode is over.
 */
static void
polled_give_output()
{
	cons_polledio_t		*polled_io;

	/*
	 * We check the dev_ops pointer to see if there is an
	 * output device that has been registered.
	 */
	polled_io = polled_output_device.polled_io;

	if (polled_io == NULL || polled_io->cons_polledio_enter == NULL) {
		return;
	}

	/*
	 * Call down to the lower layers to save the state.
	 */
	polled_io->cons_polledio_enter(
		polled_io->cons_polledio_argument);
}

/*
 * This is the routine that kmdb calls when it is giving up control of the
 * output device.  This routine, and the lower layer routines that it calls,
 * are responsible for restoring the controller state to the state it was
 * in before kmdb took control.
 */
static void
polled_take_output(void)
{
	cons_polledio_t		*polled_io;

	/*
	 * We check the dev_ops pointer to see if there is an
	 * output device that has been registered.
	 */
	polled_io = polled_output_device.polled_io;

	if (polled_io == NULL || polled_io->cons_polledio_exit == NULL) {
		return;
	}

	/*
	 * Call down to the lower layers to save the state.
	 */
	polled_io->cons_polledio_exit(
		polled_io->cons_polledio_argument);
}
#endif	/* MAYBE_SOMETIME */