From b06e68ef1f6df69cc86d72356c3a002054a35fad Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 17 Aug 1995 19:51:51 +0000 Subject: 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 --- c/src/exec/libcsupport/include/clockdrv.h | 31 +- c/src/exec/libcsupport/include/rtems/assoc.h | 44 +++ c/src/exec/libcsupport/include/rtems/error.h | 26 ++ c/src/exec/libcsupport/include/rtems/libio.h | 101 +++++++ c/src/exec/libcsupport/src/assoc.c | 258 ++++++++++++++++ c/src/exec/libcsupport/src/error.c | 212 +++++++++++++ c/src/exec/libcsupport/src/libio.c | 433 +++++++++++++++++++++++++++ 7 files changed, 1086 insertions(+), 19 deletions(-) create mode 100644 c/src/exec/libcsupport/include/rtems/assoc.h create mode 100644 c/src/exec/libcsupport/include/rtems/error.h create mode 100644 c/src/exec/libcsupport/include/rtems/libio.h create mode 100644 c/src/exec/libcsupport/src/assoc.c create mode 100644 c/src/exec/libcsupport/src/error.c create mode 100644 c/src/exec/libcsupport/src/libio.c (limited to 'c/src/exec/libcsupport') diff --git a/c/src/exec/libcsupport/include/clockdrv.h b/c/src/exec/libcsupport/include/clockdrv.h index aad9bd6d3b..258c590e0d 100644 --- a/c/src/exec/libcsupport/include/clockdrv.h +++ b/c/src/exec/libcsupport/include/clockdrv.h @@ -23,31 +23,24 @@ extern "C" { /* variables */ extern volatile rtems_unsigned32 Clock_driver_ticks; +extern rtems_device_major_number rtems_clock_major; +extern rtems_device_minor_number rtems_clock_minor; -/* functions */ - -rtems_task Exit_task(); -void exit_task_init(); - -void Install_clock( rtems_isr_entry ); -void ReInstall_clock( rtems_isr_entry ); -void Clock_exit(); - -rtems_isr Clock_isr( - rtems_vector_number -); - -/* driver entries */ +/* default clock driver entry */ #define CLOCK_DRIVER_TABLE_ENTRY \ - { Clock_initialize, NULL, NULL, NULL, NULL, NULL } - + { Clock_initialize, NULL, NULL, NULL, NULL, Clock_control } + rtems_device_driver Clock_initialize( rtems_device_major_number, rtems_device_minor_number, - void *, - rtems_id, - rtems_unsigned32 * + void * +); + +rtems_device_driver Clock_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp ); #ifdef __cplusplus diff --git a/c/src/exec/libcsupport/include/rtems/assoc.h b/c/src/exec/libcsupport/include/rtems/assoc.h new file mode 100644 index 0000000000..c820cfa973 --- /dev/null +++ b/c/src/exec/libcsupport/include/rtems/assoc.h @@ -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 */ diff --git a/c/src/exec/libcsupport/include/rtems/error.h b/c/src/exec/libcsupport/include/rtems/error.h new file mode 100644 index 0000000000..a41f0aa534 --- /dev/null +++ b/c/src/exec/libcsupport/include/rtems/error.h @@ -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; + diff --git a/c/src/exec/libcsupport/include/rtems/libio.h b/c/src/exec/libcsupport/include/rtems/libio.h new file mode 100644 index 0000000000..f80a1954a3 --- /dev/null +++ b/c/src/exec/libcsupport/include/rtems/libio.h @@ -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 */ diff --git a/c/src/exec/libcsupport/src/assoc.c b/c/src/exec/libcsupport/src/assoc.c new file mode 100644 index 0000000000..c18359ef8a --- /dev/null +++ b/c/src/exec/libcsupport/src/assoc.c @@ -0,0 +1,258 @@ +/* + * @(#)assoc.c 1.4 - 95/08/02 + * + * + * assoc.c + * rtems assoc routines + * + * $Id$ + */ + + +#include +#include "assoc.h" + +#include /* sprintf */ +#include /* 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; +} diff --git a/c/src/exec/libcsupport/src/error.c b/c/src/exec/libcsupport/src/error.c new file mode 100644 index 0000000000..8cf46f0565 --- /dev/null +++ b/c/src/exec/libcsupport/src/error.c @@ -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 + * #include + * 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 + +#include "error.h" +#include "assoc.h" + +#include +#include +#include +#include +#include +#include /* _exit() */ + +/* bug in hpux : 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); +} diff --git a/c/src/exec/libcsupport/src/libio.c b/c/src/exec/libcsupport/src/libio.c new file mode 100644 index 0000000000..ce41643a09 --- /dev/null +++ b/c/src/exec/libcsupport/src/libio.c @@ -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 +#include /* assoc.h not included by rtems.h */ + +#include /* O_RDONLY, et.al. */ +#if defined(solaris2) +#define O_NDELAY O_NONBLOCK +#endif +#include +#include /* strcmp */ +#include +#include /* 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; +} -- cgit v1.2.3