summaryrefslogtreecommitdiffstats
path: root/cpukit/libblock
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2010-08-13 12:40:16 +0000
committerSebastian Huber <sebastian.huber@embedded-brains.de>2010-08-13 12:40:16 +0000
commitd91e3a71bb6e6dbbb03b62c80fce972549ed13b7 (patch)
tree8dc154d81093b9fd349b83208d4133f188370220 /cpukit/libblock
parent2010-08-13 Chris Johns <chrisj@rtems.org> (diff)
downloadrtems-d91e3a71bb6e6dbbb03b62c80fce972549ed13b7.tar.bz2
2010-08-13 Sebastian Huber <sebastian.huber@embedded-brains.de>
* libblock/include/rtems/media.h, libblock/src/media-desc.c, libblock/src/media-dev-ident.c, libblock/src/media-path.c, libblock/src/media-server.c, libblock/src/media.c: New files. * Makefile.am, preinstall.am, libblock/Makefile.am: Reflect changes above.
Diffstat (limited to 'cpukit/libblock')
-rw-r--r--cpukit/libblock/Makefile.am5
-rw-r--r--cpukit/libblock/include/rtems/media.h525
-rw-r--r--cpukit/libblock/src/media-desc.c72
-rw-r--r--cpukit/libblock/src/media-dev-ident.c47
-rw-r--r--cpukit/libblock/src/media-path.c82
-rw-r--r--cpukit/libblock/src/media-server.c158
-rw-r--r--cpukit/libblock/src/media.c1012
7 files changed, 1901 insertions, 0 deletions
diff --git a/cpukit/libblock/Makefile.am b/cpukit/libblock/Makefile.am
index f4c86fe901..647adfe49d 100644
--- a/cpukit/libblock/Makefile.am
+++ b/cpukit/libblock/Makefile.am
@@ -20,6 +20,11 @@ libblock_a_SOURCES = src/bdbuf.c src/blkdev.c src/diskdevs.c src/flashdisk.c \
src/bdpart-register.c \
src/bdpart-sort.c \
src/bdpart-write.c \
+ src/media-path.c \
+ src/media.c \
+ src/media-server.c \
+ src/media-desc.c \
+ src/media-dev-ident.c \
include/rtems/bdbuf.h include/rtems/blkdev.h \
include/rtems/diskdevs.h include/rtems/flashdisk.h \
include/rtems/ramdisk.h include/rtems/nvdisk.h include/rtems/nvdisk-sram.h \
diff --git a/cpukit/libblock/include/rtems/media.h b/cpukit/libblock/include/rtems/media.h
new file mode 100644
index 0000000000..df37342fd6
--- /dev/null
+++ b/cpukit/libblock/include/rtems/media.h
@@ -0,0 +1,525 @@
+/**
+ * @file
+ *
+ * @ingroup RTEMSMedia
+ *
+ * @brief Media API.
+ */
+
+/*
+ * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef RTEMS_MEDIA_H
+#define RTEMS_MEDIA_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup RTEMSMedia Media Manager
+ *
+ * @brief Removable media support.
+ *
+ * The media manager may be used to maintain the life cycle of a removable
+ * media. Currently only disk devices are supported. The initiator posts an
+ * event to the media manager and it will respond with appropriate default
+ * actions. For example a disk attach will lead to inspection of the partition
+ * table and mounted file systems. Clients can register listeners to react to
+ * events.
+ * @{
+ */
+
+#define RTEMS_MEDIA_MOUNT_BASE "/media"
+
+#define RTEMS_MEDIA_DELIMITER '-'
+
+/**
+ * Disk life cycle events:
+ * @dot
+ * digraph disk_events {
+ * "DISK ATTACH" -> "PARTITION INQUIRY";
+ * "DISK ATTACH" -> "MOUNT";
+ * "PARTITION INQUIRY" -> "PARTITION ATTACH";
+ * "PARTITION INQUIRY" -> "DISK DETACH";
+ * "PARTITION ATTACH" -> "MOUNT";
+ * "MOUNT" -> "UNMOUNT";
+ * "UNMOUNT" -> "PARTITION DETACH";
+ * "UNMOUNT" -> "DISK DETACH";
+ * "PARTITION DETACH" -> "DISK DETACH";
+ * }
+ * @enddot
+ */
+typedef enum {
+ RTEMS_MEDIA_EVENT_DISK_ATTACH,
+ RTEMS_MEDIA_EVENT_DISK_DETACH,
+ RTEMS_MEDIA_EVENT_MOUNT,
+ RTEMS_MEDIA_EVENT_UNMOUNT,
+ RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
+ RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
+ RTEMS_MEDIA_EVENT_PARTITION_DETACH,
+ RTEMS_MEDIA_EVENT_ERROR
+} rtems_media_event;
+
+/**
+ * Normal state transition:
+ * @dot
+ * digraph state {
+ * INQUIRY -> READY [label="all listeners\nreturned successful"];
+ * INQUIRY -> ABORTED [label="otherwise"];
+ * READY -> SUCCESS [label="the worker\nreturned successful"];
+ * READY -> FAILED [label="otherwise"];
+ * }
+ * @enddot
+ */
+typedef enum {
+ RTEMS_MEDIA_STATE_INQUIRY,
+ RTEMS_MEDIA_STATE_READY,
+ RTEMS_MEDIA_STATE_ABORTED,
+ RTEMS_MEDIA_STATE_SUCCESS,
+ RTEMS_MEDIA_STATE_FAILED,
+ RTEMS_MEDIA_ERROR_DISK_UNKNOWN,
+ RTEMS_MEDIA_ERROR_DISK_EXISTS,
+ RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_UNKNOWN,
+ RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_EXISTS,
+ RTEMS_MEDIA_ERROR_PARTITION_UNKNOWN,
+ RTEMS_MEDIA_ERROR_PARTITION_ORPHAN,
+ RTEMS_MEDIA_ERROR_PARTITION_DETACH_WITH_MOUNT,
+ RTEMS_MEDIA_ERROR_PARTITION_WITH_UNKNOWN_DISK,
+ RTEMS_MEDIA_ERROR_MOUNT_POINT_UNKNOWN,
+ RTEMS_MEDIA_ERROR_MOUNT_POINT_EXISTS,
+ RTEMS_MEDIA_ERROR_MOUNT_POINT_ORPHAN
+} rtems_media_state;
+
+/**
+ * @brief Event listener.
+ *
+ * The listener will be called with the @a listener_arg passed to
+ * rtems_media_listener_add().
+ *
+ * Source and destination values for each event and state:
+ * <table>
+ * <tr><th>Event</th><th>State</th><th>Source</th><th>Destination</th></tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_DISK_ATTACH</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td><td>driver name</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td><td>driver name</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td><td>driver name</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td><td>driver name</td><td>disk path</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td><td>driver name</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_DISK_DETACH</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_PARTITION_INQUIRY</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_PARTITION_ATTACH</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td>
+ * <td>disk path</td><td>partition path</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_PARTITION_DETACH</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td><td>partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td><td>partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td><td>partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td><td>partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td><td>partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_MOUNT</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td>
+ * <td>disk or partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td>
+ * <td>disk or partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td>
+ * <td>disk or partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td>
+ * <td>disk or partition path</td><td>mount path</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td>
+ * <td>disk or partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="5">RTEMS_MEDIA_EVENT_UNMOUNT</td>
+ * <td>RTEMS_MEDIA_STATE_INQUIRY</td><td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_READY</td><td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_ABORTED</td><td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_SUCCESS</td><td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_STATE_FAILED</td><td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="11">RTEMS_MEDIA_EVENT_ERROR</td>
+ * <td>RTEMS_MEDIA_ERROR_DISK_UNKNOWN</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_DISK_EXISTS</td><td>disk path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_UNKNOWN</td>
+ * <td>disk or partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_EXISTS</td>
+ * <td>disk or partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_PARTITION_UNKNOWN</td>
+ * <td>partition path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_PARTITION_ORPHAN</td>
+ * <td>partition path</td><td>disk path</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_PARTITION_DETACH_WITH_MOUNT</td>
+ * <td>partition path</td><td>mount path</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_PARTITION_WITH_UNKNOWN_DISK</td>
+ * <td>partition path</td><td>disk path</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_MOUNT_POINT_UNKNOWN</td>
+ * <td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_MOUNT_POINT_EXISTS</td>
+ * <td>mount path</td><td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>RTEMS_MEDIA_ERROR_MOUNT_POINT_ORPHAN</td>
+ * <td>mount path</td><td>disk path</td>
+ * </tr>
+ * </table>
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_IO_ERROR In the inquiry state this will abort the action.
+ */
+typedef rtems_status_code (*rtems_media_listener)(
+ rtems_media_event event,
+ rtems_media_state state,
+ const char *src,
+ const char *dest,
+ void *listener_arg
+);
+
+/**
+ * @brief Do the work corresponding to an event.
+ *
+ * The @a state will be
+ * - RTEMS_MEDIA_STATE_READY, or
+ * - RTEMS_MEDIA_STATE_ABORTED.
+ *
+ * It will be called with the @a src and @a worker_arg arguments passed to
+ * rtems_media_post_event().
+ *
+ * The destination shall be returned in @a dest in case of success. It shall
+ * be allocated with malloc().
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_IO_ERROR Failure.
+ */
+typedef rtems_status_code (*rtems_media_worker)(
+ rtems_media_state state,
+ const char *src,
+ char **dest,
+ void *worker_arg
+);
+
+/**
+ * @name Base
+ *
+ * @{
+ */
+
+/**
+ * @brief Initializes the media manager.
+ *
+ * Calling this function more than once will have no effects. There is no
+ * protection against concurrent access.
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_NO_MEMORY Not enough resources.
+ */
+rtems_status_code rtems_media_initialize(void);
+
+/**
+ * @brief Adds the @a listener with argument @a listener_arg.
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_NO_MEMORY Not enough memory.
+ * @retval RTEMS_TOO_MANY Such a listener is already present.
+ */
+rtems_status_code rtems_media_listener_add(
+ rtems_media_listener listener,
+ void *listener_arg
+);
+
+/**
+ * @brief Removes the @a listener with argument @a listener_arg.
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_INVALID_ID No such listener is present.
+ */
+rtems_status_code rtems_media_listener_remove(
+ rtems_media_listener listener,
+ void *listener_arg
+);
+
+/**
+ * @brief Posts the @a event with source @a src.
+ *
+ * The @a worker will be called with the @a worker_arg argument.
+ *
+ * The destination will be returned in @a dest in case of success. It will be
+ * allocated with malloc() and should be freed if not needed anymore.
+ *
+ * The work will be done by the calling thread. You can avoid this if you use
+ * the media server via rtems_media_server_post_event().
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_UNSATISFIED One or more listeners aborted the action.
+ * @retval RTEMS_IO_ERROR The worker returned with an error status.
+ */
+rtems_status_code rtems_media_post_event(
+ rtems_media_event event,
+ const char *src,
+ char **dest,
+ rtems_media_worker worker,
+ void *worker_arg
+);
+
+/** @} */
+
+/**
+ * @name Server
+ *
+ * @{
+ */
+
+/**
+ * @brief Initializes the media manager and media server.
+ *
+ * It creates a server task with the @a priority, @a stack_size, @a modes, and
+ * @a attributes parameters.
+ *
+ * A message queue will be used for communication with the server task which
+ * may buffer up to @a message_count messages.
+ *
+ * Calling this function more than once will have no effects. There is no
+ * protection against concurrent access.
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_NO_MEMORY Not enough resources.
+ */
+rtems_status_code rtems_media_server_initialize(
+ rtems_task_priority priority,
+ size_t stack_size,
+ rtems_mode modes,
+ rtems_attribute attributes,
+ uint32_t message_count
+);
+
+/**
+ * @brief Sends an event message to the media server.
+ *
+ * @see See rtems_media_post_event().
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_UNSATISFIED Message queue is full.
+ * @retval RTEMS_NO_MEMORY Not enough memory for the message.
+ */
+rtems_status_code rtems_media_server_post_event(
+ rtems_media_event event,
+ const char *src,
+ rtems_media_worker worker,
+ void *worker_arg
+);
+
+/**
+ * @brief See rtems_media_server_post_event().
+ */
+static inline rtems_status_code rtems_media_server_disk_attach(
+ const char *driver_name,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ return rtems_media_server_post_event(
+ RTEMS_MEDIA_EVENT_DISK_ATTACH,
+ driver_name,
+ worker,
+ worker_arg
+ );
+}
+
+/**
+ * @brief See rtems_media_server_post_event().
+ */
+static inline rtems_status_code rtems_media_server_disk_detach(
+ const char *disk_path
+)
+{
+ return rtems_media_server_post_event(
+ RTEMS_MEDIA_EVENT_DISK_DETACH,
+ disk_path,
+ NULL,
+ NULL
+ );
+}
+
+/** @} */
+
+/**
+ * @name Path Construction
+ *
+ * @{
+ */
+
+/**
+ * @brief Creates a new path as "prefix/name-major".
+ *
+ * @return New string, or @c NULL if no memory is available.
+ */
+char *rtems_media_create_path(
+ const char *prefix,
+ const char *name,
+ rtems_device_major_number major
+);
+
+/**
+ * @brief Replaces the prefix of the @a path with @a new_prefix.
+ *
+ * The prefix is everything up to the last '/'.
+ *
+ * @return New string, or @c NULL if no memory is available.
+ */
+char *rtems_media_replace_prefix(const char *new_prefix, const char *path);
+
+/**
+ * @brief Appends the @a minor number to the @a path resulting in "path-minor".
+ *
+ * @return New string, or @c NULL if no memory is available.
+ */
+char *rtems_media_append_minor(
+ const char *path,
+ rtems_device_minor_number minor
+);
+
+/** @} */
+
+/**
+ * @name Support
+ *
+ * @{
+ */
+
+/**
+ * @brief Returns the device identifier for the device located at
+ * @a device_path in @a device_identifier.
+ *
+ * @retval RTEMS_SUCCESSFUL Successful operation.
+ * @retval RTEMS_INVALID_ID No device at this path.
+ */
+rtems_status_code rtems_media_get_device_identifier(
+ const char *device_path,
+ dev_t *device_identifier
+);
+
+const char *rtems_media_event_description(rtems_media_event event);
+
+const char *rtems_media_state_description(rtems_media_state state);
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* RTEMS_MEDIA_H */
diff --git a/cpukit/libblock/src/media-desc.c b/cpukit/libblock/src/media-desc.c
new file mode 100644
index 0000000000..005f0f7329
--- /dev/null
+++ b/cpukit/libblock/src/media-desc.c
@@ -0,0 +1,72 @@
+/**
+ * @file
+ *
+ * @ingroup RTEMSMedia
+ *
+ * @brief Media implementation.
+ */
+
+/*
+ * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems/media.h>
+
+static const char *const rtems_media_event_desc_table [] = {
+ [RTEMS_MEDIA_EVENT_DISK_ATTACH] = "DISK ATTACH",
+ [RTEMS_MEDIA_EVENT_DISK_DETACH] = "DISK DETACH",
+ [RTEMS_MEDIA_EVENT_MOUNT] = "MOUNT",
+ [RTEMS_MEDIA_EVENT_UNMOUNT] = "UNMOUNT",
+ [RTEMS_MEDIA_EVENT_PARTITION_INQUIRY] = "PARTITION INQUIRY",
+ [RTEMS_MEDIA_EVENT_PARTITION_ATTACH] = "PARTITION ATTACH",
+ [RTEMS_MEDIA_EVENT_PARTITION_DETACH] = "PARTITION DETACH"
+};
+
+static const char *const rtems_media_state_desc_table [] = {
+ [RTEMS_MEDIA_STATE_INQUIRY] = "INQUIRY",
+ [RTEMS_MEDIA_STATE_ABORTED] = "ABORTED",
+ [RTEMS_MEDIA_STATE_READY] = "SUCCESS",
+ [RTEMS_MEDIA_STATE_FAILED] = "FAILED",
+ [RTEMS_MEDIA_STATE_SUCCESS] = "SUCCESS",
+ [RTEMS_MEDIA_ERROR_DISK_UNKNOWN] = "ERROR DISK UNKNOWN",
+ [RTEMS_MEDIA_ERROR_DISK_EXISTS] = "ERROR DISK EXISTS",
+ [RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_UNKNOWN] = "ERROR DISK OR PARTITION UNKNOWN",
+ [RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_EXISTS] = "ERROR DISK OR PARTITION EXISTS",
+ [RTEMS_MEDIA_ERROR_PARTITION_UNKNOWN] = "ERROR PARTITION UNKNOWN",
+ [RTEMS_MEDIA_ERROR_PARTITION_ORPHAN] = "ERROR PARTITION ORPHAN",
+ [RTEMS_MEDIA_ERROR_PARTITION_DETACH_WITH_MOUNT] = "ERROR PARTITION DETACH WITH MOUNT",
+ [RTEMS_MEDIA_ERROR_PARTITION_WITH_UNKNOWN_DISK] = "ERROR PARTITION WITH UNKNOWN DISK",
+ [RTEMS_MEDIA_ERROR_MOUNT_POINT_UNKNOWN] = "ERROR MOUNT POINT UNKNOWN",
+ [RTEMS_MEDIA_ERROR_MOUNT_POINT_EXISTS] = "ERROR MOUNT POINT EXISTS",
+ [RTEMS_MEDIA_ERROR_MOUNT_POINT_ORPHAN] = "ERROR MOUNT POINT ORPHAN"
+};
+
+#define TC(table) (sizeof(table) / sizeof(table [0]))
+
+const char *rtems_media_event_description(rtems_media_event event)
+{
+ if ((size_t) event < TC(rtems_media_event_desc_table)) {
+ return rtems_media_event_desc_table [event];
+ } else {
+ return "INVALID";
+ }
+}
+
+const char *rtems_media_state_description(rtems_media_state state)
+{
+ if ((size_t) state < TC(rtems_media_state_desc_table)) {
+ return rtems_media_state_desc_table [state];
+ } else {
+ return "INVALID";
+ }
+}
diff --git a/cpukit/libblock/src/media-dev-ident.c b/cpukit/libblock/src/media-dev-ident.c
new file mode 100644
index 0000000000..7c0f298424
--- /dev/null
+++ b/cpukit/libblock/src/media-dev-ident.c
@@ -0,0 +1,47 @@
+/**
+ * @file
+ *
+ * @ingroup RTEMSMedia
+ *
+ * @brief Media implementation.
+ */
+
+/*
+ * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rtems.h>
+
+#include <rtems/media.h>
+
+rtems_status_code rtems_media_get_device_identifier(
+ const char *device_path,
+ dev_t *device_identifier
+)
+{
+ int rv = 0;
+ struct stat st;
+
+ rv = stat(device_path, &st);
+ if (rv != 0) {
+ return RTEMS_INVALID_ID;
+ }
+
+ *device_identifier = st.st_rdev;
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/cpukit/libblock/src/media-path.c b/cpukit/libblock/src/media-path.c
new file mode 100644
index 0000000000..19da3faa8c
--- /dev/null
+++ b/cpukit/libblock/src/media-path.c
@@ -0,0 +1,82 @@
+/**
+ * @file
+ *
+ * @ingroup RTEMSMedia
+ *
+ * @brief Media implementation.
+ */
+
+/*
+ * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <rtems/media.h>
+
+char *rtems_media_create_path(const char *prefix, const char *name, rtems_device_major_number major)
+{
+ size_t const len = strlen(prefix) + 1 + strlen(name) + 1 + 10 + 1;
+ char *const s = malloc(len);
+
+ if (s != NULL) {
+ int rv = snprintf(s, len, "%s/%s-%" PRIu32, prefix, name, major);
+
+ if (rv >= (int) len) {
+ free(s);
+
+ return NULL;
+ }
+ }
+
+ return s;
+}
+
+char *rtems_media_replace_prefix(const char *new_prefix, const char *path)
+{
+ const char *const name_try = strrchr(path, '/');
+ const char *const name = (name_try == NULL) ? path : name_try + 1;
+ size_t const new_prefix_len = strlen(new_prefix);
+ size_t const name_len = strlen(name);
+ size_t const len = new_prefix_len + 1 + name_len + 1;
+ char *const s = malloc(len);
+
+ if (s != NULL) {
+ strcpy(s, new_prefix);
+ strcpy(s + new_prefix_len, "/");
+ strcpy(s + new_prefix_len + 1, name);
+ }
+
+ return s;
+}
+
+char *rtems_media_append_minor(const char *path, rtems_device_minor_number minor)
+{
+ size_t const len = strlen(path) + 1 + 10 + 1;
+ char *const s = malloc(len);
+
+ if (s != NULL) {
+ int rv = snprintf(s, len, "%s-%" PRIu32, path, minor);
+
+ if (rv >= (int) len) {
+ free(s);
+
+ return NULL;
+ }
+ }
+
+ return s;
+}
diff --git a/cpukit/libblock/src/media-server.c b/cpukit/libblock/src/media-server.c
new file mode 100644
index 0000000000..85b2a6db08
--- /dev/null
+++ b/cpukit/libblock/src/media-server.c
@@ -0,0 +1,158 @@
+/**
+ * @file
+ *
+ * @ingroup RTEMSMedia
+ *
+ * @brief Media implementation.
+ */
+
+/*
+ * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <rtems/chain.h>
+
+#include <rtems/media.h>
+
+typedef struct {
+ rtems_media_event event;
+ char *src;
+ rtems_media_worker worker;
+ void *arg;
+} media_server_event;
+
+static rtems_id message_queue_id = RTEMS_ID_NONE;
+
+static void rtems_media_server(rtems_task_argument arg __attribute__((unused)))
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ while (true) {
+ media_server_event msg;
+ size_t msg_size = sizeof(msg);
+
+ sc = rtems_message_queue_receive(
+ message_queue_id,
+ &msg,
+ &msg_size,
+ RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ break;
+ }
+
+ rtems_media_post_event(msg.event, msg.src, NULL, msg.worker, msg.arg);
+
+ free(msg.src);
+ }
+
+ rtems_task_delete(RTEMS_SELF);
+}
+
+rtems_status_code rtems_media_server_initialize(
+ rtems_task_priority priority,
+ size_t stack_size,
+ rtems_mode modes,
+ rtems_attribute attributes,
+ uint32_t message_count
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_id task_id = RTEMS_ID_NONE;
+
+ if (message_queue_id == RTEMS_ID_NONE) {
+ sc = rtems_media_initialize();
+ if (sc != RTEMS_SUCCESSFUL) {
+ goto error;
+ }
+
+ sc = rtems_message_queue_create(
+ rtems_build_name('M', 'D', 'I', 'A'),
+ message_count,
+ sizeof(media_server_event),
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &message_queue_id
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ goto error;
+ }
+
+ sc = rtems_task_create(
+ rtems_build_name('M', 'D', 'I', 'A'),
+ priority,
+ stack_size,
+ modes,
+ attributes,
+ &task_id
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ goto error;
+ }
+
+ sc = rtems_task_start(task_id, rtems_media_server, 0);
+ if (sc != RTEMS_SUCCESSFUL) {
+ goto error;
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+
+error:
+
+ if (task_id != RTEMS_ID_NONE) {
+ rtems_task_delete(task_id);
+ }
+
+ rtems_message_queue_delete(message_queue_id);
+
+ return RTEMS_NO_MEMORY;
+}
+
+rtems_status_code rtems_media_server_post_event(
+ rtems_media_event event,
+ const char *src,
+ rtems_media_worker worker,
+ void *arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ media_server_event msg = {
+ .event = event,
+ .src = strdup(src),
+ .worker = worker,
+ .arg = arg
+ };
+
+ if (msg.src == NULL) {
+ return RTEMS_NO_MEMORY;
+ }
+
+ sc = rtems_message_queue_send(
+ message_queue_id,
+ &msg,
+ sizeof(msg)
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ free(msg.src);
+
+ return RTEMS_UNSATISFIED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/cpukit/libblock/src/media.c b/cpukit/libblock/src/media.c
new file mode 100644
index 0000000000..d63f7bef7e
--- /dev/null
+++ b/cpukit/libblock/src/media.c
@@ -0,0 +1,1012 @@
+/**
+ * @file
+ *
+ * @ingroup RTEMSMedia
+ *
+ * @brief Media implementation.
+ */
+
+/*
+ * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include <rtems.h>
+#include <rtems/bdbuf.h>
+#include <rtems/diskdevs.h>
+#include <rtems/bdpart.h>
+#include <rtems/libio.h>
+
+#include <rtems/media.h>
+
+typedef struct {
+ rtems_bdpart_partition *partitions;
+ size_t *count;
+} partition_table;
+
+typedef struct {
+ dev_t physical_disk;
+ dev_t logical_disk;
+ rtems_blkdev_bnum begin;
+ rtems_blkdev_bnum count;
+} partition;
+
+typedef struct media_item {
+ rtems_chain_node node;
+ struct media_item *parent;
+ char *disk_path;
+ char *mount_path;
+} media_item;
+
+typedef struct listener_item {
+ rtems_chain_node node;
+ rtems_media_listener listener;
+ void *listener_arg;
+} listener_item;
+
+static RTEMS_CHAIN_DEFINE_EMPTY(listener_item_chain);
+
+static RTEMS_CHAIN_DEFINE_EMPTY(media_item_chain);
+
+static rtems_id media_mutex = RTEMS_ID_NONE;
+
+static rtems_status_code lock(void)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = rtems_semaphore_obtain(media_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL) {
+ sc = RTEMS_NOT_CONFIGURED;
+ }
+
+ return sc;
+}
+
+static void unlock(void)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = rtems_semaphore_release(media_mutex);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static listener_item *find_listener(
+ rtems_media_listener listener,
+ void *listener_arg
+)
+{
+ rtems_chain_node *node = rtems_chain_first(&listener_item_chain);
+
+ while (!rtems_chain_is_tail(&listener_item_chain, node)) {
+ listener_item *item = (listener_item *) node;
+
+ if (item->listener == listener && item->listener_arg == listener_arg) {
+ return item;
+ }
+
+ node = rtems_chain_next(node);
+ }
+
+ return NULL;
+}
+
+rtems_status_code rtems_media_listener_add(
+ rtems_media_listener listener,
+ void *listener_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = lock();
+ if (sc == RTEMS_SUCCESSFUL) {
+ listener_item *item = find_listener(listener, listener_arg);
+
+ if (item == NULL) {
+ item = malloc(sizeof(*item));
+ if (item != NULL) {
+ item->listener = listener;
+ item->listener_arg = listener_arg;
+ rtems_chain_append_unprotected(&listener_item_chain, &item->node);
+ } else {
+ sc = RTEMS_NO_MEMORY;
+ }
+ } else {
+ sc = RTEMS_TOO_MANY;
+ }
+
+ unlock();
+ }
+
+ return sc;
+}
+
+rtems_status_code rtems_media_listener_remove(
+ rtems_media_listener listener,
+ void *listener_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = lock();
+ if (sc == RTEMS_SUCCESSFUL) {
+ listener_item *item = find_listener(listener, listener_arg);
+
+ if (item != NULL) {
+ rtems_chain_extract(&item->node);
+ free(item);
+ } else {
+ sc = RTEMS_INVALID_ID;
+ }
+
+ unlock();
+ }
+
+ return sc;
+}
+
+static rtems_status_code notify(
+ rtems_media_event event,
+ rtems_media_state state,
+ const char *src,
+ const char *dest
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_status_code rsc = RTEMS_SUCCESSFUL;
+ rtems_chain_node *node = rtems_chain_first(&listener_item_chain);
+
+ while (!rtems_chain_is_tail(&listener_item_chain, node)) {
+ listener_item *item = (listener_item *) node;
+
+ sc = (*item->listener)(event, state, src, dest, item->listener_arg);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = sc;
+ }
+
+ node = rtems_chain_next(node);
+ }
+
+ return rsc;
+}
+
+static void error(
+ rtems_media_state state,
+ const char *src,
+ const char *dest
+)
+{
+ notify(RTEMS_MEDIA_EVENT_ERROR, state, src, dest);
+}
+
+static media_item *get_media_item(
+ const char *disk_path,
+ const char *mount_path
+)
+{
+ rtems_chain_node *node = rtems_chain_first(&media_item_chain);
+
+ while (!rtems_chain_is_tail(&media_item_chain, node)) {
+ media_item *item = (media_item *) node;
+
+ if (
+ (disk_path == NULL || strcmp(disk_path, item->disk_path) == 0)
+ && (mount_path == NULL || strcmp(mount_path, item->mount_path) == 0)
+ ) {
+ return item;
+ }
+
+ node = rtems_chain_next(node);
+ }
+
+ return NULL;
+}
+
+static void free_item(media_item *item)
+{
+ rtems_chain_extract(&item->node);
+ free(item->mount_path);
+ free(item);
+}
+
+static void create_item(
+ media_item *parent,
+ const char *disk_path,
+ const char *mount_path
+)
+{
+ size_t disk_path_size = strlen(disk_path) + 1;
+ media_item *item = malloc(sizeof(*item) + disk_path_size);
+
+ if (item != NULL) {
+ if (mount_path != NULL) {
+ item->mount_path = strdup(mount_path);
+
+ if (item->mount_path == NULL) {
+ free(item);
+
+ return;
+ }
+ } else {
+ item->mount_path = NULL;
+ }
+
+ item->parent = parent;
+ item->disk_path = (char *) item + sizeof(*item);
+ strcpy(item->disk_path, disk_path);
+ rtems_chain_append(&media_item_chain, &item->node);
+ }
+}
+
+static void remove_mount_point(const char *mount_path)
+{
+ media_item *item = get_media_item(NULL, mount_path);
+
+ if (item != NULL) {
+ free(item->mount_path);
+ item->mount_path = NULL;
+ } else {
+ error(RTEMS_MEDIA_ERROR_MOUNT_POINT_UNKNOWN, mount_path, NULL);
+ }
+}
+
+static void remove_partition(const char *partition_path)
+{
+ media_item *item = get_media_item(partition_path, NULL);
+
+ if (item != NULL) {
+ if (item->mount_path != NULL) {
+ error(
+ RTEMS_MEDIA_ERROR_PARTITION_DETACH_WITH_MOUNT,
+ partition_path,
+ item->mount_path
+ );
+ }
+ free_item(item);
+ } else {
+ error(RTEMS_MEDIA_ERROR_PARTITION_UNKNOWN, partition_path, NULL);
+ }
+}
+
+static void remove_disk(const char *disk_path)
+{
+ media_item *item = get_media_item(disk_path, NULL);
+
+ if (item != NULL) {
+ rtems_chain_node *node = rtems_chain_first(&media_item_chain);
+
+ while (!rtems_chain_is_tail(&media_item_chain, node)) {
+ media_item *child = (media_item *) node;
+
+ node = rtems_chain_next(node);
+
+ if (child->parent == item) {
+ if (child->mount_path != NULL) {
+ error(
+ RTEMS_MEDIA_ERROR_MOUNT_POINT_ORPHAN,
+ child->mount_path,
+ disk_path
+ );
+ }
+ error(RTEMS_MEDIA_ERROR_PARTITION_ORPHAN, child->disk_path, disk_path);
+ free_item(child);
+ }
+ }
+
+ free_item(item);
+ } else {
+ error(RTEMS_MEDIA_ERROR_DISK_UNKNOWN, disk_path, NULL);
+ }
+}
+
+static void add_disk(const char *disk_path)
+{
+ media_item *item = get_media_item(disk_path, NULL);
+
+ if (item != NULL) {
+ error(RTEMS_MEDIA_ERROR_DISK_EXISTS, disk_path, NULL);
+ remove_disk(disk_path);
+ }
+
+ create_item(NULL, disk_path, NULL);
+}
+
+static void add_partition(const char *disk_path, const char *partition_path)
+{
+ media_item *item = get_media_item(partition_path, NULL);
+ media_item *parent = get_media_item(disk_path, NULL);
+
+ if (item != NULL) {
+ error(RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_EXISTS, partition_path, NULL);
+ remove_disk(partition_path);
+ }
+
+ if (parent != NULL) {
+ create_item(parent, partition_path, NULL);
+ } else {
+ error(
+ RTEMS_MEDIA_ERROR_PARTITION_WITH_UNKNOWN_DISK,
+ partition_path,
+ disk_path
+ );
+ }
+}
+
+static void add_mount_point(const char *disk_path, const char *mount_path)
+{
+ media_item *item = get_media_item(disk_path, NULL);
+
+ if (item != NULL) {
+ if (item->mount_path != NULL) {
+ error(RTEMS_MEDIA_ERROR_MOUNT_POINT_EXISTS, item->mount_path, NULL);
+ free(item->mount_path);
+ }
+ item->mount_path = strdup(mount_path);
+ } else {
+ error(RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_UNKNOWN, disk_path, NULL);
+ }
+}
+
+static bool is_add_state(rtems_media_state state)
+{
+ return state == RTEMS_MEDIA_STATE_SUCCESS;
+}
+
+static bool is_remove_state(rtems_media_state state)
+{
+ return state == RTEMS_MEDIA_STATE_SUCCESS
+ || state == RTEMS_MEDIA_STATE_FAILED;
+}
+
+static rtems_status_code remember_event(
+ rtems_media_event event,
+ rtems_media_state state,
+ const char *src,
+ const char *dest
+)
+{
+ switch (event) {
+ case RTEMS_MEDIA_EVENT_DISK_ATTACH:
+ if (is_add_state(state)) {
+ add_disk(dest);
+ }
+ break;
+ case RTEMS_MEDIA_EVENT_PARTITION_ATTACH:
+ if (is_add_state(state)) {
+ add_partition(src, dest);
+ }
+ break;
+ case RTEMS_MEDIA_EVENT_MOUNT:
+ if (is_add_state(state)) {
+ add_mount_point(src, dest);
+ }
+ break;
+ case RTEMS_MEDIA_EVENT_UNMOUNT:
+ if (is_remove_state(state)) {
+ remove_mount_point(src);
+ }
+ break;
+ case RTEMS_MEDIA_EVENT_PARTITION_DETACH:
+ if (is_remove_state(state)) {
+ remove_partition(src);
+ }
+ break;
+ case RTEMS_MEDIA_EVENT_DISK_DETACH:
+ if (is_remove_state(state)) {
+ remove_disk(src);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code process_event(
+ rtems_media_event event,
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_media_state state = RTEMS_MEDIA_STATE_FAILED;
+ char *dest = NULL;
+
+ sc = notify(event, RTEMS_MEDIA_STATE_INQUIRY, src, NULL);
+ if (sc == RTEMS_SUCCESSFUL) {
+ state = RTEMS_MEDIA_STATE_READY;
+ } else {
+ state = RTEMS_MEDIA_STATE_ABORTED;
+ }
+
+ sc = (*worker)(state, src, &dest, worker_arg);
+ if (state == RTEMS_MEDIA_STATE_READY) {
+ if (sc == RTEMS_SUCCESSFUL) {
+ state = RTEMS_MEDIA_STATE_SUCCESS;
+ } else {
+ state = RTEMS_MEDIA_STATE_FAILED;
+ }
+ }
+
+ notify(event, state, src, dest);
+ remember_event(event, state, src, dest);
+
+ if (state == RTEMS_MEDIA_STATE_SUCCESS) {
+ sc = RTEMS_SUCCESSFUL;
+ } else if (state == RTEMS_MEDIA_STATE_ABORTED) {
+ sc = RTEMS_UNSATISFIED;
+ } else {
+ sc = RTEMS_IO_ERROR;
+ }
+
+ if (dest_ptr != NULL && sc == RTEMS_SUCCESSFUL) {
+ *dest_ptr = dest;
+ } else {
+ free(dest);
+ }
+
+ return sc;
+}
+
+static rtems_status_code mount_worker(
+ rtems_media_state state,
+ const char *src,
+ char **dest,
+ void *worker_arg
+)
+{
+ int rv = 0;
+
+ if (state == RTEMS_MEDIA_STATE_READY) {
+ char *mount_path = NULL;
+
+ if (worker_arg == NULL) {
+ mount_path = rtems_media_replace_prefix(RTEMS_MEDIA_MOUNT_BASE, src);
+ } else {
+ mount_path = strdup(worker_arg);
+ }
+
+ if (mount_path == NULL) {
+ return RTEMS_IO_ERROR;
+ }
+
+ rv = rtems_mkdir(mount_path, S_IRWXU | S_IRWXG | S_IRWXO);
+ if (rv != 0) {
+ free(mount_path);
+
+ return RTEMS_IO_ERROR;
+ }
+
+ rv = mount(
+ src,
+ mount_path,
+ RTEMS_FILESYSTEM_TYPE_DOSFS,
+ RTEMS_FILESYSTEM_READ_WRITE,
+ NULL
+ );
+ if (rv != 0) {
+ rmdir(mount_path);
+ free(mount_path);
+
+ return RTEMS_IO_ERROR;
+ }
+
+ *dest = mount_path;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code do_mount(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ if (worker == NULL) {
+ worker = mount_worker;
+ }
+
+ return process_event(
+ RTEMS_MEDIA_EVENT_MOUNT,
+ src,
+ dest_ptr,
+ worker,
+ worker_arg
+ );
+}
+
+static rtems_status_code do_partition_attach(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ char *part_path = NULL;
+
+ if (worker != NULL) {
+ sc = process_event(
+ RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
+ src,
+ &part_path,
+ worker,
+ worker_arg
+ );
+
+ if (sc == RTEMS_SUCCESSFUL) {
+ sc = do_mount(part_path, NULL, NULL, NULL);
+ }
+ } else {
+ sc = RTEMS_INVALID_ADDRESS;
+ }
+
+ if (dest_ptr != NULL && sc == RTEMS_SUCCESSFUL) {
+ *dest_ptr = part_path;
+ } else {
+ free(part_path);
+ }
+
+ return sc;
+}
+
+static rtems_status_code partition_attach_worker(
+ rtems_media_state state,
+ const char *src,
+ char **dest,
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (state == RTEMS_MEDIA_STATE_READY) {
+ partition *part = worker_arg;
+ rtems_device_minor_number minor =
+ rtems_filesystem_dev_minor_t(part->logical_disk);
+ char *part_path = rtems_media_append_minor(src, minor);
+
+ if (part_path == NULL) {
+ return RTEMS_IO_ERROR;
+ }
+
+ sc = rtems_disk_create_log(
+ part->logical_disk,
+ part->physical_disk,
+ part->begin,
+ part->count,
+ part_path
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ free(part_path);
+
+ return RTEMS_IO_ERROR;
+ }
+
+ *dest = part_path;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code attach_and_mount_partitions(
+ const char *disk_path,
+ rtems_bdpart_partition *partitions,
+ size_t count
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_device_major_number major = 0;
+ rtems_device_minor_number minor = 0;
+ dev_t dev = 0;
+ size_t i = 0;
+
+ sc = rtems_media_get_device_identifier(disk_path, &dev);
+ if (sc != RTEMS_SUCCESSFUL) {
+ return RTEMS_INVALID_ID;
+ }
+
+ major = rtems_filesystem_dev_major_t(dev);
+ minor = rtems_filesystem_dev_minor_t(dev) + 1;
+
+ for (i = 0; i < count; ++i, ++minor) {
+ partition part_desc = {
+ .physical_disk = dev,
+ .logical_disk = rtems_filesystem_make_dev_t(major, minor),
+ .begin = partitions [i].begin,
+ .count = partitions [i].end - partitions [i].begin
+ };
+ char *part_path = NULL;
+
+ sc = process_event(
+ RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
+ disk_path,
+ &part_path,
+ partition_attach_worker,
+ &part_desc
+ );
+
+ if (sc == RTEMS_SUCCESSFUL) {
+ sc = do_mount(part_path, NULL, NULL, NULL);
+ }
+
+ free(part_path);
+ }
+
+ return sc;
+}
+
+static rtems_status_code partition_inquiry_worker(
+ rtems_media_state state,
+ const char *src,
+ char **dest __attribute__((unused)),
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (state == RTEMS_MEDIA_STATE_READY) {
+ partition_table *pt = worker_arg;
+ rtems_bdpart_format format;
+
+ sc = rtems_bdpart_read(src, &format, pt->partitions, pt->count);
+ if (sc != RTEMS_SUCCESSFUL || *pt->count == 0) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code do_partition_inquiry(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (worker == NULL) {
+ rtems_bdpart_partition partitions [RTEMS_BDPART_PARTITION_NUMBER_HINT];
+ size_t count = RTEMS_BDPART_PARTITION_NUMBER_HINT;
+ partition_table pt = {
+ .partitions = partitions,
+ .count = &count
+ };
+
+ sc = process_event(
+ RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
+ src,
+ dest_ptr,
+ partition_inquiry_worker,
+ &pt
+ );
+
+ if (sc == RTEMS_SUCCESSFUL) {
+ sc = attach_and_mount_partitions(src, partitions, count);
+ }
+ } else {
+ sc = process_event(
+ RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
+ src,
+ dest_ptr,
+ worker,
+ worker_arg
+ );
+ }
+
+ return sc;
+}
+
+static rtems_status_code do_disk_attach(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_status_code rsc = RTEMS_SUCCESSFUL;
+ char *disk_path = NULL;
+
+ if (worker != NULL) {
+ rsc = process_event(
+ RTEMS_MEDIA_EVENT_DISK_ATTACH,
+ src,
+ &disk_path,
+ worker,
+ worker_arg
+ );
+
+ if (rsc == RTEMS_SUCCESSFUL) {
+ sc = do_mount(disk_path, NULL, NULL, NULL);
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ do_partition_inquiry(disk_path, NULL, NULL, NULL);
+ }
+ }
+ } else {
+ rsc = RTEMS_INVALID_ADDRESS;
+ }
+
+ if (dest_ptr != NULL && rsc == RTEMS_SUCCESSFUL) {
+ *dest_ptr = disk_path;
+ } else {
+ free(disk_path);
+ }
+
+ return rsc;
+}
+
+static rtems_status_code unmount_worker(
+ rtems_media_state state,
+ const char *src,
+ char **dest __attribute__((unused)),
+ void *worker_arg __attribute__((unused))
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (state == RTEMS_MEDIA_STATE_READY) {
+ int rv = unmount(src);
+
+ if (rv == 0) {
+ rv = rmdir(src);
+ if (rv != 0) {
+ sc = RTEMS_IO_ERROR;
+ }
+ } else {
+ sc = RTEMS_IO_ERROR;
+ }
+ }
+
+ return sc;
+}
+
+static rtems_status_code do_unmount(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ if (worker == NULL) {
+ worker = unmount_worker;
+ worker_arg = NULL;
+ }
+
+ return process_event(
+ RTEMS_MEDIA_EVENT_UNMOUNT,
+ src,
+ dest_ptr,
+ worker,
+ worker_arg
+ );
+}
+
+static rtems_status_code disk_detach_worker(
+ rtems_media_state state,
+ const char *src,
+ char **dest __attribute__((unused)),
+ void *worker_arg __attribute__((unused))
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_status_code rsc = RTEMS_SUCCESSFUL;
+
+ if (state == RTEMS_MEDIA_STATE_READY) {
+ dev_t dev = 0;
+
+ sc = rtems_media_get_device_identifier(src, &dev);
+ if (sc != RTEMS_SUCCESSFUL) {
+ return RTEMS_IO_ERROR;
+ }
+
+ sc = rtems_bdbuf_syncdev(dev);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+
+ sc = rtems_disk_delete(dev);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+
+ rtems_bdbuf_purge_dev(dev);
+
+ if (rtems_filesystem_dev_minor_t(dev) == 0) {
+ sc = rtems_io_unregister_driver(rtems_filesystem_dev_major_t(dev));
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+ }
+ }
+
+ return rsc;
+}
+
+static rtems_status_code detach_item(rtems_media_event event, media_item *item)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_status_code rsc = RTEMS_SUCCESSFUL;
+
+ if (item->mount_path != NULL) {
+ sc = do_unmount(item->mount_path, NULL, NULL, NULL);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+ }
+
+ sc = process_event(event, item->disk_path, NULL, disk_detach_worker, NULL);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+
+ return rsc;
+}
+
+static rtems_status_code detach_parent_item(media_item *parent)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_status_code rsc = RTEMS_SUCCESSFUL;
+
+ rtems_chain_node *node = rtems_chain_first(&media_item_chain);
+
+ while (!rtems_chain_is_tail(&media_item_chain, node)) {
+ media_item *child = (media_item *) node;
+
+ node = rtems_chain_next(node);
+
+ if (child->parent == parent) {
+ sc = detach_item(RTEMS_MEDIA_EVENT_PARTITION_DETACH, child);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+ }
+ }
+
+ sc = detach_item(RTEMS_MEDIA_EVENT_DISK_DETACH, parent);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = RTEMS_IO_ERROR;
+ }
+
+ return rsc;
+}
+
+static rtems_status_code do_disk_detach(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ if (worker == NULL) {
+ media_item *parent = get_media_item(src, NULL);
+
+ if (parent != NULL) {
+ return detach_parent_item(parent);
+ }
+
+ worker = disk_detach_worker;
+ worker_arg = NULL;
+ }
+
+ return process_event(
+ RTEMS_MEDIA_EVENT_DISK_DETACH,
+ src,
+ dest_ptr,
+ worker,
+ worker_arg
+ );
+}
+
+static rtems_status_code do_partition_detach(
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ if (worker == NULL) {
+ media_item *item = get_media_item(src, NULL);
+
+ if (item != NULL) {
+ return detach_item(RTEMS_MEDIA_EVENT_PARTITION_DETACH, item);
+ }
+
+ worker = disk_detach_worker;
+ worker_arg = NULL;
+ }
+
+ return process_event(
+ RTEMS_MEDIA_EVENT_PARTITION_DETACH,
+ src,
+ dest_ptr,
+ worker,
+ worker_arg
+ );
+}
+
+rtems_status_code rtems_media_post_event(
+ rtems_media_event event,
+ const char *src,
+ char **dest_ptr,
+ rtems_media_worker worker,
+ void *worker_arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = lock();
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+
+ switch (event) {
+ case RTEMS_MEDIA_EVENT_DISK_ATTACH:
+ sc = do_disk_attach(src, dest_ptr, worker, worker_arg);
+ break;
+ case RTEMS_MEDIA_EVENT_DISK_DETACH:
+ sc = do_disk_detach(src, dest_ptr, worker, worker_arg);
+ break;
+ case RTEMS_MEDIA_EVENT_MOUNT:
+ sc = do_mount(src, dest_ptr, worker, worker_arg);
+ break;
+ case RTEMS_MEDIA_EVENT_UNMOUNT:
+ sc = do_unmount(src, dest_ptr, worker, worker_arg);
+ break;
+ case RTEMS_MEDIA_EVENT_PARTITION_INQUIRY:
+ sc = do_partition_inquiry(src, dest_ptr, worker, worker_arg);
+ break;
+ case RTEMS_MEDIA_EVENT_PARTITION_ATTACH:
+ sc = do_partition_attach(src, dest_ptr, worker, worker_arg);
+ break;
+ case RTEMS_MEDIA_EVENT_PARTITION_DETACH:
+ sc = do_partition_detach(src, dest_ptr, worker, worker_arg);
+ break;
+ default:
+ sc = RTEMS_INVALID_ID;
+ break;
+ }
+
+ unlock();
+
+ return sc;
+}
+
+rtems_status_code rtems_media_initialize(void)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (media_mutex == RTEMS_ID_NONE) {
+ sc = rtems_semaphore_create(
+ rtems_build_name('M', 'D', 'I', 'A'),
+ 1,
+ RTEMS_LOCAL | RTEMS_PRIORITY
+ | RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE,
+ 0,
+ &media_mutex
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ sc = RTEMS_NO_MEMORY;
+ }
+ }
+
+ return sc;
+}