diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2010-08-13 12:40:16 +0000 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2010-08-13 12:40:16 +0000 |
commit | d91e3a71bb6e6dbbb03b62c80fce972549ed13b7 (patch) | |
tree | 8dc154d81093b9fd349b83208d4133f188370220 /cpukit | |
parent | 2010-08-13 Chris Johns <chrisj@rtems.org> (diff) | |
download | rtems-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 '')
-rw-r--r-- | cpukit/ChangeLog | 8 | ||||
-rw-r--r-- | cpukit/Makefile.am | 3 | ||||
-rw-r--r-- | cpukit/libblock/Makefile.am | 5 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/media.h | 525 | ||||
-rw-r--r-- | cpukit/libblock/src/media-desc.c | 72 | ||||
-rw-r--r-- | cpukit/libblock/src/media-dev-ident.c | 47 | ||||
-rw-r--r-- | cpukit/libblock/src/media-path.c | 82 | ||||
-rw-r--r-- | cpukit/libblock/src/media-server.c | 158 | ||||
-rw-r--r-- | cpukit/libblock/src/media.c | 1012 | ||||
-rw-r--r-- | cpukit/preinstall.am | 4 |
10 files changed, 1915 insertions, 1 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 409e87bad0..896d01f90f 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,11 @@ +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. + 2010-08-13 Chris Johns <chrisj@rtems.org> * libfs/src/imfs/imfs_eval.c: Add the missing ';' for the debug diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am index ab55cebd1e..741c7319dc 100644 --- a/cpukit/Makefile.am +++ b/cpukit/Makefile.am @@ -124,7 +124,8 @@ include_rtems_HEADERS += libblock/include/rtems/bdbuf.h \ libblock/include/rtems/flashdisk.h libblock/include/rtems/ramdisk.h \ libblock/include/rtems/nvdisk.h libblock/include/rtems/nvdisk-sram.h \ libblock/include/rtems/ide_part_table.h \ - libblock/include/rtems/bdpart.h + libblock/include/rtems/bdpart.h \ + libblock/include/rtems/media.h ## ftpd if LIBNETWORKING 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; +} diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am index b430f793c2..2d33da3bf6 100644 --- a/cpukit/preinstall.am +++ b/cpukit/preinstall.am @@ -289,6 +289,10 @@ $(PROJECT_INCLUDE)/rtems/bdpart.h: libblock/include/rtems/bdpart.h $(PROJECT_INC $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bdpart.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bdpart.h +$(PROJECT_INCLUDE)/rtems/media.h: libblock/include/rtems/media.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/media.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/media.h + if LIBNETWORKING $(PROJECT_INCLUDE)/rtems/ftpd.h: ftpd/ftpd.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/ftpd.h |