summaryrefslogtreecommitdiffstats
path: root/cpukit/libcsupport
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libcsupport')
-rw-r--r--cpukit/libcsupport/include/clockdrv.h31
-rw-r--r--cpukit/libcsupport/include/rtems/assoc.h44
-rw-r--r--cpukit/libcsupport/include/rtems/error.h26
-rw-r--r--cpukit/libcsupport/include/rtems/libio.h101
-rw-r--r--cpukit/libcsupport/src/assoc.c258
-rw-r--r--cpukit/libcsupport/src/error.c212
-rw-r--r--cpukit/libcsupport/src/libio.c433
7 files changed, 1086 insertions, 19 deletions
diff --git a/cpukit/libcsupport/include/clockdrv.h b/cpukit/libcsupport/include/clockdrv.h
index aad9bd6d3b..258c590e0d 100644
--- a/cpukit/libcsupport/include/clockdrv.h
+++ b/cpukit/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/cpukit/libcsupport/include/rtems/assoc.h b/cpukit/libcsupport/include/rtems/assoc.h
new file mode 100644
index 0000000000..c820cfa973
--- /dev/null
+++ b/cpukit/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/cpukit/libcsupport/include/rtems/error.h b/cpukit/libcsupport/include/rtems/error.h
new file mode 100644
index 0000000000..a41f0aa534
--- /dev/null
+++ b/cpukit/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/cpukit/libcsupport/include/rtems/libio.h b/cpukit/libcsupport/include/rtems/libio.h
new file mode 100644
index 0000000000..f80a1954a3
--- /dev/null
+++ b/cpukit/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/cpukit/libcsupport/src/assoc.c b/cpukit/libcsupport/src/assoc.c
new file mode 100644
index 0000000000..c18359ef8a
--- /dev/null
+++ b/cpukit/libcsupport/src/assoc.c
@@ -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;
+}
diff --git a/cpukit/libcsupport/src/error.c b/cpukit/libcsupport/src/error.c
new file mode 100644
index 0000000000..8cf46f0565
--- /dev/null
+++ b/cpukit/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 <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);
+}
diff --git a/cpukit/libcsupport/src/libio.c b/cpukit/libcsupport/src/libio.c
new file mode 100644
index 0000000000..ce41643a09
--- /dev/null
+++ b/cpukit/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 <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;
+}