diff options
Diffstat (limited to 'cpukit/libblock/include')
-rw-r--r-- | cpukit/libblock/include/rtems/bdbuf.h | 594 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/bdpart.h | 409 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/blkdev.h | 276 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/diskdevs.h | 341 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/flashdisk.h | 366 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/ide_part_table.h | 217 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/media.h | 521 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/nvdisk-sram.h | 25 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/nvdisk.h | 209 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/ramdisk.h | 243 |
10 files changed, 3201 insertions, 0 deletions
diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h new file mode 100644 index 0000000000..66a9bbf59b --- /dev/null +++ b/cpukit/libblock/include/rtems/bdbuf.h @@ -0,0 +1,594 @@ +/** + * @file + * + * @ingroup rtems_bdbuf + * + * Block device buffer management. + */ + +/* + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Victor V. Vengerov <vvv@oktet.ru> + * + * Copyright (C) 2008,2009 Chris Johns <chrisj@rtems.org> + * Rewritten to remove score mutex access. Fixes many performance + * issues. + * Change to support demand driven variable buffer sizes. + * + * Copyright (c) 2009 embedded brains GmbH. + * + * @(#) bdbuf.h,v 1.9 2005/02/02 00:06:18 joel Exp + */ + +#ifndef _RTEMS_BDBUF_H +#define _RTEMS_BDBUF_H + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/chain.h> + +#include <rtems/blkdev.h> +#include <rtems/diskdevs.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup rtems_libblock Block Device Library + * + * Block device modules. + */ + +/** + * @defgroup rtems_bdbuf Block Device Buffer Management + * + * @ingroup rtems_libblock + * + * The Block Device Buffer Management implements a cache between the disk + * devices and file systems. The code provides read ahead and write queuing to + * the drivers and fast cache look-up using an AVL tree. + * + * The block size used by a file system can be set at runtime and must be a + * multiple of the disk device block size. The disk device's physical block + * size is called the media block size. The file system can set the block size + * it uses to a larger multiple of the media block size. The driver must be + * able to handle buffers sizes larger than one media block. + * + * The user configures the amount of memory to be used as buffers in the cache, + * and the minimum and maximum buffer size. The cache will allocate additional + * memory for the buffer descriptors and groups. There are enough buffer + * descriptors allocated so all the buffer memory can be used as minimum sized + * buffers. + * + * The cache is a single pool of buffers. The buffer memory is divided into + * groups where the size of buffer memory allocated to a group is the maximum + * buffer size. A group's memory can be divided down into small buffer sizes + * that are a multiple of 2 of the minimum buffer size. A group is the minimum + * allocation unit for buffers of a specific size. If a buffer of maximum size + * is request the group will have a single buffer. If a buffer of minimum size + * is requested the group is divided into minimum sized buffers and the + * remaining buffers are held ready for use. A group keeps track of which + * buffers are with a file system or driver and groups who have buffer in use + * cannot be realloced. Groups with no buffers in use can be taken and + * realloced to a new size. This is how buffers of different sizes move around + * the cache. + + * The buffers are held in various lists in the cache. All buffers follow this + * state machine: + * + * @dot + * digraph state { + * size="16,8"; + * f [label="FREE",style="filled",fillcolor="aquamarine"]; + * e [label="EMPTY",style="filled",fillcolor="seagreen"]; + * c [label="CACHED",style="filled",fillcolor="chartreuse"]; + * ac [label="ACCESS CACHED",style="filled",fillcolor="royalblue"]; + * am [label="ACCESS MODIFIED",style="filled",fillcolor="royalblue"]; + * ae [label="ACCESS EMPTY",style="filled",fillcolor="royalblue"]; + * ap [label="ACCESS PURGED",style="filled",fillcolor="royalblue"]; + * t [label="TRANSFER",style="filled",fillcolor="red"]; + * tp [label="TRANSFER PURGED",style="filled",fillcolor="red"]; + * s [label="SYNC",style="filled",fillcolor="red"]; + * m [label="MODIFIED",style="filled",fillcolor="gold"]; + * i [label="INITIAL"]; + * + * legend_transfer [label="Transfer Wake-Up",fontcolor="red",shape="none"]; + * legend_access [label="Access Wake-Up",fontcolor="royalblue",shape="none"]; + * + * i -> f [label="Init"]; + * f -> e [label="Buffer Recycle"]; + * e -> ae [label="Get"]; + * e -> t [label="Read"]; + * e -> f [label="Nobody Waits"]; + * c -> ac [label="Get\nRead"]; + * c -> e [label="Buffer Recycle\nPurge"]; + * c -> f [label="Reallocate\nBlock Size Changed"]; + * t -> c [label="Transfer Done",color="red",fontcolor="red"]; + * t -> e [label="Transfer Error",color="red",fontcolor="red"]; + * t -> tp [label="Purge"]; + * tp -> e [label="Transfer Done\nTransfer Error",color="red",fontcolor="red"]; + * m -> t [label="Swapout"]; + * m -> s [label="Block Size Changed"]; + * m -> am [label="Get\nRead"]; + * m -> e [label="Purge"]; + * ac -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"]; + * ac -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; + * ac -> c [label="Release",color="royalblue",fontcolor="royalblue"]; + * ac -> ap [label="Purge"]; + * am -> m [label="Release\nRelease Modified",color="royalblue",fontcolor="royalblue"]; + * am -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; + * am -> ap [label="Purge"]; + * ae -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"]; + * ae -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; + * ae -> e [label="Release",color="royalblue",fontcolor="royalblue"]; + * ae -> ap [label="Purge"]; + * ap -> e [label="Release\nRelease Modified\nSync",color="royalblue",fontcolor="royalblue"]; + * s -> t [label="Swapout"]; + * s -> e [label="Purge",color="red",fontcolor="red"]; + * } + * @enddot + * + * Empty or cached buffers are added to the LRU list and removed from this + * queue when a caller requests a buffer. This is referred to as getting a + * buffer in the code and the event get in the state diagram. The buffer is + * assigned to a block and inserted to the AVL based on the block/device key. + * If the block is to be read by the user and not in the cache it is transfered + * from the disk into memory. If no buffers are on the LRU list the modified + * list is checked. If buffers are on the modified the swap out task will be + * woken. The request blocks until a buffer is available for recycle. + * + * A block being accessed is given to the file system layer and not accessible + * to another requester until released back to the cache. The same goes to a + * buffer in the transfer state. The transfer state means being read or + * written. If the file system has modifed the block and releases it as + * modified it placed on the cache's modified list and a hold timer + * initialised. The buffer is held for the hold time before being written to + * disk. Buffers are held for a configurable period of time on the modified + * list as a write sets the state to transfer and this locks the buffer out + * from the file system until the write completes. Buffers are often accessed + * and modified in a series of small updates so if sent to the disk when + * released as modified the user would have to block waiting until it had been + * written. This would be a performance problem. + * + * The code performs multiple block reads and writes. Multiple block reads or + * read ahead increases performance with hardware that supports it. It also + * helps with a large cache as the disk head movement is reduced. It however + * is a speculative operation so excessive use can remove valuable and needed + * blocks from the cache. + * + * The cache has the following lists of buffers: + * - LRU: Accessed or transfered buffers released in least recently used + * order. Empty buffers will be placed to the front. + * - Modified: Buffers waiting to be written to disk. + * - Sync: Buffers to be synchronized with the disk. + * + * A cache look-up will be performed to find a suitable buffer. A suitable + * buffer is one that matches the same allocation size as the device the buffer + * is for. The a buffer's group has no buffers in use with the file system or + * driver the group is reallocated. This means the buffers in the group are + * invalidated, resized and placed on the LRU queue. There is a performance + * issue with this design. The reallocation of a group may forced recently + * accessed buffers out of the cache when they should not. The design should be + * change to have groups on a LRU list if they have no buffers in use. + * + * @{ + */ + +/** + * @brief State of a buffer of the cache. + * + * The state has several implications. Depending on the state a buffer can be + * in the AVL tree, in a list, in use by an entity and a group user or not. + * + * <table> + * <tr> + * <th>State</th><th>Valid Data</th><th>AVL Tree</th> + * <th>LRU List</th><th>Modified List</th><th>Synchronization List</th> + * <th>Group User</th><th>External User</th> + * </tr> + * <tr> + * <td>FREE</td><td></td><td></td> + * <td>X</td><td></td><td></td><td></td><td></td> + * </tr> + * <tr> + * <td>EMPTY</td><td></td><td>X</td> + * <td></td><td></td><td></td><td></td><td></td> + * </tr> + * <tr> + * <td>CACHED</td><td>X</td><td>X</td> + * <td>X</td><td></td><td></td><td></td><td></td> + * </tr> + * <tr> + * <td>ACCESS CACHED</td><td>X</td><td>X</td> + * <td></td><td></td><td></td><td>X</td><td>X</td> + * </tr> + * <tr> + * <td>ACCESS MODIFIED</td><td>X</td><td>X</td> + * <td></td><td></td><td></td><td>X</td><td>X</td> + * </tr> + * <tr> + * <td>ACCESS EMPTY</td><td></td><td>X</td> + * <td></td><td></td><td></td><td>X</td><td>X</td> + * </tr> + * <tr> + * <td>ACCESS PURGED</td><td></td><td>X</td> + * <td></td><td></td><td></td><td>X</td><td>X</td> + * </tr> + * <tr> + * <td>MODIFIED</td><td>X</td><td>X</td> + * <td></td><td>X</td><td></td><td>X</td><td></td> + * </tr> + * <tr> + * <td>SYNC</td><td>X</td><td>X</td> + * <td></td><td></td><td>X</td><td>X</td><td></td> + * </tr> + * <tr> + * <td>TRANSFER</td><td>X</td><td>X</td> + * <td></td><td></td><td></td><td>X</td><td>X</td> + * </tr> + * <tr> + * <td>TRANSFER PURGED</td><td></td><td>X</td> + * <td></td><td></td><td></td><td>X</td><td>X</td> + * </tr> + * </table> + */ +typedef enum +{ + /** + * @brief Free. + */ + RTEMS_BDBUF_STATE_FREE = 0, + + /** + * @brief Empty. + */ + RTEMS_BDBUF_STATE_EMPTY, + + /** + * @brief Cached. + */ + RTEMS_BDBUF_STATE_CACHED, + + /** + * @brief Accessed by upper layer with cached data. + */ + RTEMS_BDBUF_STATE_ACCESS_CACHED, + + /** + * @brief Accessed by upper layer with modified data. + */ + RTEMS_BDBUF_STATE_ACCESS_MODIFIED, + + /** + * @brief Accessed by upper layer with invalid data. + */ + RTEMS_BDBUF_STATE_ACCESS_EMPTY, + + /** + * @brief Accessed by upper layer with purged data. + */ + RTEMS_BDBUF_STATE_ACCESS_PURGED, + + /** + * @brief Modified by upper layer. + */ + RTEMS_BDBUF_STATE_MODIFIED, + + /** + * @brief Scheduled for synchronization. + */ + RTEMS_BDBUF_STATE_SYNC, + + /** + * @brief In transfer by block device driver. + */ + RTEMS_BDBUF_STATE_TRANSFER, + + /** + * @brief In transfer by block device driver and purged. + */ + RTEMS_BDBUF_STATE_TRANSFER_PURGED +} rtems_bdbuf_buf_state; + +/** + * Forward reference to the block. + */ +struct rtems_bdbuf_group; +typedef struct rtems_bdbuf_group rtems_bdbuf_group; + +/** + * To manage buffers we using buffer descriptors (BD). A BD holds a buffer plus + * a range of other information related to managing the buffer in the cache. To + * speed-up buffer lookup descriptors are organized in AVL-Tree. The fields + * 'dev' and 'block' are search keys. + */ +typedef struct rtems_bdbuf_buffer +{ + rtems_chain_node link; /**< Link the BD onto a number of lists. */ + + struct rtems_bdbuf_avl_node + { + struct rtems_bdbuf_buffer* left; /**< Left Child */ + struct rtems_bdbuf_buffer* right; /**< Right Child */ + signed char cache; /**< Cache */ + signed char bal; /**< The balance of the sub-tree */ + } avl; + + dev_t dev; /**< device number */ + + rtems_blkdev_bnum block; /**< block number on the device */ + + unsigned char* buffer; /**< Pointer to the buffer memory area */ + + volatile rtems_bdbuf_buf_state state; /**< State of the buffer. */ + + volatile uint32_t waiters; /**< The number of threads waiting on this + * buffer. */ + rtems_bdbuf_group* group; /**< Pointer to the group of BDs this BD is + * part of. */ + volatile uint32_t hold_timer; /**< Timer to indicate how long a buffer + * has been held in the cache modified. */ + + int references; /**< Allow reference counting by owner. */ + void* user; /**< User data. */ +} rtems_bdbuf_buffer; + +/** + * A group is a continuous block of buffer descriptors. A group covers the + * maximum configured buffer size and is the allocation size for the buffers to + * a specific buffer size. If you allocate a buffer to be a specific size, all + * buffers in the group, if there are more than 1 will also be that size. The + * number of buffers in a group is a multiple of 2, ie 1, 2, 4, 8, etc. + */ +struct rtems_bdbuf_group +{ + rtems_chain_node link; /**< Link the groups on a LRU list if they + * have no buffers in use. */ + size_t bds_per_group; /**< The number of BD allocated to this + * group. This value must be a multiple of + * 2. */ + uint32_t users; /**< How many users the block has. */ + rtems_bdbuf_buffer* bdbuf; /**< First BD this block covers. */ +}; + +/** + * Buffering configuration definition. See confdefs.h for support on using this + * structure. + */ +typedef struct rtems_bdbuf_config { + uint32_t max_read_ahead_blocks; /**< Number of blocks to read + * ahead. */ + uint32_t max_write_blocks; /**< Number of blocks to write + * at once. */ + rtems_task_priority swapout_priority; /**< Priority of the swap out + * task. */ + uint32_t swapout_period; /**< Period swapout checks buf + * timers. */ + uint32_t swap_block_hold; /**< Period a buffer is held. */ + size_t swapout_workers; /**< The number of worker + * threads for the swapout + * task. */ + rtems_task_priority swapout_worker_priority; /**< Priority of the swap out + * task. */ + size_t size; /**< Size of memory in the + * cache */ + uint32_t buffer_min; /**< Minimum buffer size. */ + uint32_t buffer_max; /**< Maximum buffer size + * supported. It is also the + * allocation size. */ +} rtems_bdbuf_config; + +/** + * External reference to the configuration. + * + * The configuration is provided by the application. + */ +extern const rtems_bdbuf_config rtems_bdbuf_configuration; + +/** + * The max_read_ahead_blocks value is altered if there are fewer buffers + * than this defined max. This stops thrashing in the cache. + */ +#define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT 0 + +/** + * Default maximum number of blocks to write at once. + */ +#define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT 16 + +/** + * Default swap-out task priority. + */ +#define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT 15 + +/** + * Default swap-out task swap period in milli seconds. + */ +#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250 + +/** + * Default swap-out task block hold time in milli seconds. + */ +#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000 + +/** + * Default swap-out worker tasks. Currently disabled. + */ +#define RTEMS_BDBUF_SWAPOUT_WORKER_TASKS_DEFAULT 0 + +/** + * Default swap-out worker task priority. The same as the swapout task. + */ +#define RTEMS_BDBUF_SWAPOUT_WORKER_TASK_PRIORITY_DEFAULT \ + RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT + +/** + * Default size of memory allocated to the cache. + */ +#define RTEMS_BDBUF_CACHE_MEMORY_SIZE_DEFAULT (64 * 512) + +/** + * Default minimum size of buffers. + */ +#define RTEMS_BDBUF_BUFFER_MIN_SIZE_DEFAULT (512) + +/** + * Default maximum size of buffers. + */ +#define RTEMS_BDBUF_BUFFER_MAX_SIZE_DEFAULT (4096) + +/** + * Prepare buffering layer to work - initialize buffer descritors and (if it is + * neccessary) buffers. After initialization all blocks is placed into the + * ready state. + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_init (void); + +/** + * Get block buffer for data to be written into. The buffers is set to the + * access or modifed access state. If the buffer is in the cache and modified + * the state is access modified else the state is access. This buffer contents + * are not initialised if the buffer is not already in the cache. If the block + * is already resident in memory it is returned how-ever if not in memory the + * buffer is not read from disk. This call is used when writing the whole block + * on a disk rather than just changing a part of it. If there is no buffers + * available this call will block. A buffer obtained with this call will not be + * involved in a transfer request and will not be returned to another user + * until released. If the buffer is already with a user when this call is made + * the call is blocked until the buffer is returned. The highest priority + * waiter will obtain the buffer first. + * + * The block number is the linear block number. This is relative to the start + * of the partition on the media. + * + * @param device Device number (constructed of major and minor device number) + * @param block Linear media block number + * @param bd Reference to the buffer descriptor pointer. + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_get (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); + +/** + * Get the block buffer and if not already in the cache read from the disk. If + * specified block already cached return. The buffer is set to the access or + * modifed access state. If the buffer is in the cache and modified the state + * is access modified else the state is access. If block is already being read + * from disk for being written to disk this call blocks. If the buffer is + * waiting to be written it is removed from modified queue and returned to the + * user. If the buffer is not in the cache a new buffer is obtained and the + * data read from disk. The call may block until these operations complete. A + * buffer obtained with this call will not be involved in a transfer request + * and will not be returned to another user until released. If the buffer is + * already with a user when this call is made the call is blocked until the + * buffer is returned. The highest priority waiter will obtain the buffer + * first. + * + * @param device Device number (constructed of major and minor device number) + * @param block Linear media block number + * @param bd Reference to the buffer descriptor pointer. + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_read (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); + +/** + * Release the buffer obtained by a read call back to the cache. If the buffer + * was obtained by a get call and was not already in the cache the release + * modified call should be used. A buffer released with this call obtained by a + * get call may not be in sync with the contents on disk. If the buffer was in + * the cache and modified before this call it will be returned to the modified + * queue. The buffers is returned to the end of the LRU list. + * + * @param bd Reference to the buffer descriptor. + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_release (rtems_bdbuf_buffer* bd); + +/** + * Release the buffer allocated with a get or read call placing it on the + * modidied list. If the buffer was not released modified before the hold + * timer is set to the configuration value. If the buffer had been released + * modified before but not written to disk the hold timer is not updated. The + * buffer will be written to disk when the hold timer has expired, there are + * not more buffers available in the cache and a get or read buffer needs one + * or a sync call has been made. If the buffer is obtained with a get or read + * before the hold timer has expired the buffer will be returned to the user. + * + * @param bd Reference to the buffer descriptor. + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd); + +/** + * Release the buffer as modified and wait until it has been synchronized with + * the disk by writing it. This buffer will be the first to be transfer to disk + * and other buffers may also be written if the maximum number of blocks in a + * requests allows it. + * + * @note This code does not lock the sync mutex and stop additions to the + * modified queue. + + * @param bd Reference to the buffer descriptor. + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_sync (rtems_bdbuf_buffer* bd); + +/** + * Synchronize all modified buffers for this device with the disk and wait + * until the transfers have completed. The sync mutex for the cache is locked + * stopping the addition of any further modifed buffers. It is only the + * currently modified buffers that are written. + * + * @note Nesting calls to sync multiple devices will be handled sequentially. A + * nested call will be blocked until the first sync request has complete. + * + * @param dev Block device number + * + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed + * successfully or error code if error is occured) + */ +rtems_status_code +rtems_bdbuf_syncdev (dev_t dev); + +/** + * @brief Purges all buffers that matches the device identifier @a dev. + * + * This may result in loss of data. + */ +void +rtems_bdbuf_purge_dev (dev_t dev); + +/** + * @brief Purges all buffers that matches the device major number @a major. + * + * This may result in loss of data. + */ +void +rtems_bdbuf_purge_major (rtems_device_major_number major); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libblock/include/rtems/bdpart.h b/cpukit/libblock/include/rtems/bdpart.h new file mode 100644 index 0000000000..907866eb43 --- /dev/null +++ b/cpukit/libblock/include/rtems/bdpart.h @@ -0,0 +1,409 @@ +/** + * @file + * + * @ingroup rtems_bdpart + * + * Block device partition management. + */ + +/* + * Copyright (c) 2009, 2010 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-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_BDPART_H +#define RTEMS_BDPART_H + +#include <uuid/uuid.h> + +#include <rtems.h> +#include <rtems/blkdev.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup rtems_bdpart Block Device Partition Management + * + * @ingroup rtems_libblock + * + * This module provides functions to manage partitions of a disk device. + * + * A @ref rtems_disk "disk" is a set of blocks which are identified by a + * consecutive set of non-negative integers starting at zero. There are also + * logical disks which contain a subset of consecutive disk blocks. The + * logical disks are used to represent the partitions of a disk. The disk + * devices are accessed via the @ref rtems_disk "block device buffer module". + * + * The partition format on the physical disk will be converted to an internal + * representation. It is possible to convert the internal representation into + * a specific output format and write it to the physical disk. One of the + * constrains for the internal representation was to support the GPT format + * easily. + * + * Currently two physical partition formats are supported. These are the MBR + * and the GPT format. Please note that the GPT support is not implemented. + * With MBR format we mean the partition format of the wide spread IBM + * PC-compatible systems. The GPT format is defined in the Extensible Firmware + * Interface (EFI). + * + * The most common task will be to read the partition information of a disk and + * register logical disks for each partition. This can be done with the + * rtems_bdpart_register_from_disk() function. Afterwards you can + * @ref rtems_fsmount "mount" the file systems within the partitions. + * + * You can read the partition information from a disk with rtems_bdpart_read() + * and write it to the disk with rtems_bdpart_write(). + * + * To create a partition table from scratch for a disk use + * rtems_bdpart_create(). + * + * You can access some disk functions with the shell command @c fdisk. + * + * References used to create this module: + * - <a href="http://en.wikipedia.org/wiki/UUID">Universally Unique Identifier</a> + * - <a href="http://en.wikipedia.org/wiki/Globally_Unique_Identifier">Globally Unique Identifier</a> + * - <a href="http://en.wikipedia.org/wiki/Disk_partitioning">Disk Paritioning</a> + * - <a href="http://en.wikipedia.org/wiki/GUID_Partition_Table">GUID Partition Table</a> + * - <a href="http://en.wikipedia.org/wiki/Master_boot_record">Master Boot Record</a> + * - <a href="http://en.wikipedia.org/wiki/Extended_boot_record">Extended Boot Record</a> + * - <a href="http://en.wikipedia.org/wiki/Cylinder-head-sector">Cylinder Head Sector</a> + * - <a href="http://www.win.tue.nl/~aeb/partitions/partition_types-1.html">Partition Types</a> + * + * @{ + */ + +/** + * @name MBR Partition Types and Flags + * + * @{ + */ + +#define RTEMS_BDPART_MBR_EMPTY 0x0U + +#define RTEMS_BDPART_MBR_FAT_12 0x1U + +#define RTEMS_BDPART_MBR_FAT_16 0x4U + +#define RTEMS_BDPART_MBR_FAT_16_LBA 0xeU + +#define RTEMS_BDPART_MBR_FAT_32 0xbU + +#define RTEMS_BDPART_MBR_FAT_32_LBA 0xcU + +#define RTEMS_BDPART_MBR_EXTENDED 0x5U + +#define RTEMS_BDPART_MBR_DATA 0xdaU + +#define RTEMS_BDPART_MBR_GPT 0xeeU + +#define RTEMS_BDPART_MBR_FLAG_ACTIVE 0x80U + +/** @} */ + +/** + * Recommended maximum partition table size. + */ +#define RTEMS_BDPART_PARTITION_NUMBER_HINT 16 + +/** + * Partition description. + */ +typedef struct rtems_bdpart_partition { + /** + * Block index for partition begin. + */ + rtems_blkdev_bnum begin; + + /** + * Block index for partition end (this block is not a part of the partition). + */ + rtems_blkdev_bnum end; + + /** + * Partition type. + */ + uuid_t type; + + /** + * Partition ID. + */ + uuid_t id; + + /** + * Partition flags. + */ + uint64_t flags; +} rtems_bdpart_partition; + +/** + * Disk format for the partition tables. + */ +typedef enum { + /** + * Type value for MBR format. + */ + RTEMS_BDPART_FORMAT_MBR, + + /** + * Type value for GPT format. + */ + RTEMS_BDPART_FORMAT_GPT +} rtems_bdpart_format_type; + +/** + * Disk format description. + */ +typedef union { + /** + * Format type. + */ + rtems_bdpart_format_type type; + + /** + * MBR format fields. + */ + struct { + rtems_bdpart_format_type type; + + /** + * Disk ID in MBR at offset 440. + */ + uint32_t disk_id; + + /** + * This option is used for partition table creation and validation checks + * before a write to the disk. It ensures that the first primary + * partition and the logical partitions start at head one and sector one + * under the virtual one head and 63 sectors geometry. Each begin and + * end of a partition will be aligned to the virtual cylinder boundary. + */ + bool dos_compatibility; + } mbr; + + /** + * GPT format fields. + */ + struct { + rtems_bdpart_format_type type; + + /** + * Disk ID in GPT header. + */ + uuid_t disk_id; + } gpt; +} rtems_bdpart_format; + +/** + * Reads the partition information from the physical disk device with name + * @a disk_name. + * + * The partition information will be stored in the partition table + * @a partitions with a maximum of @a count partitions. The number of actual + * partitions will be stored in @a count. If there are more partitions than + * space for storage an error status will be returned. The partition table + * format recognized on the disk will be stored in @a format. + */ +rtems_status_code rtems_bdpart_read( + const char *disk_name, + rtems_bdpart_format *format, + rtems_bdpart_partition *partitions, + size_t *count +); + +/** + * Sorts the partition table @a partitions with @a count partitions to have + * ascending begin blocks + */ +void rtems_bdpart_sort( rtems_bdpart_partition *partitions, size_t count); + +/** + * Writes the partition table to the physical disk device with name + * @a disk_name. + * + * The partition table @a partitions with @a count partitions will be written + * to the disk. The output format for the partition table on the disk is + * specified by @a format. There are some consistency checks applied to the + * partition table. The partition table must be sorted such that the begin + * blocks are in ascending order. This can be done with the + * rtems_bdpart_sort() function. The partitions must not overlap. The + * partitions must have a positive size. The partitions must be within the + * disk. Depending on the output format there are additional constrains. + */ +rtems_status_code rtems_bdpart_write( + const char *disk_name, + const rtems_bdpart_format *format, + const rtems_bdpart_partition *partitions, + size_t count +); + +/** + * Creates a partition table in @a partitions with @a count partitions for the + * physical disk device with name @a disk_name. + * + * The array of positive integer weights in @a distribution must have exactly + * @a count elements. The weights in the distribution array are summed up. + * Each weight is then divided by the sum to obtain the disk fraction which + * forms the corresponding partition. The partition boundaries are generated + * with respect to the output format in @a format. + */ +rtems_status_code rtems_bdpart_create( + const char *disk_name, + const rtems_bdpart_format *format, + rtems_bdpart_partition *partitions, + const unsigned *distribution, + size_t count +); + +/** + * Registers the partitions as logical disks for the physical disk device with + * name @a disk_name. + * + * For each partition of the partition table @a partitions with @a count + * partitions a logical disk is registered. The partition number equals the + * partition table index plus one. The name of the logical disk device is the + * concatenation of the physical disk device name and the partition number. + */ +rtems_status_code rtems_bdpart_register( + const char *disk_name, + const rtems_bdpart_partition *partitions, + size_t count +); + +/** + * Reads the partition table from the disk device with name @a disk_name and + * registers the partitions as logical disks. + * + * @see rtems_bdpart_register() and rtems_fsmount(). + */ +rtems_status_code rtems_bdpart_register_from_disk( const char *disk_name); + +/** + * Deletes the logical disks associated with the partitions of the disk device + * with name @a disk_name. + * + * The partition table @a partitions with @a count partitions will be used to + * determine which disks need to be deleted. It may be obtained from + * rtems_bdpart_read(). + */ +rtems_status_code rtems_bdpart_unregister( + const char *disk_name, + const rtems_bdpart_partition *partitions, + size_t count +); + +/** + * Mounts all supported file systems inside the logical disks derived from the + * partitions of the physical disk device with name @a disk_name. + * + * For each partition in the partition table @a partitions with @a count + * partitions it will be checked if it contains a supported file system. In + * this case a mount point derived from the disk name will be created in the + * mount base path @a mount_base. The file system will be mounted there. The + * partition number equals the partition table index plus one. The mount point + * name for each partition will be the concatenation of the mount base path, + * the disk device file name and the parition number. + * + * @see rtems_bdpart_read(). + */ +rtems_status_code rtems_bdpart_mount( + const char *disk_name, + const rtems_bdpart_partition *partitions, + size_t count, + const char *mount_base +); + +/** + * Unmounts all file systems mounted with rtems_bdpart_mount(). + */ +rtems_status_code rtems_bdpart_unmount( + const char *disk_name, + const rtems_bdpart_partition *partitions, + size_t count, + const char *mount_base +); + +/** + * Prints the partition table @a partitions with @a count partitions to + * standard output. + */ +void rtems_bdpart_dump( const rtems_bdpart_partition *partitions, size_t count); + +/** + * Returns the partition type for the MBR partition type value @a mbr_type in + * @a type. + */ +void rtems_bdpart_to_partition_type( uint8_t mbr_type, uuid_t type); + +/** + * Converts the partition type in @a type to the MBR partition type. + * + * The result will be stored in @a mbr_type. Returns @c true in case of a + * successful convertion and otherwise @c false. Both arguments must not be + * @c NULL. + */ +bool rtems_bdpart_to_mbr_partition_type( + const uuid_t type, + uint8_t *mbr_type +); + +/** @} */ + +#define RTEMS_BDPART_MBR_CYLINDER_SIZE 63 + +#define RTEMS_BDPART_NUMBER_SIZE 4 + +#define RTEMS_BDPART_BLOCK_SIZE 512 + +#define RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE 16 + +#define RTEMS_BDPART_MBR_OFFSET_TABLE_0 446 + +#define RTEMS_BDPART_MBR_OFFSET_TABLE_1 \ + (RTEMS_BDPART_MBR_OFFSET_TABLE_0 + RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE) + +#define RTEMS_BDPART_MBR_OFFSET_DISK_ID 440 + +#define RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0 510 + +#define RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1 511 + +#define RTEMS_BDPART_MBR_SIGNATURE_0 0x55U + +#define RTEMS_BDPART_MBR_SIGNATURE_1 0xaaU + +#define RTEMS_BDPART_MBR_OFFSET_BEGIN 8 + +#define RTEMS_BDPART_MBR_OFFSET_SIZE 12 + +#define RTEMS_BDPART_MBR_OFFSET_TYPE 4 + +#define RTEMS_BDPART_MBR_OFFSET_FLAGS 0 + +static inline uint8_t rtems_bdpart_mbr_partition_type( + const uuid_t type +) +{ + return type [0]; +} + +rtems_status_code rtems_bdpart_get_disk_data( + const char *disk_name, + dev_t *disk, + rtems_blkdev_bnum *disk_end +); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* RTEMS_BDPART_H */ diff --git a/cpukit/libblock/include/rtems/blkdev.h b/cpukit/libblock/include/rtems/blkdev.h new file mode 100644 index 0000000000..e9fa86b248 --- /dev/null +++ b/cpukit/libblock/include/rtems/blkdev.h @@ -0,0 +1,276 @@ +/** + * @file + * + * @ingroup rtems_blkdev + * + * Block device management. + */ + +/* + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Victor V. Vengerov <vvv@oktet.ru> + * + * @(#) $Id$ + */ + +#ifndef _RTEMS_BLKDEV_H +#define _RTEMS_BLKDEV_H + +#include <rtems.h> +#include <rtems/diskdevs.h> +#include <sys/ioctl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup rtems_blkdev Block Device Management + * + * @ingroup rtems_libblock + * + * Interface between device drivers and the + * @ref rtems_bdbuf "block device buffer module". + * + * The heart of the block device driver is the @ref RTEMS_BLKIO_REQUEST IO + * control. This call puts IO @ref rtems_blkdev_request "requests" to the block + * device for asynchronous processing. When a driver executes a request, it + * invokes the request done callback function to finish the request. + * + * @{ + */ + +/** + * Block device request type. + * + * @warning The sync request is an IO one and only used from the cache. Use the + * Block IO when operating at the device level. We need a sync request + * to avoid requests looping for ever. + */ +typedef enum rtems_blkdev_request_op { + RTEMS_BLKDEV_REQ_READ, /**< Read the requested blocks of data. */ + RTEMS_BLKDEV_REQ_WRITE, /**< Write the requested blocks of data. */ + RTEMS_BLKDEV_REQ_SYNC /**< Sync any data with the media. */ +} rtems_blkdev_request_op; + +/** + * @brief Block device request done callback function type. + * + * The first parameter @a arg must be the argument provided by the block device + * request structure @ref rtems_blkdev_request. + * + * The second parameter @a status should contain the status of the operation: + * - @c RTEMS_SUCCESSFUL Operation was successful. + * - @c RTEMS_IO_ERROR Some sort of input or output error. + * - @c RTEMS_UNSATISFIED Media no more present. + */ +typedef void (*rtems_blkdev_request_cb)(void *arg, rtems_status_code status); + +/** + * Block device scatter or gather buffer structure. + */ +typedef struct rtems_blkdev_sg_buffer { + /** + * Block index. + */ + rtems_blkdev_bnum block; + + /** + * Buffer length. + */ + uint32_t length; + + /** + * Buffer pointer. + */ + void *buffer; + + /** + * User pointer. + */ + void *user; +} rtems_blkdev_sg_buffer; + +/** + * The block device request structure is used to read or write a number of + * blocks from or to the device. + * + * TODO: The use of these req blocks is not a great design. The req is a + * struct with a single 'bufs' declared in the req struct and the + * others are added in the outer level struct. This relies on the + * structs joining as a single array and that assumes the compiler + * packs the structs. Why not just place on a list ? The BD has a + * node that can be used. + */ +typedef struct rtems_blkdev_request { + /** + * Block device operation (read or write). + */ + rtems_blkdev_request_op req; + + /** + * Request done callback function. + */ + rtems_blkdev_request_cb req_done; + + /** + * Argument to be passed to callback function. + */ + void *done_arg; + + /** + * Last IO operation completion status. + */ + rtems_status_code status; + + /** + * Number of blocks for this request. + */ + uint32_t bufnum; + + /** + * The task requesting the IO operation. + */ + rtems_id io_task; + + /** + * List of scatter or gather buffers. + */ + rtems_blkdev_sg_buffer bufs[0]; +} rtems_blkdev_request; + +/** + * The start block in a request. + * + * Only valid if the driver has returned the @ref RTEMS_BLKIO_CAPABILITIES of + * @ref RTEMS_BLKDEV_CAP_MULTISECTOR_CONT. + */ +#define RTEMS_BLKDEV_START_BLOCK(req) (req->bufs[0].block) + +/** + * @name IO Control Request Codes + * + * @{ + */ + +#define RTEMS_BLKIO_REQUEST _IOWR('B', 1, rtems_blkdev_request) +#define RTEMS_BLKIO_GETMEDIABLKSIZE _IOR('B', 2, uint32_t) +#define RTEMS_BLKIO_GETBLKSIZE _IOR('B', 3, uint32_t) +#define RTEMS_BLKIO_SETBLKSIZE _IOW('B', 4, uint32_t) +#define RTEMS_BLKIO_GETSIZE _IOR('B', 5, rtems_blkdev_bnum) +#define RTEMS_BLKIO_SYNCDEV _IO('B', 6) +#define RTEMS_BLKIO_DELETED _IO('B', 7) +#define RTEMS_BLKIO_CAPABILITIES _IO('B', 8) + +/** @} */ + +/** + * Only consecutive multi-sector buffer requests are supported. + * + * This option means the cache will only supply multiple buffers that are + * inorder so the ATA multi-sector command for example can be used. This is a + * hack to work around the current ATA driver. + */ +#define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT (1 << 0) + +/** + * The driver will accept a sync call. A sync call is made to a driver + * after a bdbuf cache sync has finished. + */ +#define RTEMS_BLKDEV_CAP_SYNC (1 << 1) + +/** + * The device driver interface conventions suppose that a driver may contain an + * initialize, open, close, read, write and IO control entry points. These + * primitives (except initialize) can be implemented in a generic fashion based + * upon the supplied block device driver IO control handler. Every block device + * driver should provide an initialize entry point, which registers the + * appropriate IO control handler. + */ +#define RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \ + rtems_blkdev_generic_open, \ + rtems_blkdev_generic_close, \ + rtems_blkdev_generic_read, \ + rtems_blkdev_generic_write, \ + rtems_blkdev_generic_ioctl + +/** + * Generic block device read primitive. + * + * Implemented using block device buffer management primitives. + */ +rtems_device_driver +rtems_blkdev_generic_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +); + +/** + * Generic block device write primitive. + * + * Implemented using block device buffer management primitives. + */ +rtems_device_driver +rtems_blkdev_generic_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +); + +/** + * Generic block device open primitive. + * + * Implemented using block device buffer management primitives. + */ +rtems_device_driver +rtems_blkdev_generic_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +); + +/** + * Generic block device close primitive. + * + * Implemented using block device buffer management primitives. + */ +rtems_device_driver +rtems_blkdev_generic_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +); + +/** + * Generic block device IO control primitive. + * + * Implemented using block device buffer management primitives. + */ +rtems_device_driver +rtems_blkdev_generic_ioctl( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +); + +/** + * Common IO control primitive. + * + * Use this in all block devices to handle the common set of ioctl requests. + */ +int +rtems_blkdev_ioctl(rtems_disk_device *dd, uint32_t req, void *argp); + +/** + * @brief Generic block operations driver address table. + */ +extern const rtems_driver_address_table rtems_blkdev_generic_ops; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libblock/include/rtems/diskdevs.h b/cpukit/libblock/include/rtems/diskdevs.h new file mode 100644 index 0000000000..8884999d95 --- /dev/null +++ b/cpukit/libblock/include/rtems/diskdevs.h @@ -0,0 +1,341 @@ +/** + * @file + * + * @ingroup rtems_disk + * + * @brief Block device disk management API. + */ + +/* + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Victor V. Vengerov <vvv@oktet.ru> + * + * @(#) $Id$ + */ + +#ifndef _RTEMS_DISKDEVS_H +#define _RTEMS_DISKDEVS_H + +#include <rtems.h> +#include <rtems/libio.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rtems_disk_device rtems_disk_device; + +/** + * @defgroup rtems_disk Block Device Disk Management + * + * @ingroup rtems_libblock + * + * @brief This module provides functions to manage disk devices. + * + * A disk is a set of blocks which are identified by a consecutive set of + * non-negative integers starting at zero. There are also logical disks which + * contain a subset of consecutive disk blocks. The logical disks are used to + * represent the partitions of a disk. The disk devices are accessed via the + * @ref rtems_bdbuf "block device buffer module". + * + * @{ + */ + +/** + * @brief Block device block index type. + */ +typedef uint32_t rtems_blkdev_bnum; + +/** + * @brief Block device IO control handler type. + */ +typedef int (*rtems_block_device_ioctl)( + rtems_disk_device *dd, + uint32_t req, + void *argp +); + +/** + * @brief Description of a disk device (logical and physical disks). + * + * An array of pointer tables to rtems_disk_device structures is maintained. + * The first table will be indexed by the major number and the second table + * will be indexed by the minor number. This allows quick lookup using a data + * structure of moderated size. + */ +struct rtems_disk_device { + /** + * @brief Device identifier (concatenation of major and minor number). + */ + dev_t dev; + + /** + * @brief Physical device identifier (equals the @c dev entry if it specifies a + * physical device). + */ + rtems_disk_device *phys_dev; + + /** + * @brief Driver capabilities. + */ + uint32_t capabilities; + + /** + * @brief Disk device name. + */ + char *name; + + /** + * @brief Usage counter. + * + * Devices cannot be deleted if they are in use. + */ + unsigned uses; + + /** + * @brief Start block number. + * + * Equals zero for physical devices. It is a block offset to the related + * physical device for logical device. + */ + rtems_blkdev_bnum start; + + /** + * @brief Size of the physical or logical disk in blocks. + */ + rtems_blkdev_bnum size; + + /** + * @brief Device block size in bytes. + * + * This is the minimum transfer unit. It can be any size. + */ + uint32_t block_size; + + /** + * @brief Device media block size in bytes. + * + * This is the media transfer unit the hardware defaults to. + */ + uint32_t media_block_size; + + /** + * @brief IO control handler for this disk. + */ + rtems_block_device_ioctl ioctl; + + /** + * @brief Private data for the disk driver. + */ + void *driver_data; + + /** + * @brief Indicates that this disk should be deleted as soon as the last user + * releases this disk. + */ + bool deleted; +}; + +/** + * @name Disk Device Data + * + * @{ + */ + +static inline dev_t rtems_disk_get_device_identifier( + const rtems_disk_device *dd +) +{ + return dd->dev; +} + +static inline rtems_device_major_number rtems_disk_get_major_number( + const rtems_disk_device *dd +) +{ + return rtems_filesystem_dev_major_t(dd->dev); +} + +static inline rtems_device_minor_number rtems_disk_get_minor_number( + const rtems_disk_device *dd +) +{ + return rtems_filesystem_dev_minor_t(dd->dev); +} + +static inline void *rtems_disk_get_driver_data( + const rtems_disk_device *dd +) +{ + return dd->driver_data; +} + +static inline uint32_t rtems_disk_get_media_block_size( + const rtems_disk_device *dd +) +{ + return dd->media_block_size; +} + +/** @} */ + +/** + * @name Disk Device Maintainance + * + * @{ + */ + +/** + * @brief Creates a physical disk with device identifier @a dev. + * + * The block size @a block_size must be positive. The disk will have + * @a block_count blocks. The block index starts with zero. The associated disk + * device driver will be invoked via the IO control handler @a handler. A + * device node will be registered in the file system with absolute path @a + * name, if @a name is not @c NULL. This function is usually invoked from a + * block device driver during initialization when a physical device is detected + * in the system. The device driver provides an IO control handler to allow + * block device operations. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_NOT_CONFIGURED Cannot lock disk device operation mutex. + * @retval RTEMS_INVALID_ADDRESS IO control handler is @c NULL. + * @retval RTEMS_INVALID_NUMBER Block size is zero. + * @retval RTEMS_NO_MEMORY Not enough memory. + * @retval RTEMS_RESOURCE_IN_USE Disk device descriptor is already in use. + * @retval RTEMS_UNSATISFIED Cannot create device node. + */ +rtems_status_code rtems_disk_create_phys( + dev_t dev, + uint32_t block_size, + rtems_blkdev_bnum block_count, + rtems_block_device_ioctl handler, + void *driver_data, + const char *name +); + +/** + * @brief Creates a logical disk with device identifier @a dev. + * + * A logical disk manages a subset of consecutive blocks contained in the + * physical disk with identifier @a phys. The start block index of the logical + * disk device is @a begin_block. The block count of the logcal disk will be + * @a block_count. The blocks must be within the range of blocks managed by + * the associated physical disk device. A device node will be registered in + * the file system with absolute path @a name, if @a name is not @c NULL. The + * block size and IO control handler are inherited by the physical disk. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_NOT_CONFIGURED Cannot lock disk device operation mutex. + * @retval RTEMS_INVALID_ID Specified physical disk identifier does not + * correspond to a physical disk. + * @retval RTEMS_INVALID_NUMBER Begin block or block count are out of range. + * @retval RTEMS_NO_MEMORY Not enough memory. + * @retval RTEMS_RESOURCE_IN_USE Disk device descriptor for logical disk + * identifier is already in use. + * @retval RTEMS_UNSATISFIED Cannot create device node. + */ +rtems_status_code rtems_disk_create_log( + dev_t dev, + dev_t phys, + rtems_blkdev_bnum begin_block, + rtems_blkdev_bnum block_count, + const char *name +); + +/** + * @brief Deletes a physical or logical disk device with identifier @a dev. + * + * Marks the disk device as deleted. When a physical disk device is deleted, + * all corresponding logical disk devices will marked as deleted too. Disks + * that are marked as deleted and have a usage counter of zero will be deleted. + * The corresponding device nodes will be removed from the file system. In + * case of a physical disk deletion the IO control handler will be invoked with + * a RTEMS_BLKIO_DELETED request. Disks that are still in use will be deleted + * upon release. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_NOT_CONFIGURED Cannot lock disk device operation mutex. + * @retval RTEMS_INVALID_ID No disk for specified device identifier. + */ +rtems_status_code rtems_disk_delete(dev_t dev); + +/** + * @brief Returns the disk device descriptor for the device identifier @a dev. + * + * Increments usage counter by one. You should release the disk device + * descriptor with rtems_disk_release(). + * + * @return Pointer to the disk device descriptor or @c NULL if no corresponding + * disk exists. + */ +rtems_disk_device *rtems_disk_obtain(dev_t dev); + +/** + * @brief Releases the disk device descriptor @a dd. + * + * Decrements usage counter by one. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + */ +rtems_status_code rtems_disk_release(rtems_disk_device *dd); + +/** @} */ + +/** + * @name Disk Management + * + * @{ + */ + +/** + * @brief Initializes the disk device management. + * + * This functions returns successful if the disk device management is already + * initialized. There is no protection against concurrent access. + * + * @retval RTEMS_SUCCESSFUL Successful initialization. + * @retval RTEMS_NO_MEMORY Not enough memory or no semaphore available. + * @retval RTEMS_UNSATISFIED Block device buffer initialization failed. + */ +rtems_status_code rtems_disk_io_initialize(void); + +/** + * @brief Releases all resources allocated for disk device management. + * + * There is no protection against concurrent access. If parts of the system + * are still in use the behaviour is undefined. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + */ +rtems_status_code rtems_disk_io_done(void); + +/** @} */ + +/** @} */ + +/** + * @brief Disk device iterator. + * + * Returns the next disk device descriptor with a device identifier larger than + * @a dev. If there is no such device, @c NULL will be returned. Use minus + * one to start the search. + * + * @code + * rtems_status_code sc = RTEMS_SUCCESSFUL; + * rtems_disk_device *dd = (dev_t) -1; + * + * while (sc == RTEMS_SUCCESSFUL && (dd = rtems_disk_next(dev)) != NULL) { + * dev = rtems_disk_get_device_identifier(dd); + * sc = rtems_disk_release(dd); + * } + * @endcode + */ +rtems_disk_device *rtems_disk_next(dev_t dev); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libblock/include/rtems/flashdisk.h b/cpukit/libblock/include/rtems/flashdisk.h new file mode 100644 index 0000000000..c24b9b08be --- /dev/null +++ b/cpukit/libblock/include/rtems/flashdisk.h @@ -0,0 +1,366 @@ +/* + * flashdisk.h -- Flash disk block device implementation + * + * Copyright (C) 2007 Chris Johns + * + * 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. + * + * $Id$ + */ + +#if !defined (_RTEMS_FLASHDISK_H_) +#define _RTEMS_FLASHDISK_H_ + +#include <stdint.h> +#include <sys/ioctl.h> + +#include <rtems.h> + +/** + * The base name of the flash disks. + */ +#define RTEMS_FLASHDISK_DEVICE_BASE_NAME "/dev/fdd" + +/** + * Flash disk specific ioctl request types. To use open the + * device and issue the ioctl call. + * + * @code + * int fd = open ("/dev/flashdisk0", O_WRONLY, 0); + * if (fd < 0) + * { + * printf ("driver open failed: %s\n", strerror (errno)); + * exit (1); + * } + * if (ioctl (fd, RTEMS_FDISK_IOCTL_ERASE_DISK) < 0) + * { + * printf ("driver erase failed: %s\n", strerror (errno)); + * exit (1); + * } + * close (fd); + * @endcode + */ +#define RTEMS_FDISK_IOCTL_ERASE_DISK _IO('B', 128) +#define RTEMS_FDISK_IOCTL_COMPACT _IO('B', 129) +#define RTEMS_FDISK_IOCTL_ERASE_USED _IO('B', 130) +#define RTEMS_FDISK_IOCTL_MONITORING _IO('B', 131) +#define RTEMS_FDISK_IOCTL_INFO_LEVEL _IO('B', 132) +#define RTEMS_FDISK_IOCTL_PRINT_STATUS _IO('B', 133) + +/** + * Flash Disk Monitoring Data allows a user to obtain + * the current status of the disk. + */ +typedef struct rtems_fdisk_monitor_data +{ + uint32_t block_size; + uint32_t block_count; + uint32_t unavail_blocks; + uint32_t device_count; + uint32_t segment_count; + uint32_t page_count; + uint32_t blocks_used; + uint32_t segs_available; + uint32_t segs_used; + uint32_t segs_failed; + uint32_t seg_erases; + uint32_t pages_desc; + uint32_t pages_active; + uint32_t pages_used; + uint32_t pages_bad; + uint32_t info_level; +} rtems_fdisk_monitor_data; + +/** + * Flash Segment Descriptor holds, number of continuous segments in the + * device of this type, the base segment number in the device, the + * address offset of the base segment in the device, and the size of + * segment. + * + * Typically this structure is part of a table of segments in the + * device which is referenced in the flash disk configuration table. + * The reference is kept in the driver and used all the time to + * manage the flash device, therefore it must always exist. + */ +typedef struct rtems_fdisk_segment_desc +{ + uint16_t count; /**< Number of segments of this type in a row. */ + uint16_t segment; /**< The base segment number. */ + uint32_t offset; /**< Address offset of base segment in device. */ + uint32_t size; /**< Size of the segment in bytes. */ +} rtems_fdisk_segment_desc; + +/** + * Return the number of kilo-bytes. + */ +#define RTEMS_FDISK_KBYTES(_k) (UINT32_C(1024) * (_k)) + +/** + * Forward declaration of the device descriptor. + */ +struct rtems_fdisk_device_desc; + +/** + * Flash Low Level driver handlers. + + * Typically this structure is part of a table of handlers in the + * device which is referenced in the flash disk configuration table. + * The reference is kept in the driver and used all the time to + * manage the flash device, therefore it must always exist. + */ +typedef struct rtems_fdisk_driver_handlers +{ + /** + * Read data from the device into the buffer. Return an errno + * error number if the device cannot be read. A segment descriptor + * can describe more than one segment in a device if the device has + * repeating segments. The segment number is the device segment to + * access and the segment descriptor must reference the segment + * being requested. For example the segment number must resided in + * the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to read data from. + * @param segment The segment within the device to read. + * @param offset The offset in the segment to read. + * @param buffer The buffer to read the data into. + * @param size The amount of data to read. + * @retval 0 No error. + * @retval EIO The read did not complete. + */ + int (*read) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + void* buffer, + uint32_t size); + + /** + * Write data from the buffer to the device. Return an errno + * error number if the device cannot be written to. A segment + * descriptor can describe more than segment in a device if the + * device has repeating segments. The segment number is the device + * segment to access and the segment descriptor must reference + * the segment being requested. For example the segment number must + * resided in the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to write data from. + * @param segment The segment within the device to write to. + * @param offset The offset in the segment to write. + * @param buffer The buffer to write the data from. + * @param size The amount of data to write. + * @retval 0 No error. + * @retval EIO The write did not complete or verify. + */ + int (*write) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + const void* buffer, + uint32_t size); + + /** + * Blank a segment in the device. Return an errno error number + * if the device cannot be read or is not blank. A segment descriptor + * can describe more than segment in a device if the device has + * repeating segments. The segment number is the device segment to + * access and the segment descriptor must reference the segment + * being requested. For example the segment number must resided in + * the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to read data from. + * @param segment The segment within the device to read. + * @param offset The offset in the segment to checl. + * @param size The amount of data to check. + * @retval 0 No error. + * @retval EIO The segment is not blank. + */ + int (*blank) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + uint32_t size); + + /** + * Verify data in the buffer to the data in the device. Return an + * errno error number if the device cannot be read. A segment + * descriptor can describe more than segment in a device if the + * device has repeating segments. The segment number is the + * segment to access and the segment descriptor must reference + * the device segment being requested. For example the segment number + * must resided in the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to verify data in. + * @param segment The segment within the device to verify. + * @param offset The offset in the segment to verify. + * @param buffer The buffer to verify the data in the device with. + * @param size The amount of data to verify. + * @retval 0 No error. + * @retval EIO The data did not verify. + */ + int (*verify) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + const void* buffer, + uint32_t size); + + /** + * Erase the segment. Return an errno error number if the + * segment cannot be erased. A segment descriptor can describe + * more than segment in a device if the device has repeating + * segments. The segment number is the device segment to access and + * the segment descriptor must reference the segment being requested. + * + * @param sd The segment descriptor. + * @param device The device to erase the segment of. + * @param segment The segment within the device to erase. + * @retval 0 No error. + * @retval EIO The segment was not erased. + */ + int (*erase) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment); + + /** + * Erase the device. Return an errno error number if the + * segment cannot be erased. A segment descriptor can describe + * more than segment in a device if the device has repeating + * segments. The segment number is the segment to access and + * the segment descriptor must reference the segment being requested. + * + * @param sd The segment descriptor. + * @param device The device to erase. + * @retval 0 No error. + * @retval EIO The device was not erased. + */ + int (*erase_device) (const struct rtems_fdisk_device_desc* dd, + uint32_t device); + +} rtems_fdisk_driver_handlers; + +/** + * Flash Device Descriptor holds the segments in a device. The + * placing of the segments in a device decriptor allows the + * low level driver to share the segment descriptors for a + * number of devices. + * + * Typically this structure is part of a table of segments in the + * device which is referenced in the flash disk configuration table. + * The reference is kept in the driver and used all the time to + * manage the flash device, therefore it must always exist. + */ +typedef struct rtems_fdisk_device_desc +{ + uint32_t segment_count; /**< Number of segments. */ + const rtems_fdisk_segment_desc* segments; /**< Array of segments. */ + const rtems_fdisk_driver_handlers* flash_ops; /**< Device handlers. */ +} rtems_fdisk_device_desc; + +/** + * RTEMS Flash Disk configuration table used to initialise the + * driver. + * + * The unavailable blocks count is the number of blocks less than the + * available number of blocks the file system is given. This means there + * will always be that number of blocks available when the file system + * thinks the disk is full. The compaction code needs blocks to compact + * with so you will never be able to have all the blocks allocated to the + * file system and be able to full the disk. + * + * The compacting segment count is the number of segments that are + * moved into a new segment. A high number will mean more segments with + * low active page counts and high used page counts will be moved into + * avaliable pages how-ever this extends the compaction time due to + * time it takes the erase the pages. There is no pont making this number + * greater than the maximum number of pages in a segment. + * + * The available compacting segment count is the level when compaction occurs + * when writing. If you set this to 0 then compaction will fail because + * there will be no segments to compact into. + * + * The info level can be 0 for off with error, and abort messages allowed. + * Level 1 is warning messages, level 1 is informational messages, and level 3 + * is debugging type prints. The info level can be turned off with a compile + * time directive on the command line to the compiler of: + * + * -DRTEMS_FDISK_TRACE=0 + */ +typedef struct rtems_flashdisk_config +{ + uint32_t block_size; /**< The block size. */ + uint32_t device_count; /**< The number of devices. */ + const rtems_fdisk_device_desc* devices; /**< The device descriptions. */ + uint32_t flags; /**< Set of flags to control + driver. */ + uint32_t unavail_blocks; /**< Number of blocks not + available to the file sys. */ + uint32_t compact_segs; /**< Max number of segs to + compact in one pass. */ + uint32_t avail_compact_segs; /**< The number of segments + when compaction occurs + when writing. */ + uint32_t info_level; /**< Default info level. */ +} rtems_flashdisk_config; + +/* + * Driver flags. + */ + +/** + * Leave the erasing of used segment to the background handler. + */ +#define RTEMS_FDISK_BACKGROUND_ERASE (1 << 0) + +/** + * Leave the compacting of of used segment to the background handler. + */ +#define RTEMS_FDISK_BACKGROUND_COMPACT (1 << 1) + +/** + * Check the pages during initialisation to see which pages are + * valid and which are not. This could slow down initialising the + * disk driver. + */ +#define RTEMS_FDISK_CHECK_PAGES (1 << 2) + +/** + * Blank check the flash device before writing to them. This is needed if + * you think you have a driver or device problem. + */ +#define RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE (1 << 3) + +/** + * Flash disk device driver initialization. Place in a table as the + * initialisation entry and remainder of the entries are the + * RTEMS block device generic handlers. + * + * @param major Flash disk major device number. + * @param minor Minor device number, not applicable. + * @param arg Initialization argument, not applicable. + * @return The rtems_device_driver is actually just + * rtems_status_code. + */ +rtems_device_driver +rtems_fdisk_initialize (rtems_device_major_number major, + rtems_device_minor_number minor, + void* arg); + +/** + * External reference to the configuration. Please supply. + * Support is present in confdefs.h for providing this variable. + */ +extern const rtems_flashdisk_config rtems_flashdisk_configuration[]; + +/** + * External reference to the number of configurations. Please supply. + * Support is present in confdefs.h for providing this variable. + */ +extern uint32_t rtems_flashdisk_configuration_size; + +#endif diff --git a/cpukit/libblock/include/rtems/ide_part_table.h b/cpukit/libblock/include/rtems/ide_part_table.h new file mode 100644 index 0000000000..c6fe587e02 --- /dev/null +++ b/cpukit/libblock/include/rtems/ide_part_table.h @@ -0,0 +1,217 @@ +/** + * @file rtems/ide_part_table.h + * + * Support for "MS-DOS-style" partition tables + */ + +/* + * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia + * + * Author: Konstantin Abramenko <Konstantin.Abramenko@oktet.ru> + * Alexander Kukuta <Alexander.Kukuta@oktet.ru> + * + * 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. + * + * $Id$ + * + *****************************************************************************/ + +#ifndef _RTEMS_IDE_PART_TABLE_H +#define _RTEMS_IDE_PART_TABLE_H + +#include <rtems/chain.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <rtems.h> +#include <rtems/blkdev.h> +#include <rtems/libio.h> +#include <rtems/libio_.h> +#include <rtems/bdbuf.h> +#include <rtems/seterr.h> + +/* Minor base number for all logical devices */ +#define RTEMS_IDE_SECTOR_BITS 9 +#define RTEMS_IDE_SECTOR_SIZE 512 +#define RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE 16 +#define RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER 63 +#define RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER 4 +#define RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX 16 + +#define RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA1 0x55 +#define RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA2 0xaa +#define RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET 0x1fe +#define RTEMS_IDE_PARTITION_TABLE_OFFSET 0x1be +#define RTEMS_IDE_PARTITION_TABLE_SIZE (4 * 16) +#define RTEMS_IDE_PARTITION_BOOTABLE_OFFSET 0 +#define RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET 4 +#define RTEMS_IDE_PARTITION_START_OFFSET 8 +#define RTEMS_IDE_PARTITION_SIZE_OFFSET 12 + +/* + * Conversion from and to little-endian byte order. (no-op on i386/i486) + */ + +#if (CPU_BIG_ENDIAN == TRUE) +# define LE_TO_CPU_U16(v) CPU_swap_u16(v) +# define LE_TO_CPU_U32(v) CPU_swap_u32(v) +# define CPU_TO_LE_U16(v) CPU_swap_u16(v) +# define CPU_TO_LE_U32(v) CPU_swap_u32(v) +#else +# define LE_TO_CPU_U16(v) (v) +# define LE_TO_CPU_U32(v) (v) +# define CPU_TO_LE_U16(v) (v) +# define CPU_TO_LE_U32(v) (v) +#endif + + +/* + * sector_data_t -- + * corresponds to the sector on the device + */ +typedef struct rtems_sector_data_s +{ + uint32_t sector_num; /* sector number on the device */ + uint8_t data[0]; /* raw sector data */ +} rtems_sector_data_t; + + +/* + * Enum partition types + * see list at http://ata-atapi.com/hiwtab.htm + * + * @todo Should these have RTEMS before them. + */ +enum { + EMPTY_PARTITION = 0x00, + DOS_FAT12_PARTITION = 0x01, + DOS_FAT16_PARTITION = 0x04, + EXTENDED_PARTITION = 0x05, + DOS_P32MB_PARTITION = 0x06, + FAT32_PARTITION = 0x0B, + FAT32_LBA_PARTITION = 0x0C, + FAT16_LBA_PARTITION = 0x0E, + DM6_PARTITION = 0x54, + EZD_PARTITION = 0x55, + DM6_AUX1PARTITION = 0x51, + DM6_AUX3PARTITION = 0x53, + LINUX_SWAP = 0x82, + LINUX_NATIVE = 0x83, + LINUX_EXTENDED = 0x85 +}; + + +/* Forward declaration */ +struct rtems_disk_desc_s; + +/* + * part_desc_t -- + * contains all neccessary information about partition + */ +typedef struct rtems_part_desc_s { + uint8_t bootable; /* is the partition active */ + uint8_t sys_type; /* type of partition */ + uint8_t log_id; /* logical number of partition */ + uint32_t start; /* first partition sector, in absolute + * numeration */ + uint32_t size; /* size in sectors */ + uint32_t end; /* last partition sector, end = start + size - 1 */ + struct rtems_disk_desc_s *disk_desc; /* descriptor of disk, partition + * contains in */ + struct rtems_part_desc_s *ext_part; /* extended partition containing this + * one */ + + /* partitions, containing in this one */ + struct rtems_part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER]; +} rtems_part_desc_t; + + + +typedef struct rtems_disk_desc_s { + dev_t dev; /* device number */ + + /* device name in /dev filesystem */ + char dev_name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX]; + + uint32_t sector_size; /* size of sector */ + uint32_t sector_bits; /* the base-2 logarithm of sector_size */ + uint32_t lba_size; /* total amount of sectors in lba address mode */ + int last_log_id; /* used for logical disks enumerating */ + + /* primary partition descriptors */ + rtems_part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER]; +} rtems_disk_desc_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * rtems_ide_part_table_free -- + * frees disk descriptor structure + * + * PARAMETERS: + * disk_desc - disc descriptor structure to free + * + * RETURNS: + * N/A + */ +/** + * @deprecated Use the @ref rtems_bdpart "block device partition module" instead. + */ +void rtems_ide_part_table_free( + rtems_disk_desc_t *disk_desc +) RTEMS_COMPILER_DEPRECATED_ATTRIBUTE; + + +/* + * rtems_ide_part_table_get -- + * reads partition table structure from the device + * and creates disk description structure + * + * PARAMETERS: + * dev_name - path to physical device in /dev filesystem + * disk_desc - returned disc description structure + * + * RETURNS: + * RTEMS_SUCCESSFUL if success, or -1 and corresponding errno else + */ +/** + * @deprecated Use the @ref rtems_bdpart "block device partition module" instead. + */ +rtems_status_code rtems_ide_part_table_get( + const char *dev_name, + rtems_disk_desc_t *disk_desc +) RTEMS_COMPILER_DEPRECATED_ATTRIBUTE; + + +/* + * rtems_ide_part_table_initialize -- + * initializes logical devices on the physical IDE drive + * + * PARAMETERS: + * dev_name - path to physical device in /dev filesystem + * + * RETURNS: + * RTEMS_SUCCESSFUL if success, or -1 and corresponding errno else + */ +/** + * @deprecated Use the @ref rtems_bdpart "block device partition module" instead. + */ +rtems_status_code rtems_ide_part_table_initialize( + char *dev_name +) RTEMS_COMPILER_DEPRECATED_ATTRIBUTE; + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_IDE_PART_TABLE_H */ diff --git a/cpukit/libblock/include/rtems/media.h b/cpukit/libblock/include/rtems/media.h new file mode 100644 index 0000000000..038357c16d --- /dev/null +++ b/cpukit/libblock/include/rtems/media.h @@ -0,0 +1,521 @@ +/** + * @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. + * + * 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 +); + +/** + * @brief Sends an event message to the media server. + * + * @see See rtems_media_post_event(). + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_NO_MEMORY Not enough resources to notify the media server. + * @retval RTEMS_NOT_CONFIGURED Media server is not initialized. + */ +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/include/rtems/nvdisk-sram.h b/cpukit/libblock/include/rtems/nvdisk-sram.h new file mode 100644 index 0000000000..450cfd8602 --- /dev/null +++ b/cpukit/libblock/include/rtems/nvdisk-sram.h @@ -0,0 +1,25 @@ +/* + * $Id$ + * + * RTEMS Project (http://www.rtems.org/) + * + * Copyright 2007 Chris Johns (chrisj@rtems.org) + */ + +/** + * NV Disk Static RAM Device Driver. + * + * This driver maps an NV disk to static RAM. You can use this + */ + +#if !defined (_RTEMS_NVDISK_SRAM_H_) +#define _RTEMS_NVDISK_SRAM_H_ + +#include <rtems/nvdisk.h> + +/** + * The handlers for the NV Disk SRAM driver. + */ +extern const rtems_nvdisk_driver_handlers rtems_nvdisk_sram_handlers; + +#endif diff --git a/cpukit/libblock/include/rtems/nvdisk.h b/cpukit/libblock/include/rtems/nvdisk.h new file mode 100644 index 0000000000..48d8ba0b16 --- /dev/null +++ b/cpukit/libblock/include/rtems/nvdisk.h @@ -0,0 +1,209 @@ +/* + * nvdisk.h -- Non-volatile disk block device implementation + * + * Copyright (C) 2007 Chris Johns + * + * 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. + * + * $Id$ + */ + +/** + * The Non-volatile disk provides a simple directly mapped disk + * driver with checksums for each. It is designed to provied a + * disk that can survive a restart. Examples are EEPROM devices + * which have byte writeable locations, or a battery backed up + * RAM disk. + * + * The low level driver provides the physical access to the + * hardware. + */ +#if !defined (_RTEMS_NVDISK_H_) +#define _RTEMS_NVDISK_H_ + +#include <stdint.h> +#include <sys/ioctl.h> + +#include <rtems.h> + +/** + * The base name of the nv disks. + */ +#define RTEMS_NVDISK_DEVICE_BASE_NAME "/dev/nvd" + +/** + * NV disk specific ioctl request types. To use open the + * device and issue the ioctl call. + * + * @code + * int fd = open ("/dev/nvdisk0", O_WRONLY, 0); + * if (fd < 0) + * { + * printf ("driver open failed: %s\n", strerror (errno)); + * exit (1); + * } + * if (ioctl (fd, RTEMS_NVDISK_IOCTL_ERASE_DISK) < 0) + * { + * printf ("driver erase failed: %s\n", strerror (errno)); + * exit (1); + * } + * close (fd); + * @endcode + */ +#define RTEMS_NVDISK_IOCTL_ERASE_DISK _IO('B', 128) +#define RTEMS_NVDISK_IOCTL_MONITORING _IO('B', 129) +#define RTEMS_NVDISK_IOCTL_INFO_LEVEL _IO('B', 130) +#define RTEMS_NVDISK_IOCTL_PRINT_STATUS _IO('B', 131) + +/** + * NV Disk Monitoring Data allows a user to obtain + * the current status of the disk. + */ +typedef struct rtems_nvdisk_monitor_data +{ + uint32_t block_size; + uint32_t block_count; + uint32_t page_count; + uint32_t pages_available; + uint32_t pages_used; + uint32_t info_level; +} rtems_nvdisk_monitor_data; + +/** + * Return the number of kilo-bytes. + */ +#define RTEMS_NVDISK_KBYTES(_k) ((_k) * 1024) + +/** + * NV Low Level driver handlers. + + * Typically this structure is part of a table of handlers in the + * device which is referenced in the nvdisk configuration table. + * The reference is kept in the driver and used all the time to + * manage the nv device, therefore it must always exist. + */ +typedef struct rtems_nvdisk_driver_handlers +{ + /** + * Read data from the device into the buffer. Return an errno + * error number if the data cannot be read. + * + * @param device The device to read data from. + * @param flags Device specific flags for the driver. + * @param base The base address of the device. + * @param offset The offset in the segment to read. + * @param buffer The buffer to read the data into. + * @param size The amount of data to read. + * @retval 0 No error. + * @retval EIO The read did not complete. + */ + int (*read) (uint32_t device, uint32_t flags, void* base, + uint32_t offset, void* buffer, size_t size); + + /** + * Write data from the buffer to the device. Return an errno + * error number if the device cannot be written to. + * + * @param device The device to write data to. + * @param flags Device specific flags for the driver. + * @param base The base address of the device. + * @param offset The offset in the device to write to. + * @param buffer The buffer to write the data from. + * @param size The amount of data to write. + * @retval 0 No error. + * @retval EIO The write did not complete or verify. + */ + int (*write) (uint32_t device, uint32_t flags, void* base, + uint32_t offset, const void* buffer, size_t size); + + /** + * Verify data in the buffer to the data in the device. Return an + * errno error number if the device cannot be read or the data verified. + * + * @param device The device to verify the data with. + * @param flags Device specific flags for the driver. + * @param base The base address of the device. + * @param offset The offset in the device to verify. + * @param buffer The buffer to verify the data in the device with. + * @param size The amount of data to verify. + * @retval 0 No error. + * @retval EIO The data did not verify. + */ + int (*verify) (uint32_t device, uint32_t flags, void* base, + uint32_t offset, const void* buffer, size_t size); + +} rtems_nvdisk_driver_handlers; + +/** + * NV Device Descriptor holds the description of a device that is + * part of the NV disk. + * + * Typically this structure is part of a table of the device which + * is referenced in the nvdisk configuration table. + * The reference is kept in the driver and used all the time to + * manage the nv device, therefore it must always exist. + */ +typedef struct rtems_nvdisk_device_desc +{ + uint32_t flags; /**< Private user flags. */ + void* base; /**< Base address of the device. */ + uint32_t size; /**< Size of the device. */ + const rtems_nvdisk_driver_handlers* nv_ops; /**< Device handlers. */ +} rtems_nvdisk_device_desc; + +/** + * RTEMS Non-Volatile Disk configuration table used to initialise the + * driver. + */ +typedef struct rtems_nvdisk_config +{ + uint32_t block_size; /**< The block size. */ + uint32_t device_count; /**< The number of devices. */ + const rtems_nvdisk_device_desc* devices; /**< The device descriptions. */ + uint32_t flags; /**< Set of flags to control + driver. */ + uint32_t info_level; /**< Default info level. */ +} rtems_nvdisk_config; + +/* + * Driver flags. + */ + +/** + * Check the pages during initialisation to see which pages are + * valid and which are not. This could slow down initialising the + * disk driver. + */ +#define RTEMS_NVDISK_CHECK_PAGES (1 << 0) + +/** + * Non-volatile disk device driver initialization. Place in a table as the + * initialisation entry and remainder of the entries are the RTEMS block + * device generic handlers. + * + * @param major NV disk major device number. + * @param minor Minor device number, not applicable. + * @param arg Initialization argument, not applicable. + * @return The rtems_device_driver is actually just + * rtems_status_code. + */ +rtems_device_driver +rtems_nvdisk_initialize (rtems_device_major_number major, + rtems_device_minor_number minor, + void* arg); + +/** + * External reference to the configuration. Please supply. + * Support is present in confdefs.h for providing this variable. + */ +extern const rtems_nvdisk_config rtems_nvdisk_configuration[]; + +/** + * External reference to the number of configurations. Please supply. + * Support is present in confdefs.h for providing this variable. + */ +extern uint32_t rtems_nvdisk_configuration_size; + +#endif diff --git a/cpukit/libblock/include/rtems/ramdisk.h b/cpukit/libblock/include/rtems/ramdisk.h new file mode 100644 index 0000000000..71efc9fda0 --- /dev/null +++ b/cpukit/libblock/include/rtems/ramdisk.h @@ -0,0 +1,243 @@ +/** + * @file + * + * @ingroup rtems_ramdisk + * + * @brief RAM disk block device API. + */ + +/* + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Victor V. Vengerov <vvv@oktet.ru> + * + * @(#) $Id$ + */ + +#ifndef _RTEMS_RAMDISK_H +#define _RTEMS_RAMDISK_H + + +#include <rtems.h> +#include <rtems/blkdev.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup rtems_ramdisk RAM Disk Device + * + * @ingroup rtems_blkdev + * + * @{ + */ + +/** + * @name Static Configuration + * + * @{ + */ + +/** + * @brief RAM disk configuration table entry. + */ +typedef struct rtems_ramdisk_config { + /** + * @brief RAM disk block size. + */ + uint32_t block_size; + + /** + * @brief Number of blocks on this RAM disk. + */ + rtems_blkdev_bnum block_num; + + /** + * @brief RAM disk location or @c NULL if RAM disk memory should be allocated + * dynamically. + */ + void *location; +} rtems_ramdisk_config; + +/** + * @brief External reference to the RAM disk configuration table describing + * each RAM disk in the system. + * + * The configuration table is provided by the application. + */ +extern rtems_ramdisk_config rtems_ramdisk_configuration []; + +/** + * @brief External reference the size of the RAM disk configuration table @ref + * rtems_ramdisk_configuration. + * + * The configuration table size is provided by the application. + */ +extern size_t rtems_ramdisk_configuration_size; + +/** + * @brief RAM disk driver initialization entry point. + */ +rtems_device_driver ramdisk_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +); + +/** + * RAM disk driver table entry. + */ +#define RAMDISK_DRIVER_TABLE_ENTRY \ + { \ + .initialization_entry = ramdisk_initialize, \ + RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \ + } + +#define RAMDISK_DEVICE_BASE_NAME "/dev/rd" + +/** @} */ + +/** + * @name Runtime Configuration + * + * @{ + */ + +/** + * @brief RAM disk descriptor. + */ +typedef struct ramdisk { + /** + * @brief RAM disk block size, the media size. + */ + uint32_t block_size; + + /** + * @brief Number of blocks on this RAM disk. + */ + rtems_blkdev_bnum block_num; + + /** + * @brief RAM disk memory area. + */ + void *area; + + /** + * @brief RAM disk is initialized. + */ + bool initialized; + + /** + * @brief Indicates if memory is allocated by malloc() for this RAM disk. + */ + bool malloced; + + /** + * @brief Trace enable. + */ + bool trace; +} ramdisk; + +extern const rtems_driver_address_table ramdisk_ops; + +int ramdisk_ioctl(rtems_disk_device *dd, uint32_t req, void *argp); + +/** + * @brief Allocates and initializes a RAM disk descriptor. + * + * The block size will be @a block_size. The block count will be @a + * block_count. The disk storage area begins at @a area_begin. If @a + * area_begin is @c NULL, the memory will be allocated and zeroed. Sets the + * trace enable to @a trace. + * + * @return Pointer to allocated and initialized ramdisk structure, or @c NULL + * if no memory is available. + * + * @note + * Runtime configuration example: + * @code + * #include <rtems.h> + * #include <rtems/libio.h> + * #include <rtems/ramdisk.h> + * + * rtems_status_code create_ramdisk( + * const char *disk_name_path, + * uint32_t block_size, + * rtems_blkdev_bnum block_count + * ) + * { + * rtems_status_code sc = RTEMS_SUCCESSFUL; + * rtems_device_major_number major = 0; + * ramdisk *rd = NULL; + * dev_t dev = 0; + * + * sc = rtems_io_register_driver(0, &ramdisk_ops, &major); + * if (sc != RTEMS_SUCCESSFUL) { + * return RTEMS_UNSATISFIED; + * } + * + * rd = ramdisk_allocate(NULL, block_size, block_count, false); + * if (rd == NULL) { + * rtems_io_unregister_driver(major); + * + * return RTEMS_UNSATISFIED; + * } + * + * dev = rtems_filesystem_make_dev_t(major, 0); + * + * sc = rtems_disk_create_phys( + * dev, + * block_size, + * block_count, + * ramdisk_ioctl, + * rd, + * disk_name_path + * ); + * if (sc != RTEMS_SUCCESSFUL) { + * ramdisk_free(rd); + * rtems_io_unregister_driver(major); + * + * return RTEMS_UNSATISFIED; + * } + * + * return RTEMS_SUCCESSFUL; + * } + * @endcode + */ +ramdisk *ramdisk_allocate( + void *area_begin, + uint32_t block_size, + rtems_blkdev_bnum block_count, + bool trace +); + +void ramdisk_free(ramdisk *rd); + +/** + * @brief Allocates, initializes and registers a RAM disk. + * + * The block size will be @a block_size. The block count will be @a + * block_count. The disk storage will be allocated. Sets the trace enable to + * @a trace. Registers a device node with disk name path @a disk. The + * registered device number will be returned in @a dev. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_UNSATISFIED Something is wrong. + */ +rtems_status_code ramdisk_register( + uint32_t block_size, + rtems_blkdev_bnum block_count, + bool trace, + const char *disk, + dev_t *dev +); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif |