forked from Imagelibrary/rtems
Numerous miscellaneous features incorporated from Tony Bennett
(tbennett@divnc.com) including the following major additions: + variable length messages + named devices + debug monitor + association tables/variables
This commit is contained in:
258
c/src/lib/libc/assoc.c
Normal file
258
c/src/lib/libc/assoc.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* @(#)assoc.c 1.4 - 95/08/02
|
||||
*
|
||||
*
|
||||
* assoc.c
|
||||
* rtems assoc routines
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
#include <rtems.h>
|
||||
#include "assoc.h"
|
||||
|
||||
#include <stdio.h> /* sprintf */
|
||||
#include <string.h> /* strcat, strcmp */
|
||||
|
||||
#define STREQ(a,b) (strcmp((a), (b)) == 0)
|
||||
#define rtems_assoc_is_default(ap) ((ap)->name && STREQ(ap->name, RTEMS_ASSOC_DEFAULT_NAME))
|
||||
|
||||
rtems_assoc_t *
|
||||
rtems_assoc_ptr_by_name(
|
||||
rtems_assoc_t *ap,
|
||||
char *name
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *default_ap = 0;
|
||||
|
||||
if (rtems_assoc_is_default(ap))
|
||||
default_ap = ap++;
|
||||
|
||||
for ( ; ap->name; ap++)
|
||||
if (strcmp(ap->name, name) == 0)
|
||||
return ap;
|
||||
|
||||
return default_ap;
|
||||
}
|
||||
|
||||
rtems_assoc_t *
|
||||
rtems_assoc_ptr_by_local(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 local_value
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *default_ap = 0;
|
||||
|
||||
if (rtems_assoc_is_default(ap))
|
||||
default_ap = ap++;
|
||||
|
||||
for ( ; ap->name; ap++)
|
||||
if (ap->local_value == local_value)
|
||||
return ap;
|
||||
|
||||
return default_ap;
|
||||
}
|
||||
|
||||
|
||||
rtems_assoc_t *
|
||||
rtems_assoc_ptr_by_remote(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 remote_value
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *default_ap = 0;
|
||||
|
||||
if (rtems_assoc_is_default(ap))
|
||||
default_ap = ap++;
|
||||
|
||||
for ( ; ap->name; ap++)
|
||||
if (ap->remote_value == remote_value)
|
||||
return ap;
|
||||
|
||||
return default_ap;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get values
|
||||
*/
|
||||
|
||||
unsigned32
|
||||
rtems_assoc_remote_by_local(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 local_value
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *nap;
|
||||
nap = rtems_assoc_ptr_by_local(ap, local_value);
|
||||
if (nap)
|
||||
return nap->remote_value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned32
|
||||
rtems_assoc_local_by_remote(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 remote_value
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *nap;
|
||||
nap = rtems_assoc_ptr_by_remote(ap, remote_value);
|
||||
if (nap)
|
||||
return nap->local_value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned32
|
||||
rtems_assoc_remote_by_name(
|
||||
rtems_assoc_t *ap,
|
||||
char *name
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *nap;
|
||||
nap = rtems_assoc_ptr_by_name(ap, name);
|
||||
if (nap)
|
||||
return nap->remote_value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned32
|
||||
rtems_assoc_local_by_name(
|
||||
rtems_assoc_t *ap,
|
||||
char *name
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *nap;
|
||||
nap = rtems_assoc_ptr_by_name(ap, name);
|
||||
if (nap)
|
||||
return nap->local_value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* what to return if a value is not found
|
||||
* this is not reentrant, but it really shouldn't be invoked anyway
|
||||
*/
|
||||
|
||||
char *
|
||||
rtems_assoc_name_bad(
|
||||
unsigned32 bad_value
|
||||
)
|
||||
{
|
||||
static char bad_buffer[32];
|
||||
|
||||
sprintf(bad_buffer, "< %d [0x%x] >", bad_value, bad_value);
|
||||
return bad_buffer;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
rtems_assoc_name_by_local(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 local_value
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *nap;
|
||||
nap = rtems_assoc_ptr_by_local(ap, local_value);
|
||||
if (nap)
|
||||
return nap->name;
|
||||
|
||||
return rtems_assoc_name_bad(local_value);
|
||||
}
|
||||
|
||||
char *
|
||||
rtems_assoc_name_by_remote(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 remote_value
|
||||
)
|
||||
{
|
||||
rtems_assoc_t *nap;
|
||||
nap = rtems_assoc_ptr_by_remote(ap, remote_value);
|
||||
if (nap)
|
||||
return nap->name;
|
||||
|
||||
return rtems_assoc_name_bad(remote_value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitfield functions assume just 1 bit set in each of remote and local
|
||||
* entries; they do not check for this.
|
||||
*/
|
||||
|
||||
unsigned32 rtems_assoc_remote_by_local_bitfield(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 local_value
|
||||
)
|
||||
{
|
||||
unsigned32 b;
|
||||
unsigned32 remote_value = 0;
|
||||
|
||||
for (b = 1; b; b <<= 1)
|
||||
if (b & local_value)
|
||||
remote_value |= rtems_assoc_remote_by_local(ap, b);
|
||||
|
||||
return remote_value;
|
||||
}
|
||||
|
||||
|
||||
unsigned32 rtems_assoc_local_by_remote_bitfield(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 remote_value
|
||||
)
|
||||
{
|
||||
unsigned32 b;
|
||||
unsigned32 local_value = 0;
|
||||
|
||||
for (b = 1; b; b <<= 1)
|
||||
if (b & remote_value)
|
||||
local_value |= rtems_assoc_local_by_remote(ap, b);
|
||||
|
||||
return local_value;
|
||||
}
|
||||
|
||||
char *rtems_assoc_name_by_remote_bitfield(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 value,
|
||||
char *buffer
|
||||
)
|
||||
{
|
||||
unsigned32 b;
|
||||
|
||||
*buffer = 0;
|
||||
|
||||
for (b = 1; b; b <<= 1)
|
||||
if (b & value)
|
||||
{
|
||||
if (*buffer)
|
||||
strcat(buffer, " ");
|
||||
strcat(buffer, rtems_assoc_name_by_remote(ap, b));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *rtems_assoc_name_by_local_bitfield(
|
||||
rtems_assoc_t *ap,
|
||||
unsigned32 value,
|
||||
char *buffer
|
||||
)
|
||||
{
|
||||
unsigned32 b;
|
||||
|
||||
*buffer = 0;
|
||||
|
||||
for (b = 1; b; b <<= 1)
|
||||
if (b & value)
|
||||
{
|
||||
if (*buffer)
|
||||
strcat(buffer, " ");
|
||||
strcat(buffer, rtems_assoc_name_by_local(ap, b));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
44
c/src/lib/libc/assoc.h
Normal file
44
c/src/lib/libc/assoc.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @(#)assoc.h 1.2 - 95/06/28
|
||||
*
|
||||
*
|
||||
* Rtems associativity routines. Mainly used to convert a value from
|
||||
* one space to another (eg: our errno's to host errno's and v.v)
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_ASSOC_H
|
||||
#define _INCLUDE_ASSOC_H
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
unsigned32 local_value;
|
||||
unsigned32 remote_value;
|
||||
} rtems_assoc_t;
|
||||
|
||||
/*
|
||||
* Flag/marker for optional default value in each table
|
||||
*/
|
||||
|
||||
#define RTEMS_ASSOC_DEFAULT_NAME "(default)"
|
||||
|
||||
rtems_assoc_t *rtems_assoc_ptr_by_name(rtems_assoc_t *, char *);
|
||||
rtems_assoc_t *rtems_assoc_ptr_by_value(rtems_assoc_t *, unsigned32);
|
||||
rtems_assoc_t *rtems_assoc_ptr_by_remote(rtems_assoc_t *, unsigned32);
|
||||
|
||||
unsigned32 rtems_assoc_remote_by_local(rtems_assoc_t *, unsigned32);
|
||||
unsigned32 rtems_assoc_local_by_remote(rtems_assoc_t *, unsigned32);
|
||||
unsigned32 rtems_assoc_remote_by_name(rtems_assoc_t *, char *);
|
||||
unsigned32 rtems_assoc_local_by_name(rtems_assoc_t *, char *);
|
||||
char *rtems_assoc_name_by_local(rtems_assoc_t *, unsigned32);
|
||||
char *rtems_assoc_name_by_remote(rtems_assoc_t *, unsigned32);
|
||||
|
||||
unsigned32 rtems_assoc_remote_by_local_bitfield(rtems_assoc_t *, unsigned32);
|
||||
char *rtems_assoc_name_by_local_bitfield(rtems_assoc_t *, unsigned32, char *);
|
||||
char *rtems_assoc_name_by_remote_bitfield(rtems_assoc_t *, unsigned32, char *);
|
||||
unsigned32 rtems_assoc_local_by_remote_bitfield(rtems_assoc_t *ap, unsigned32);
|
||||
|
||||
|
||||
#endif /* ! _INCLUDE_ASSOC_H */
|
||||
212
c/src/lib/libc/error.c
Normal file
212
c/src/lib/libc/error.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* @(#)error.c 1.2 - 95/08/02
|
||||
*
|
||||
*
|
||||
* report errors and panics to RTEMS' stderr.
|
||||
* Currently just used by RTEMS monitor.
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* These routines provide general purpose error reporting.
|
||||
* rtems_error reports an error to stderr and allows use of
|
||||
* printf style formatting. A newline is appended to all messages.
|
||||
*
|
||||
* error_flag can be specified as any of the following:
|
||||
*
|
||||
* RTEMS_ERROR_ERRNO -- include errno text in output
|
||||
* RTEMS_ERROR_PANIC -- halts local system after output
|
||||
* RTEMS_ERROR_ABORT -- abort after output
|
||||
*
|
||||
* It can also include a rtems_status value which can be OR'd
|
||||
* with the above flags. *
|
||||
*
|
||||
* EXAMPLE
|
||||
* #include <rtems.h>
|
||||
* #include <rtems/error.h>
|
||||
* rtems_error(0, "stray interrupt %d", intr);
|
||||
*
|
||||
* EXAMPLE
|
||||
* if ((status = rtems_task_create(...)) != RTEMS_SUCCCESSFUL)
|
||||
* {
|
||||
* rtems_error(status | RTEMS_ERROR_ABORT,
|
||||
* "could not create task");
|
||||
* }
|
||||
*
|
||||
* EXAMPLE
|
||||
* if ((fd = open(pathname, O_RDNLY)) < 0)
|
||||
* {
|
||||
* rtems_error(FLOSS_ERROR_ERRNO, "open of '%s' failed", pathname);
|
||||
* goto failed;
|
||||
* }
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "assoc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h> /* _exit() */
|
||||
|
||||
/* bug in hpux <errno.h>: no prototypes unless you are C++ */
|
||||
#ifdef hpux9
|
||||
char *strerror(int);
|
||||
#endif
|
||||
|
||||
extern char *rtems_progname;
|
||||
int rtems_panic_in_progress;
|
||||
|
||||
rtems_assoc_t rtems_status_assoc[] = {
|
||||
{ "successful completion", RTEMS_SUCCESSFUL, },
|
||||
{ "returned from a thread", RTEMS_TASK_EXITTED, },
|
||||
{ "multiprocessing not configured", RTEMS_MP_NOT_CONFIGURED, },
|
||||
{ "invalid object name", RTEMS_INVALID_NAME, },
|
||||
{ "invalid object id", RTEMS_INVALID_ID, },
|
||||
{ "too many", RTEMS_TOO_MANY, },
|
||||
{ "timed out waiting", RTEMS_TIMEOUT, },
|
||||
{ "object deleted while waiting", RTEMS_OBJECT_WAS_DELETED, },
|
||||
{ "specified size was invalid", RTEMS_INVALID_SIZE, },
|
||||
{ "address specified is invalid", RTEMS_INVALID_ADDRESS, },
|
||||
{ "number was invalid", RTEMS_INVALID_NUMBER, },
|
||||
{ "item has not been initialized", RTEMS_NOT_DEFINED, },
|
||||
{ "resources still outstanding", RTEMS_RESOURCE_IN_USE, },
|
||||
{ "request not satisfied", RTEMS_UNSATISFIED, },
|
||||
{ "thread is in wrong state", RTEMS_INCORRECT_STATE, },
|
||||
{ "thread already in state", RTEMS_ALREADY_SUSPENDED, },
|
||||
{ "illegal on calling thread", RTEMS_ILLEGAL_ON_SELF, },
|
||||
{ "illegal for remote object", RTEMS_ILLEGAL_ON_REMOTE_OBJECT, },
|
||||
{ "called from wrong environment", RTEMS_CALLED_FROM_ISR, },
|
||||
{ "invalid thread priority", RTEMS_INVALID_PRIORITY, },
|
||||
{ "invalid date/time", RTEMS_INVALID_CLOCK, },
|
||||
{ "invalid node id", RTEMS_INVALID_NODE, },
|
||||
{ "directive not configured", RTEMS_NOT_CONFIGURED, },
|
||||
{ "not owner of resource", RTEMS_NOT_OWNER_OF_RESOURCE , },
|
||||
{ "directive not implemented", RTEMS_NOT_IMPLEMENTED, },
|
||||
{ "RTEMS inconsistency detected", RTEMS_INTERNAL_ERROR, },
|
||||
{ "internal multiprocessing only", RTEMS_PROXY_BLOCKING, },
|
||||
{ "could not get enough memory", RTEMS_NO_MEMORY, },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
|
||||
char *
|
||||
rtems_status_text(
|
||||
rtems_status_code status
|
||||
)
|
||||
{
|
||||
return rtems_assoc_name_by_local(rtems_status_assoc, status);
|
||||
}
|
||||
|
||||
|
||||
static int rtems_verror(
|
||||
unsigned32 error_flag,
|
||||
char *printf_format,
|
||||
va_list arglist
|
||||
)
|
||||
{
|
||||
int local_errno = 0;
|
||||
int chars_written = 0;
|
||||
rtems_status_code status;
|
||||
|
||||
if (error_flag & RTEMS_ERROR_PANIC)
|
||||
{
|
||||
rtems_panic_in_progress++;
|
||||
|
||||
/* disable task switches */
|
||||
_Thread_Disable_dispatch();
|
||||
|
||||
/* don't aggravate things */
|
||||
if (rtems_panic_in_progress > 2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) fflush(stdout); /* in case stdout/stderr same */
|
||||
|
||||
status = error_flag & ~RTEMS_ERROR_MASK;
|
||||
if (error_flag & RTEMS_ERROR_ERRNO) /* include errno? */
|
||||
local_errno = errno;
|
||||
|
||||
if (_Configuration_Is_multiprocessing())
|
||||
fprintf(stderr, "[%d] ", _Configuration_MP_table->node);
|
||||
|
||||
if (rtems_progname && *rtems_progname)
|
||||
chars_written += fprintf(stderr, "%s: ", rtems_progname);
|
||||
chars_written += vfprintf(stderr, printf_format, arglist);
|
||||
|
||||
if (status)
|
||||
chars_written += fprintf(stderr, " (status: %s)", rtems_status_text(status));
|
||||
|
||||
if (local_errno)
|
||||
if ((local_errno > 0) && *strerror(local_errno))
|
||||
chars_written += fprintf(stderr, " (errno: %s)", strerror(local_errno));
|
||||
else
|
||||
chars_written += fprintf(stderr, " (unknown errno=%d)", local_errno);
|
||||
|
||||
chars_written += fprintf(stderr, "\n");
|
||||
|
||||
(void) fflush(stderr);
|
||||
|
||||
if (error_flag & (RTEMS_ERROR_PANIC | RTEMS_ERROR_ABORT))
|
||||
{
|
||||
if (error_flag & RTEMS_ERROR_PANIC)
|
||||
{
|
||||
rtems_error(0, "fatal error, exiting");
|
||||
_exit(local_errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtems_error(0, "fatal error, aborting");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
return chars_written;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Report an error.
|
||||
* error_flag is as above; printf_format is a normal
|
||||
* printf(3) format string, with its concommitant arguments.
|
||||
*
|
||||
* Returns the number of characters written.
|
||||
*/
|
||||
|
||||
int rtems_error(
|
||||
int error_flag,
|
||||
char *printf_format,
|
||||
...
|
||||
)
|
||||
{
|
||||
va_list arglist;
|
||||
int chars_written;
|
||||
|
||||
va_start(arglist, printf_format);
|
||||
chars_written = rtems_verror(error_flag, printf_format, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
return chars_written;
|
||||
}
|
||||
|
||||
/*
|
||||
* rtems_panic is shorthand for rtems_error(RTEMS_ERROR_PANIC, ...)
|
||||
*/
|
||||
|
||||
void rtems_panic(
|
||||
char *printf_format,
|
||||
...
|
||||
)
|
||||
{
|
||||
va_list arglist;
|
||||
|
||||
va_start(arglist, printf_format);
|
||||
(void) rtems_verror(RTEMS_ERROR_PANIC, printf_format, arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
26
c/src/lib/libc/error.h
Normal file
26
c/src/lib/libc/error.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* @(#)error.h 1.1 - 95/08/02
|
||||
*
|
||||
*
|
||||
* Defines and externs for rtems error reporting
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* rtems_error() and rtems_panic() support
|
||||
*/
|
||||
|
||||
#define RTEMS_ERROR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
|
||||
#define RTEMS_ERROR_PANIC (RTEMS_ERROR_ERRNO / 2) /* err fatal; no return */
|
||||
#define RTEMS_ERROR_ABORT (RTEMS_ERROR_ERRNO / 4) /* err is fatal; panic */
|
||||
|
||||
#define RTEMS_ERROR_MASK (RTEMS_ERROR_ERRNO | RTEMS_ERROR_ABORT | \
|
||||
RTEMS_ERROR_PANIC) /* all */
|
||||
|
||||
char *rtems_status_text(rtems_status_code);
|
||||
int rtems_error(int error_code, char *printf_format, ...);
|
||||
void rtems_panic(char *printf_format, ...);
|
||||
|
||||
extern int rtems_panic_in_progress;
|
||||
|
||||
433
c/src/lib/libc/libio.c
Normal file
433
c/src/lib/libc/libio.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* @(#)libio.c 1.1 - 95/06/02
|
||||
*
|
||||
*
|
||||
* Provide UNIX/POSIX-like io system calls for RTEMS using the
|
||||
* RTEMS IO manager
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/assoc.h> /* assoc.h not included by rtems.h */
|
||||
|
||||
#include <fcntl.h> /* O_RDONLY, et.al. */
|
||||
#if defined(solaris2)
|
||||
#define O_NDELAY O_NONBLOCK
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <string.h> /* strcmp */
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h> /* calloc() */
|
||||
|
||||
#include "libio.h" /* libio.h not pulled in by rtems */
|
||||
|
||||
/*
|
||||
* Semaphore to protect the io table
|
||||
*/
|
||||
|
||||
Objects_Id rtems_libio_semaphore;
|
||||
|
||||
#define RTEMS_LIBIO_SEM rtems_build_name('L', 'B', 'I', 'O')
|
||||
#define RTEMS_LIBIO_IOP_SEM(n) rtems_build_name('L', 'B', 'I', n)
|
||||
|
||||
unsigned32 rtems_libio_number_iops;
|
||||
rtems_libio_t *rtems_libio_iops;
|
||||
rtems_libio_t *rtems_libio_last_iop;
|
||||
|
||||
#define rtems_libio_iop(fd) ((((unsigned32)(fd)) < rtems_libio_number_iops) ? \
|
||||
&rtems_libio_iops[fd] : 0)
|
||||
|
||||
#define rtems_libio_check_fd(fd) \
|
||||
do { \
|
||||
if ((fd) >= rtems_libio_number_iops) \
|
||||
{ \
|
||||
errno = EBADF; \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define rtems_libio_check_buffer(buffer) \
|
||||
do { \
|
||||
if ((buffer) == 0) \
|
||||
{ \
|
||||
errno = EINVAL; \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define rtems_libio_check_count(count) \
|
||||
do { \
|
||||
if ((count) == 0) \
|
||||
{ \
|
||||
return 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define rtems_libio_check_permissions(iop, flag) \
|
||||
do { \
|
||||
if (((iop)->flags & (flag)) == 0) \
|
||||
{ \
|
||||
errno = EINVAL; \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
void
|
||||
rtems_libio_config(
|
||||
rtems_configuration_table *config,
|
||||
unsigned32 max_fds
|
||||
)
|
||||
{
|
||||
rtems_libio_number_iops = max_fds;
|
||||
|
||||
/*
|
||||
* tweak config to reflect # of semaphores we will need
|
||||
*/
|
||||
|
||||
config->maximum_semaphores += 1; /* one for iop table */
|
||||
config->maximum_semaphores += max_fds;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by bsp startup code to init the libio area.
|
||||
*/
|
||||
|
||||
void
|
||||
rtems_libio_init(void)
|
||||
{
|
||||
rtems_status_code rc;
|
||||
|
||||
if (rtems_libio_number_iops > 0)
|
||||
{
|
||||
rtems_libio_iops = (rtems_libio_t *) calloc(rtems_libio_number_iops,
|
||||
sizeof(rtems_libio_t));
|
||||
if (rtems_libio_iops == NULL)
|
||||
rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
|
||||
|
||||
rtems_libio_last_iop = rtems_libio_iops + (rtems_libio_number_iops - 1);
|
||||
}
|
||||
|
||||
rc = rtems_semaphore_create(RTEMS_LIBIO_SEM,
|
||||
1,
|
||||
RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
|
||||
&rtems_libio_semaphore);
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert RTEMS status to a UNIX errno
|
||||
*/
|
||||
|
||||
rtems_assoc_t errno_assoc[] = {
|
||||
{ "OK", RTEMS_SUCCESSFUL, 0 },
|
||||
{ "TIMEOUT", RTEMS_TIMEOUT, ETIME },
|
||||
{ "NO MEMORY", RTEMS_NO_MEMORY, ENOMEM },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
static unsigned32
|
||||
rtems_libio_errno(rtems_status_code code)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = rtems_assoc_remote_by_local(errno_assoc, (unsigned32) code)))
|
||||
{
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand
|
||||
*/
|
||||
|
||||
rtems_assoc_t access_modes_assoc[] = {
|
||||
{ "READ", LIBIO_FLAGS_READ, O_RDONLY },
|
||||
{ "WRITE", LIBIO_FLAGS_WRITE, O_WRONLY },
|
||||
{ "READ/WRITE", LIBIO_FLAGS_READ_WRITE, O_RDWR },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
rtems_assoc_t status_flags_assoc[] = {
|
||||
{ "NO DELAY", LIBIO_FLAGS_NO_DELAY, O_NDELAY },
|
||||
{ "APPEND", LIBIO_FLAGS_APPEND, O_APPEND },
|
||||
{ "CREATE", LIBIO_FLAGS_CREATE, O_CREAT },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
static unsigned32
|
||||
rtems_libio_fcntl_flags(unsigned32 fcntl_flags)
|
||||
{
|
||||
unsigned32 flags = 0;
|
||||
unsigned32 access_modes;
|
||||
|
||||
/*
|
||||
* Access mode is a small integer
|
||||
*/
|
||||
|
||||
access_modes = fcntl_flags & O_ACCMODE;
|
||||
fcntl_flags &= ~O_ACCMODE;
|
||||
flags = rtems_assoc_local_by_remote(access_modes_assoc, access_modes);
|
||||
|
||||
/*
|
||||
* Everything else is single bits
|
||||
*/
|
||||
|
||||
flags |= rtems_assoc_local_by_remote_bitfield(status_flags_assoc, fcntl_flags);
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
static rtems_libio_t *
|
||||
rtems_libio_allocate(void)
|
||||
{
|
||||
rtems_libio_t *iop;
|
||||
rtems_status_code rc;
|
||||
|
||||
rtems_semaphore_obtain(rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
|
||||
for (iop = rtems_libio_iops; iop <= rtems_libio_last_iop; iop++)
|
||||
if ((iop->flags & LIBIO_FLAGS_OPEN) == 0)
|
||||
{
|
||||
/*
|
||||
* Got one; create a semaphore for it
|
||||
*/
|
||||
|
||||
rc = rtems_semaphore_create(RTEMS_LIBIO_IOP_SEM(iop - rtems_libio_iops),
|
||||
1, RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
|
||||
&iop->sem);
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
goto failed;
|
||||
|
||||
iop->flags = LIBIO_FLAGS_OPEN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
failed:
|
||||
iop = 0;
|
||||
|
||||
done:
|
||||
rtems_semaphore_release(rtems_libio_semaphore);
|
||||
return iop;
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_libio_free(rtems_libio_t *iop)
|
||||
{
|
||||
rtems_semaphore_obtain(rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
|
||||
if (iop->sem)
|
||||
rtems_semaphore_delete(iop->sem);
|
||||
(void) memset(iop, 0, sizeof(*iop));
|
||||
|
||||
rtems_semaphore_release(rtems_libio_semaphore);
|
||||
}
|
||||
|
||||
int
|
||||
__open(
|
||||
const char *pathname,
|
||||
unsigned32 flag,
|
||||
unsigned32 mode)
|
||||
{
|
||||
rtems_status_code rc;
|
||||
rtems_libio_t *iop = 0;
|
||||
rtems_driver_name_t *np;
|
||||
rtems_libio_open_close_args_t args;
|
||||
|
||||
if ((rc = rtems_io_lookup_name(pathname, &np)) != RTEMS_SUCCESSFUL)
|
||||
goto done;
|
||||
|
||||
iop = rtems_libio_allocate();
|
||||
if (iop == 0)
|
||||
{
|
||||
rc = RTEMS_TOO_MANY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
iop->driver = np;
|
||||
iop->pathname = (char *) pathname;
|
||||
iop->flags |= rtems_libio_fcntl_flags(flag);
|
||||
|
||||
args.iop = iop;
|
||||
args.flags = iop->flags;
|
||||
args.mode = mode;
|
||||
|
||||
rc = rtems_io_open(np->major, np->minor, (void *) &args);
|
||||
|
||||
done:
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
{
|
||||
if (iop)
|
||||
rtems_libio_free(iop);
|
||||
return rtems_libio_errno(rc);
|
||||
}
|
||||
|
||||
return iop - rtems_libio_iops;
|
||||
}
|
||||
|
||||
int
|
||||
__close(
|
||||
int fd
|
||||
)
|
||||
{
|
||||
rtems_status_code rc;
|
||||
rtems_driver_name_t *np;
|
||||
rtems_libio_t *iop = rtems_libio_iop(fd);
|
||||
rtems_libio_open_close_args_t args;
|
||||
|
||||
rtems_libio_check_fd(fd);
|
||||
|
||||
np = iop->driver;
|
||||
|
||||
args.iop = iop;
|
||||
args.flags = 0;
|
||||
args.mode = 0;
|
||||
|
||||
rc = rtems_io_close(np->major, np->minor, (void *) &args);
|
||||
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
return rtems_libio_errno(rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__read(
|
||||
int fd,
|
||||
void * buffer,
|
||||
unsigned32 count
|
||||
)
|
||||
{
|
||||
rtems_status_code rc;
|
||||
rtems_driver_name_t *np;
|
||||
rtems_libio_t *iop = rtems_libio_iop(fd);
|
||||
rtems_libio_rw_args_t args;
|
||||
|
||||
rtems_libio_check_fd(fd);
|
||||
rtems_libio_check_buffer(buffer);
|
||||
rtems_libio_check_count(count);
|
||||
rtems_libio_check_permissions(iop, LIBIO_FLAGS_READ);
|
||||
|
||||
np = iop->driver;
|
||||
|
||||
args.iop = iop;
|
||||
args.offset = iop->offset;
|
||||
args.buffer = buffer;
|
||||
args.count = count;
|
||||
args.flags = iop->flags;
|
||||
args.bytes_moved = 0;
|
||||
|
||||
rc = rtems_io_read(np->major, np->minor, (void *) &args);
|
||||
|
||||
iop->offset += args.bytes_moved;
|
||||
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
return rtems_libio_errno(rc);
|
||||
|
||||
return args.bytes_moved;
|
||||
}
|
||||
|
||||
int
|
||||
__write(
|
||||
int fd,
|
||||
const void *buffer,
|
||||
unsigned32 count
|
||||
)
|
||||
{
|
||||
rtems_status_code rc;
|
||||
rtems_driver_name_t *np;
|
||||
rtems_libio_t *iop = rtems_libio_iop(fd);
|
||||
rtems_libio_rw_args_t args;
|
||||
|
||||
rtems_libio_check_fd(fd);
|
||||
rtems_libio_check_buffer(buffer);
|
||||
rtems_libio_check_count(count);
|
||||
rtems_libio_check_permissions(iop, LIBIO_FLAGS_WRITE);
|
||||
|
||||
np = iop->driver;
|
||||
|
||||
args.iop = iop;
|
||||
args.offset = iop->offset;
|
||||
args.buffer = (void *) buffer;
|
||||
args.count = count;
|
||||
args.flags = iop->flags;
|
||||
args.bytes_moved = 0;
|
||||
|
||||
rc = rtems_io_write(np->major, np->minor, (void *) &args);
|
||||
|
||||
iop->offset += args.bytes_moved;
|
||||
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
return rtems_libio_errno(rc);
|
||||
|
||||
return args.bytes_moved;
|
||||
}
|
||||
|
||||
int
|
||||
__ioctl(
|
||||
int fd,
|
||||
unsigned32 command,
|
||||
void * buffer)
|
||||
{
|
||||
rtems_status_code rc;
|
||||
rtems_driver_name_t *np;
|
||||
rtems_libio_t *iop = rtems_libio_iop(fd);
|
||||
rtems_libio_ioctl_args_t args;
|
||||
|
||||
rtems_libio_check_fd(fd);
|
||||
|
||||
np = iop->driver;
|
||||
|
||||
args.iop = iop;
|
||||
args.command = command;
|
||||
args.buffer = buffer;
|
||||
|
||||
rc = rtems_io_control(np->major, np->minor, (void *) &args);
|
||||
|
||||
if (rc != RTEMS_SUCCESSFUL)
|
||||
return rtems_libio_errno(rc);
|
||||
|
||||
return args.ioctl_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* internal only??
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
__lseek(
|
||||
int fd,
|
||||
rtems_libio_offset_t offset,
|
||||
int whence
|
||||
)
|
||||
{
|
||||
rtems_libio_t *iop = rtems_libio_iop(fd);
|
||||
|
||||
rtems_libio_check_fd(fd);
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
iop->offset = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
iop->offset += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
iop->offset = iop->size - offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
101
c/src/lib/libc/libio.h
Normal file
101
c/src/lib/libc/libio.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* @(#)libio.h 1.1 - 95/06/02
|
||||
*
|
||||
*
|
||||
* General purpose communication channel for RTEMS to allow UNIX/POSIX
|
||||
* system call behavior on top of RTEMS IO devices.
|
||||
*
|
||||
* TODO
|
||||
* stat(2)
|
||||
* unlink(2)
|
||||
* rename(2)
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _RTEMS_LIBIO_H
|
||||
#define _RTEMS_LIBIO_H
|
||||
|
||||
typedef unsigned32 rtems_libio_offset_t;
|
||||
|
||||
/*
|
||||
* An open file data structure, indexed by 'fd'
|
||||
* TODO:
|
||||
* should really have a separate per/file data structure that this
|
||||
* points to (eg: size, offset, driver, pathname should be in that)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rtems_driver_name_t *driver;
|
||||
rtems_libio_offset_t size; /* size of file */
|
||||
rtems_libio_offset_t offset; /* current offset into the file */
|
||||
unsigned32 flags;
|
||||
char *pathname; /* opened pathname */
|
||||
Objects_Id sem;
|
||||
unsigned32 data0; /* private to "driver" */
|
||||
unsigned32 data1; /* ... */
|
||||
} rtems_libio_t;
|
||||
|
||||
|
||||
/*
|
||||
* param block for read/write
|
||||
* Note: it must include 'offset' instead of using iop's offset since
|
||||
* we can have multiple outstanding i/o's on a device.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rtems_libio_t *iop;
|
||||
rtems_libio_offset_t offset;
|
||||
unsigned8 *buffer;
|
||||
unsigned32 count;
|
||||
unsigned32 flags;
|
||||
unsigned32 bytes_moved;
|
||||
} rtems_libio_rw_args_t;
|
||||
|
||||
/*
|
||||
* param block for open/close
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rtems_libio_t *iop;
|
||||
unsigned32 flags;
|
||||
unsigned32 mode;
|
||||
} rtems_libio_open_close_args_t;
|
||||
|
||||
/*
|
||||
* param block for ioctl
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rtems_libio_t *iop;
|
||||
unsigned32 command;
|
||||
void *buffer;
|
||||
unsigned32 ioctl_return;
|
||||
} rtems_libio_ioctl_args_t;
|
||||
|
||||
|
||||
/*
|
||||
* Values for 'flag'
|
||||
*/
|
||||
|
||||
#define LIBIO_FLAGS_NO_DELAY 0x0001 /* return immediately if no data */
|
||||
#define LIBIO_FLAGS_READ 0x0002 /* reading */
|
||||
#define LIBIO_FLAGS_WRITE 0x0004 /* writing */
|
||||
#define LIBIO_FLAGS_LINE_BUFFERED 0x0008 /* line buffered io (^h, ^u, etc) */
|
||||
#define LIBIO_FLAGS_OPEN 0x0100 /* device is open */
|
||||
#define LIBIO_FLAGS_APPEND 0x0200 /* all writes append */
|
||||
#define LIBIO_FLAGS_CREATE 0x0400 /* create file */
|
||||
|
||||
#define LIBIO_FLAGS_READ_WRITE (LIBIO_FLAGS_READ | LIBIO_FLAGS_WRITE)
|
||||
|
||||
void rtems_libio_config(rtems_configuration_table *config, unsigned32 max_fds);
|
||||
void rtems_libio_init(void);
|
||||
|
||||
int __open(const char *pathname, unsigned32 flag, unsigned32 mode);
|
||||
int __close(int fd);
|
||||
int __read(int fd, void *buffer, unsigned32 count);
|
||||
int __write(int fd, const void *buffer, unsigned32 count);
|
||||
int __ioctl(int fd, unsigned32 command, void *buffer);
|
||||
int __lseek(int fd, rtems_libio_offset_t offset, int whence);
|
||||
|
||||
#endif /* _RTEMS_LIBIO_H */
|
||||
@@ -35,27 +35,6 @@ __isatty(int _fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
__close(int _fd)
|
||||
{
|
||||
/* return value usually ignored anyhow */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__open(const char *filename)
|
||||
{
|
||||
/* always fail */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
__lseek(int _fd, off_t offset, int whence)
|
||||
{
|
||||
/* nothing is ever seekable */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int stat( const char *path, struct stat *buf )
|
||||
{
|
||||
/* always fail */
|
||||
|
||||
Reference in New Issue
Block a user