polled_io.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* 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"
/*
* This code sets up the callbacks(vx_handlers) so that the firmware may call
* The callbacks that execute in debug mode must be careful to not
* allocate memory, access mutexes, etc. because most kernel services are
* not available during this mode.
*
* This code, and the underlying code that supports the polled input, is very
* hard to debug. In order to get the code to execute, polled input must
* provide input to the debugger. If anything goes wrong with the code, then
* it is hard to debug the debugger. If there are any problems to debug,
* the following is useful:
*
* set polled_debug=1
*
* This variable will register the callbacks but will not throw the switch
* in the firmware. The callbacks can be executed by hand from the firmware.
* Boot the system and drop down to the firmware.
*
* ok " /os-io" select-dev
*
* The following will cause the polled_give_input to execute:
* ok take
*
* The following will cause the polled_take_input to execute:
* ok give
*
* The following will cause polled_read to execute:
* ok read
*/
#include <sys/polled_io.h>
/*
* Internal Functions
*/
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);
static int polled_io_take_console(polled_io_console_type_t, int);
static int polled_io_release_console(polled_io_console_type_t, int);
/*
*/
static polled_device_t polled_input_device;
static polled_device_t polled_output_device;
static int polled_vx_handlers_init = 0;
extern void remove_vx_handler(char *name);
/*
* This is a useful flag for debugging the entry points. This flag
* allows us to exercise the entry points from the firmware without
* switching the firmware's notion of the input device.
*/
int polled_debug = 0;
/*
* This routine is called to initialize polled I/O. We insert our entry
* points so that the firmware will call into this code
* when the switch is thrown in polled_io_take_console().
*/
void
polled_io_init(void)
{
/*
* Only do the initialization once
*/
if (polled_vx_handlers_init != 0)
return;
/*
* Add the vx_handlers for the different functions that
* need to be accessed from firmware.
*/
/*
* Initialize lock to protect multiple thread access to the
* polled_input_device structure. This does not protect
* us from access in debug mode.
*/
/*
* Initialize lock to protect multiple thread access to the
* polled_output_device structure. This does not protect
* us from access in debug mode.
*/
}
/*
* 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
int flags
)
{
/*
* If the input structure entries aren't filled in, then register this
* structure as an input device.
*/
}
/*
* If the output structure entries aren't filled in, then register this
* structure as an output device.
*/
}
return (DDI_SUCCESS);
}
/*
*/
int
int flags
)
{
/*
* If polled_io is being used for input, then unregister it.
*/
}
/*
* If polled_io is being used for output, then unregister it.
*/
}
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
{
/*
* Remove the vx_handlers so that our functions will nolonger be
* accessible.
*/
remove_vx_handler("enter-input");
remove_vx_handler("read");
remove_vx_handler("exit-input");
remove_vx_handler("give-output");
remove_vx_handler("write");
remove_vx_handler("take-output");
/*
* Destroy the mutexes, we will not need them anymore.
*/
}
/*
* Generic internal routine for registering a polled input or output device.
*/
/* ARGSUSED */
static void
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.
*/
/*
* Save the polled_io pointers so that we can access
* them later.
*/
if (!polled_debug) {
/*
* Tell the generic console framework to
* repoint firmware'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.
*/
/*
* Save the polled_io pointers so that we can access
* them later.
*/
break;
}
}
/*
* Generic internal routine for unregistering a polled input or output device.
*/
/* ARGSUSED */
static void
int flags
)
{
switch (type) {
case POLLED_IO_CONSOLE_INPUT:
/*
* Tell the generic console framework to restore
* the firmware's old stdin pointers.
*/
(void) polled_io_release_console(type, 0);
/*
* Grab the device lock, because we are going to access
* protected structure entries.
*/
break;
case POLLED_IO_CONSOLE_OUTPUT:
/*
* Grab the device lock, because we are going to access
* protected structure entries.
*/
break;
}
}
/*
* This is the routine that is called to throw the switch from the
*/
/* ARGSUSED */
static int
int flags
)
{
switch (type) {
case POLLED_IO_CONSOLE_INPUT:
/*
* Call into firmware to switch to the kernel I/O handling.
* We will save the old value of stdin so that we can
* restore it if the device is released.
*/
#ifdef DEBUG_OBP
/*
* This code is useful to trace through
* what the prom is doing
*/
"stdin @ swap ! trace-on \" /os-io\" input trace-off",
0, 0, 0, 0);
#endif
"stdin @ swap ! \" /os-io\" open-dev stdin !",
0, 0, 0, 0);
break;
case POLLED_IO_CONSOLE_OUTPUT:
/*
* Call into firmware to switch to the kernel I/O handling.
* We will save the old value of stdout so that we can
* restore it if the device is released.
*/
"stdout @ swap ! \" /os-io\" output",
0, 0, 0, 0);
break;
}
return (DDI_SUCCESS);
}
/*
*/
/* ARGSUSED */
static int
int flags
)
{
switch (type) {
case POLLED_IO_CONSOLE_INPUT:
/*
* Restore the stdin handle
*/
prom_interpret("to stdin",
0, 0, 0, 0);
break;
case POLLED_IO_CONSOLE_OUTPUT:
/*
* Restore the stdout handle
*/
prom_interpret("to stdout",
0, 0, 0, 0);
break;
}
return (DDI_SUCCESS);
}
/*
* This is the routine that the firmware 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 debug mode is over.
*
* WARNING: This routine runs in debug mode.
*/
static void
{
/*
* Calculate the offset of the return arguments
*/
out_args = CIF_MIN_SIZE +
/*
* There is one argument being passed back to firmware.
*/
/*
* We check to see if there is an
* input device that has been registered.
*/
return;
}
/*
* Call down to the lower layers to save the state.
*/
}
/*
* This is the routine that the firmware calls
* when it wants to read a character.
* We will call to the lower layers to see if there is any input data
* available.
*
* WARNING: This routine runs in debug mode.
*/
static void
{
/*
* The number of arguments passed in by the firmware
*/
/*
* Calculate the location of the first out arg. This location is
* CIF_MIN_SIZE plus the in argument locations.
*/
/*
* The firmware should pass in a pointer to a buffer, and the
* number of characters it expects or expects to write.
* If 2 arguments are not passed in, then return an error.
*/
if (in_args != 2) {
/*
* Tell firmware how many arguments we are passing back.
*/
/*
* Tell the firmware that we cannot give it any characters.
*/
return;
}
/*
* Get the address of where to copy the characters into.
*/
/*
* Get the length of the buffer that we can copy characters into.
*/
/*
* Make sure there is enough room in the buffer to copy the
* characters into.
*/
if (buflen == 0) {
/*
* Tell the OBP that we cannot give it any characters.
*/
/*
* Tell the firmware that we cannot give it any characters.
*/
return;
}
/*
* Pass back whether or not the operation was a success or
* failure plus the actual number of bytes in the buffer.
* Tell firmware how many arguments we are passing back.
*/
/*
* Initialize the cif to be "no characters"
*/
/*
* We check to see if there is an
* input device that has been registered.
*/
/*
* The cif structure is already set up to return
* no characters.
*/
return;
}
actual = 0;
/*
* Obtain the characters
*/
while (polled_io->cons_polledio_ischar(
/*
* Make sure that we don't overrun the buffer.
*/
break;
}
/*
* Call down to the device to copy the input data into the
* buffer.
*/
actual++;
}
/*
* There is a special return code when there is no data.
*/
if (actual == 0) {
/*
* The cif structure is already set up to return
* no characters.
*/
return;
}
/*
* Tell firmware how many characters we are sending it.
*/
}
/*
* This is the routine that firmware 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 firmware took control.
*
* WARNING: This routine runs in debug mode.
*/
static void
{
/*
* Calculate the offset of the return arguments
*/
out_args = CIF_MIN_SIZE +
/*
* There is one argument being passed back to firmware.
*/
/*
* We check the pointer to see if there is an
* input device that has been registered.
*/
return;
}
/*
* Call down to the lower layers to save the state.
*/
}
/*
* This is the routine that the firmware 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 the debug is over.
*
* WARNING: This routine runs in debug mode.
*/
static void
{
/*
* Calculate the offset of the return arguments
*/
out_args = CIF_MIN_SIZE +
/*
* There is one argument being passed back to the firmware .
*/
/*
* We check to see if there is an
* output device that has been registered.
*/
return;
}
/*
* Call down to the lower layers to save the state.
*/
}
/*
* This is the routine that the firmware calls when
* it wants to write a character.
*
* WARNING: This routine runs in debug mode.
*/
static void
{
uint_t i;
/*
* The number of arguments passed in by the firmware
*/
/*
* Calculate the location of the first out arg. This location is
* CIF_MIN_SIZE (name + no. in args + no. out args) plus the
* in argument locations.
*/
/*
* The firmware should pass in a pointer to a buffer, and the
* number of characters it expects or expects to write.
* If 2 arguments are not passed in, then return an error.
*/
if (in_args != 2) {
/*
* Tell firmware how many arguments we are passing back.
*/
/*
* Tell the firmware that we cannot give it any characters.
*/
return;
}
/*
* Get the address of where to copy the characters into.
*/
/*
* Get the length of the buffer that we can copy characters into.
*/
/*
* Make sure there is enough room in the buffer to copy the
* characters into.
*/
if (buflen == 0) {
/*
* Tell the OBP that we cannot give it any characters.
*/
/*
* Tell the firmware that we cannot give it any characters.
*/
return;
}
/*
* Tell the firmware how many arguments we are passing back.
*/
/*
* Initialize the cif to success
*/
/*
* We check the pointer to see if there is an
* input device that has been registered.
*/
/*
* The cif is already initialized
*/
return;
}
for (i = 0; i < buflen; i++) {
}
/*
* Tell the firmware how many characters we are sending it.
*/
}
/*
* This is the routine that the firmware 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 the firmware took control.
*
* WARNING: This routine runs in debug mode.
*/
static void
{
/*
* Calculate the offset of the return arguments
*/
out_args = CIF_MIN_SIZE +
/*
* There is one argument being passed back to the firmware.
*/
/*
* We check the pointer to see if there is an
* output device that has been registered.
*/
return;
}
/*
* Call down to the lower layers to save the state.
*/
}