//==========================================================================
|
//==========================================================================
|
//
|
//
|
// io/iosys.c
|
// io/iosys.c
|
//
|
//
|
// I/O Subsystem + Device Table support
|
// I/O Subsystem + Device Table support
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// eCos is free software; you can redistribute it and/or modify it under
|
// the terms of the GNU General Public License as published by the Free
|
// the terms of the GNU General Public License as published by the Free
|
// Software Foundation; either version 2 or (at your option) any later version.
|
// Software Foundation; either version 2 or (at your option) any later version.
|
//
|
//
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use macros
|
// As a special exception, if other files instantiate templates or use macros
|
// or inline functions from this file, or you compile this file and link it
|
// or inline functions from this file, or you compile this file and link it
|
// with other works to produce a work based on this file, this file does not
|
// with other works to produce a work based on this file, this file does not
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// License. However the source code for this file must still be made available
|
// License. However the source code for this file must still be made available
|
// in accordance with section (3) of the GNU General Public License.
|
// in accordance with section (3) of the GNU General Public License.
|
//
|
//
|
// This exception does not invalidate any other reasons why a work based on
|
// This exception does not invalidate any other reasons why a work based on
|
// this file might be covered by the GNU General Public License.
|
// this file might be covered by the GNU General Public License.
|
//
|
//
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// -------------------------------------------
|
// -------------------------------------------
|
//####ECOSGPLCOPYRIGHTEND####
|
//####ECOSGPLCOPYRIGHTEND####
|
//==========================================================================
|
//==========================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): gthomas
|
// Author(s): gthomas
|
// Contributors: gthomas
|
// Contributors: gthomas
|
// Date: 1999-02-04
|
// Date: 1999-02-04
|
// Purpose: Device I/O Support
|
// Purpose: Device I/O Support
|
// Description:
|
// Description:
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
|
|
#include <pkgconf/io.h>
|
#include <pkgconf/io.h>
|
#include <cyg/io/io.h>
|
#include <cyg/io/io.h>
|
#include <cyg/io/devtab.h>
|
#include <cyg/io/devtab.h>
|
#include <cyg/infra/diag.h>
|
#include <cyg/infra/diag.h>
|
|
|
//extern void cyg_io_init(void) CYGBLD_ATTRIB_CONSTRUCTOR
|
//extern void cyg_io_init(void) CYGBLD_ATTRIB_CONSTRUCTOR
|
// CYG_INIT_PRIORITY(CYG_INIT_BEFORE(LIBC));
|
// CYG_INIT_PRIORITY(CYG_INIT_BEFORE(LIBC));
|
|
|
// Checks that two strings are "equivalent" device names
|
// Checks that two strings are "equivalent" device names
|
// 'n1' is a string from the user
|
// 'n1' is a string from the user
|
// 'n2' is a name in a device table entry
|
// 'n2' is a name in a device table entry
|
// 'cyg_io_compare()' will return true IFF
|
// 'cyg_io_compare()' will return true IFF
|
// n1 == n2, for all characters
|
// n1 == n2, for all characters
|
// n2 ends in '/' and matches n1 up to the terminating '/'
|
// n2 ends in '/' and matches n1 up to the terminating '/'
|
// 'ptr' will get a pointer to the residual string.
|
// 'ptr' will get a pointer to the residual string.
|
static bool
|
static bool
|
cyg_io_compare(const char *n1, const char *n2, const char **ptr)
|
cyg_io_compare(const char *n1, const char *n2, const char **ptr)
|
{
|
{
|
while (*n1 && *n2) {
|
while (*n1 && *n2) {
|
if (*n1++ != *n2++) {
|
if (*n1++ != *n2++) {
|
return false;
|
return false;
|
}
|
}
|
}
|
}
|
if (*n1) {
|
if (*n1) {
|
// See if the devtab name is is a substring
|
// See if the devtab name is is a substring
|
if (*(n2-1) == '/') {
|
if (*(n2-1) == '/') {
|
*ptr = n1;
|
*ptr = n1;
|
return true;
|
return true;
|
}
|
}
|
}
|
}
|
if (*n1 || *n2) {
|
if (*n1 || *n2) {
|
return false;
|
return false;
|
}
|
}
|
*ptr = n1;
|
*ptr = n1;
|
return true;
|
return true;
|
}
|
}
|
|
|
//
|
//
|
// This function is called during system initialization. The purpose is
|
// This function is called during system initialization. The purpose is
|
// to step through all devices linked into the system, calling their
|
// to step through all devices linked into the system, calling their
|
// "init" entry points.
|
// "init" entry points.
|
//
|
//
|
|
|
void
|
void
|
cyg_io_init(void)
|
cyg_io_init(void)
|
{
|
{
|
static int _init = false;
|
static int _init = false;
|
cyg_devtab_entry_t *t;
|
cyg_devtab_entry_t *t;
|
if (_init) return;
|
if (_init) return;
|
for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
|
for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
|
#ifdef CYGDBG_IO_INIT
|
#ifdef CYGDBG_IO_INIT
|
diag_printf("Init device '%s'\n", t->name);
|
diag_printf("Init device '%s'\n", t->name);
|
#endif
|
#endif
|
if (t->init(t)) {
|
if (t->init(t)) {
|
t->status |= CYG_DEVTAB_STATUS_AVAIL;
|
t->status |= CYG_DEVTAB_STATUS_AVAIL;
|
} else {
|
} else {
|
// What to do if device init fails?
|
// What to do if device init fails?
|
// Device not [currently] available
|
// Device not [currently] available
|
t->status &= ~CYG_DEVTAB_STATUS_AVAIL;
|
t->status &= ~CYG_DEVTAB_STATUS_AVAIL;
|
}
|
}
|
}
|
}
|
_init = true;
|
_init = true;
|
}
|
}
|
|
|
//
|
//
|
// Look up the devtab entry for a named device and return its handle.
|
// Look up the devtab entry for a named device and return its handle.
|
// If the device is found and it has a "lookup" function, call that
|
// If the device is found and it has a "lookup" function, call that
|
// function to allow the device/driver to perform any necessary
|
// function to allow the device/driver to perform any necessary
|
// initializations.
|
// initializations.
|
//
|
//
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_lookup(const char *name, cyg_io_handle_t *handle)
|
cyg_io_lookup(const char *name, cyg_io_handle_t *handle)
|
{
|
{
|
cyg_devtab_entry_t *t, *st;
|
cyg_devtab_entry_t *t, *st;
|
Cyg_ErrNo res;
|
Cyg_ErrNo res;
|
const char *name_ptr;
|
const char *name_ptr;
|
for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
|
for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
|
if (cyg_io_compare(name, t->name, &name_ptr)) {
|
if (cyg_io_compare(name, t->name, &name_ptr)) {
|
// FUTURE: Check 'avail'/'online' here
|
// FUTURE: Check 'avail'/'online' here
|
if (t->dep_name) {
|
if (t->dep_name) {
|
res = cyg_io_lookup(t->dep_name, (cyg_io_handle_t *)&st);
|
res = cyg_io_lookup(t->dep_name, (cyg_io_handle_t *)&st);
|
if (res != ENOERR) {
|
if (res != ENOERR) {
|
return res;
|
return res;
|
}
|
}
|
} else {
|
} else {
|
st = (cyg_devtab_entry_t *)0;
|
st = (cyg_devtab_entry_t *)0;
|
}
|
}
|
if (t->lookup) {
|
if (t->lookup) {
|
// This indirection + the name pointer allows the lookup routine
|
// This indirection + the name pointer allows the lookup routine
|
// to return a different 'devtab' handle. This will provide for
|
// to return a different 'devtab' handle. This will provide for
|
// 'pluggable' devices, file names, etc.
|
// 'pluggable' devices, file names, etc.
|
res = (t->lookup)(&t, st, name_ptr);
|
res = (t->lookup)(&t, st, name_ptr);
|
if (res != ENOERR) {
|
if (res != ENOERR) {
|
return res;
|
return res;
|
}
|
}
|
}
|
}
|
*handle = (cyg_io_handle_t)t;
|
*handle = (cyg_io_handle_t)t;
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
}
|
}
|
return -ENOENT; // Not found
|
return -ENOENT; // Not found
|
}
|
}
|
|
|
//
|
//
|
// 'write' data to a device.
|
// 'write' data to a device.
|
//
|
//
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len)
|
cyg_io_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->write) {
|
if (!t->handlers->write) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
// Special check. If length is zero, this just verifies that the
|
// Special check. If length is zero, this just verifies that the
|
// 'write' method exists for the given device.
|
// 'write' method exists for the given device.
|
if (NULL != len && 0 == *len) {
|
if (NULL != len && 0 == *len) {
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
return t->handlers->write(handle, buf, len);
|
return t->handlers->write(handle, buf, len);
|
}
|
}
|
|
|
//
|
//
|
// 'read' data from a device.
|
// 'read' data from a device.
|
//
|
//
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len)
|
cyg_io_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->read) {
|
if (!t->handlers->read) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
// Special check. If length is zero, this just verifies that the
|
// Special check. If length is zero, this just verifies that the
|
// 'read' method exists for the given device.
|
// 'read' method exists for the given device.
|
if (NULL != len && 0 == *len) {
|
if (NULL != len && 0 == *len) {
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
return t->handlers->read(handle, buf, len);
|
return t->handlers->read(handle, buf, len);
|
}
|
}
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_bwrite(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len, cyg_uint32 pos)
|
cyg_io_bwrite(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len, cyg_uint32 pos)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->bwrite) {
|
if (!t->handlers->bwrite) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
// Special check. If length is zero, this just verifies that the
|
// Special check. If length is zero, this just verifies that the
|
// 'bwrite' method exists for the given device.
|
// 'bwrite' method exists for the given device.
|
if (NULL != len && 0 == *len) {
|
if (NULL != len && 0 == *len) {
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
return t->handlers->bwrite(handle, buf, len, pos);
|
return t->handlers->bwrite(handle, buf, len, pos);
|
}
|
}
|
|
|
//
|
//
|
// 'read' data from a device.
|
// 'read' data from a device.
|
//
|
//
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_bread(cyg_io_handle_t handle, void *buf, cyg_uint32 *len, cyg_uint32 pos)
|
cyg_io_bread(cyg_io_handle_t handle, void *buf, cyg_uint32 *len, cyg_uint32 pos)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->bread) {
|
if (!t->handlers->bread) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
// Special check. If length is zero, this just verifies that the
|
// Special check. If length is zero, this just verifies that the
|
// 'bread' method exists for the given device.
|
// 'bread' method exists for the given device.
|
if (NULL != len && 0 == *len) {
|
if (NULL != len && 0 == *len) {
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
return t->handlers->bread(handle, buf, len, pos);
|
return t->handlers->bread(handle, buf, len, pos);
|
}
|
}
|
|
|
//
|
//
|
// Check device for available input or space for output
|
// Check device for available input or space for output
|
//
|
//
|
|
|
cyg_bool
|
cyg_bool
|
cyg_io_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
|
cyg_io_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->select) {
|
if (!t->handlers->select) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
return t->handlers->select( handle, which, info );
|
return t->handlers->select( handle, which, info );
|
}
|
}
|
|
|
//
|
//
|
// Get the configuration of a device.
|
// Get the configuration of a device.
|
//
|
//
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf, cyg_uint32 *len)
|
cyg_io_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf, cyg_uint32 *len)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->get_config) {
|
if (!t->handlers->get_config) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
// Special check. If length is zero, this just verifies that the
|
// Special check. If length is zero, this just verifies that the
|
// 'get_config' method exists for the given device.
|
// 'get_config' method exists for the given device.
|
if (NULL != len && 0 == *len) {
|
if (NULL != len && 0 == *len) {
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
return t->handlers->get_config(handle, key, buf, len);
|
return t->handlers->get_config(handle, key, buf, len);
|
}
|
}
|
|
|
//
|
//
|
// Change the configuration of a device.
|
// Change the configuration of a device.
|
//
|
//
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_io_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len)
|
cyg_io_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len)
|
{
|
{
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
|
// Validate request
|
// Validate request
|
if (!t->handlers->set_config) {
|
if (!t->handlers->set_config) {
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
// Special check. If length is zero, this just verifies that the
|
// Special check. If length is zero, this just verifies that the
|
// 'set_config' method exists for the given device.
|
// 'set_config' method exists for the given device.
|
if (NULL != len && 0 == *len) {
|
if (NULL != len && 0 == *len) {
|
return ENOERR;
|
return ENOERR;
|
}
|
}
|
return t->handlers->set_config(handle, key, buf, len);
|
return t->handlers->set_config(handle, key, buf, len);
|
}
|
}
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
// Default functions for devio tables
|
// Default functions for devio tables
|
|
|
Cyg_ErrNo cyg_devio_cwrite(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len)
|
Cyg_ErrNo cyg_devio_cwrite(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len)
|
{
|
{
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
Cyg_ErrNo cyg_devio_cread(cyg_io_handle_t handle, void *buf, cyg_uint32 *len)
|
Cyg_ErrNo cyg_devio_cread(cyg_io_handle_t handle, void *buf, cyg_uint32 *len)
|
{
|
{
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
Cyg_ErrNo cyg_devio_bwrite(cyg_io_handle_t handle, const void *buf,
|
Cyg_ErrNo cyg_devio_bwrite(cyg_io_handle_t handle, const void *buf,
|
cyg_uint32 *len, cyg_uint32 pos)
|
cyg_uint32 *len, cyg_uint32 pos)
|
{
|
{
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
Cyg_ErrNo cyg_devio_bread(cyg_io_handle_t handle, void *buf,
|
Cyg_ErrNo cyg_devio_bread(cyg_io_handle_t handle, void *buf,
|
cyg_uint32 *len, cyg_uint32 pos)
|
cyg_uint32 *len, cyg_uint32 pos)
|
{
|
{
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_devio_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
|
cyg_devio_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
|
{
|
{
|
CYG_UNUSED_PARAM(cyg_io_handle_t, handle);
|
CYG_UNUSED_PARAM(cyg_io_handle_t, handle);
|
CYG_UNUSED_PARAM(cyg_uint32, which);
|
CYG_UNUSED_PARAM(cyg_uint32, which);
|
CYG_UNUSED_PARAM(CYG_ADDRWORD, info);
|
CYG_UNUSED_PARAM(CYG_ADDRWORD, info);
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_devio_get_config(cyg_io_handle_t handle, cyg_uint32 key,
|
cyg_devio_get_config(cyg_io_handle_t handle, cyg_uint32 key,
|
void* buf, cyg_uint32* len)
|
void* buf, cyg_uint32* len)
|
{
|
{
|
CYG_UNUSED_PARAM(cyg_io_handle_t, handle);
|
CYG_UNUSED_PARAM(cyg_io_handle_t, handle);
|
CYG_UNUSED_PARAM(cyg_uint32, key);
|
CYG_UNUSED_PARAM(cyg_uint32, key);
|
CYG_UNUSED_PARAM(void*, buf);
|
CYG_UNUSED_PARAM(void*, buf);
|
CYG_UNUSED_PARAM(cyg_uint32*, len);
|
CYG_UNUSED_PARAM(cyg_uint32*, len);
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
Cyg_ErrNo
|
Cyg_ErrNo
|
cyg_devio_set_config(cyg_io_handle_t handle, cyg_uint32 key,
|
cyg_devio_set_config(cyg_io_handle_t handle, cyg_uint32 key,
|
void* buf, cyg_uint32* len)
|
void* buf, cyg_uint32* len)
|
{
|
{
|
CYG_UNUSED_PARAM(cyg_io_handle_t, handle);
|
CYG_UNUSED_PARAM(cyg_io_handle_t, handle);
|
CYG_UNUSED_PARAM(cyg_uint32, key);
|
CYG_UNUSED_PARAM(cyg_uint32, key);
|
CYG_UNUSED_PARAM(void*, buf);
|
CYG_UNUSED_PARAM(void*, buf);
|
CYG_UNUSED_PARAM(cyg_uint32*, len);
|
CYG_UNUSED_PARAM(cyg_uint32*, len);
|
return -EDEVNOSUPP;
|
return -EDEVNOSUPP;
|
}
|
}
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/* End of io/iosys.c */
|
/* End of io/iosys.c */
|
|
|