2002-02-28 Joel Sherrill <joel@OARcorp.com>

* Submitted by Victor V. Vengerov <vvv@oktet.ru> and merged
	into the RTEMS source.
	* ChangeLog, Makefile.am, README, configure.ac, include/Makefile.am,
	include/rtems/bdbuf.h, include/rtems/blkdev.h, include/rtems/diskdevs.h,
	include/rtems/ramdisk.h, include/rtems/.cvsignore, include/.cvsignore,
	src/Makefile.am, src/bdbuf.c, src/blkdev.c, src/diskdevs.c,
	src/ramdisk.c, src/.cvsignore, .cvsignore: New files.
This commit is contained in:
Joel Sherrill
2002-02-28 20:39:54 +00:00
parent cb1e8a4644
commit e51bd967cd
53 changed files with 11440 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
Makefile
Makefile.in
aclocal.m4
autom4te.cache
config.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
missing
mkinstalldirs

View File

@@ -0,0 +1,25 @@
2002-02-28 Joel Sherrill <joel@OARcorp.com>
* Submitted by Victor V. Vengerov <vvv@oktet.ru> and merged
into the RTEMS source.
* ChangeLog, Makefile.am, README, configure.ac, include/Makefile.am,
include/rtems/bdbuf.h, include/rtems/blkdev.h, include/rtems/diskdevs.h,
include/rtems/ramdisk.h, include/rtems/.cvsignore, include/.cvsignore,
src/Makefile.am, src/bdbuf.c, src/blkdev.c, src/diskdevs.c,
src/ramdisk.c, src/.cvsignore, .cvsignore: New files.
2001-11-29 Victor V. Vengerov <vvv@oktet.ru>
* AVL trees implementation added.
2001-11-16 Victor V. Vengerov <vvv@oktet.ru>
* include/rtems/bdbuf.h, src/bdbuf.c(rtems_bdbuf_syncdev): New.
2001-11-07 Victor V. Vengerov <vvv@oktet.ru>
* ChangeLog: New file.
* src/, include/, include/rtems/: New directories.
* README, configure.ac, Makefile.am, src/Makefile.am,
include/Makefile.am: New files.
* include/rtems/bdbuf.h include/rtems/blkdev.h
include/rtems/diskdevs.h include/rtems/ramdisk.h
src/bdbuf.c src/blkdev.c src/diskdevs.c src/ramdisk.c: New files.

View File

@@ -0,0 +1,13 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I ../../../aclocal
SUBDIRS = include src
EXTRA_DIST = README
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am

View File

@@ -0,0 +1,14 @@
#
# $Id$
#
This directory contains the block device (HDD, CDROMs, etc) support code.
It includes:
- block device driver interface
- generic open/close/read/write/ioctl primitives for block device drivers
- disk I/O buffering
- logical disk support
- RAM disk block device driver
Victor V. Vengerov, <vvv@oktet.ru>
November, 7 2001

View File

@@ -0,0 +1,32 @@
## Process this file with autoconf to produce a configure script.
##
## $Id$
AC_PREREQ(2.52)
AC_INIT
AC_CONFIG_SRCDIR([src/bdbuf.c])
RTEMS_TOP(../../..)
AC_CONFIG_AUX_DIR(../../..)
RTEMS_CANONICAL_TARGET_CPU
RTEMS_CANONICAL_HOST
AM_INIT_AUTOMAKE(rtems-c-src-libblock,$RTEMS_VERSION,no)
AM_MAINTAINER_MODE
RTEMS_ENV_RTEMSBSP
RTEMS_CHECK_CPU
RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
RTEMS_PROG_CC_FOR_TARGET
RTEMS_ENABLE_BARE
RTEMS_CANONICALIZE_TOOLS
RTEMS_PROJECT_ROOT
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
include/Makefile
src/Makefile
])
AC_OUTPUT

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,23 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.5
include_rtemsdir = $(includedir)/rtems
$(PROJECT_INCLUDE)/%.h: %.h
$(INSTALL_DATA) $< $@
$(PROJECT_INCLUDE)/rtems:
@$(mkinstalldirs) $@
include_rtems_HEADERS = \
rtems/bdbuf.h rtems/blkdev.h rtems/diskdevs.h rtems/ramdisk.h
PREINSTALL_FILES = $(PROJECT_INCLUDE)/rtems \
$(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/%)
all-local: $(PREINSTALL_FILES)
include $(top_srcdir)/../../../automake/local.am

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,282 @@
/* bdbuf.h -- block device buffer management
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_BDBUF_H__
#define __RTEMS_LIBBLOCK_BDBUF_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include <rtems/libio.h>
#include <chain.h>
#include "rtems/blkdev.h"
#include "rtems/diskdevs.h"
/*
* To manage buffers we using Buffer Descriptors.
* To speed-up buffer lookup descriptors are organized in AVL-Tree.
* The fields 'dev' and 'block' are search key.
*/
/* Buffer descriptors
* Descriptors organized in AVL-tree to speedup buffer lookup.
* dev and block fields are search key in AVL-tree.
* Modified buffers, free buffers and used buffers linked in 'mod', 'free' and
* 'lru' chains appropriately.
*/
typedef struct bdbuf_buffer {
Chain_Node link; /* Link in the lru, mod or free chains */
#ifdef BINARY_TREE
struct bdbuf_avl_node {
struct bdbuf_buffer *left; /* link to the left sub-tree */
struct bdbuf_buffer *right; /* link to the right sub-tree */
int bf; /* AVL tree node balance factor */
} avl; /* AVL-tree links */
#else /* AVL TREE */
struct bdbuf_avl_node {
char cache; /* Cache */
struct bdbuf_buffer* link[2]; /* Left and Right Kids */
char bal; /* The balance of the sub-tree */
} avl;
#endif
dev_t dev; /* device number */
blkdev_bnum block; /* block number on the device */
char *buffer; /* Pointer to the buffer memory area */
rtems_status_code status; /* Last I/O operation completion status */
int error; /* If status != RTEMS_SUCCESSFUL, this field contains
errno value which can be used by user later */
boolean modified:1; /* =1 if buffer was modified */
boolean in_progress:1; /* =1 if exchange with disk is in progress;
need to wait on semaphore */
boolean actual:1; /* Buffer contains actual data */
int use_count; /* Usage counter; incremented when somebody use
this buffer; decremented when buffer released
without modification or when buffer is flushed
by swapout task */
rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer
belongs */
CORE_mutex_Control transfer_sema;
/* Transfer operation semaphore */
} bdbuf_buffer;
/* bdbuf_config structure describes block configuration (size,
* amount, memory location) for buffering layer
*/
typedef struct rtems_bdbuf_config {
int size; /* Size of block */
int num; /* Number of blocks of appropriate size */
char *mem_area; /* Pointer to the blocks location or NULL, in this
case memory for blocks will be allocated by
Buffering Layer with the help of RTEMS partition
manager */
} rtems_bdbuf_config;
extern rtems_bdbuf_config rtems_bdbuf_configuration[];
extern int rtems_bdbuf_configuration_size;
/* rtems_bdbuf_init --
* Prepare buffering layer to work - initialize buffer descritors
* and (if it is neccessary) buffers. Buffers will be allocated accoriding
* to the configuration table, each entry describes kind of block and
* amount requested. After initialization all blocks is placed into
* free elements lists.
*
* PARAMETERS:
* conf_table - pointer to the buffers configuration table
* size - number of entries in configuration table
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*/
rtems_status_code
rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size);
/* rtems_bdbuf_get --
* Obtain block buffer. If specified block already cached (i.e. there's
* block in the _modified_, or _recently_used_), return address
* of appropriate buffer descriptor and increment reference counter to 1.
* If block is not cached, allocate new buffer and return it. Data
* shouldn't be read to the buffer from media; buffer may contains
* arbitrary data. This primitive may be blocked if there are no free
* buffer descriptors available and there are no unused non-modified
* (or synchronized with media) buffers available.
*
* PARAMETERS:
* device - device number (constructed of major and minor device number)
* block - linear media block number
* bd - address of variable to store pointer to the buffer descriptor
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* bufget_sema semaphore obtained by this primitive.
*/
rtems_status_code
rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
/* rtems_bdbuf_read --
* (Similar to the rtems_bdbuf_get, except reading data from media)
* Obtain block buffer. If specified block already cached, return address
* of appropriate buffer and increment reference counter to 1. If block is
* not cached, allocate new buffer and read data to it from the media.
* This primitive may be blocked on waiting until data to be read from
* media, if there are no free buffer descriptors available and there are
* no unused non-modified (or synchronized with media) buffers available.
*
* PARAMETERS:
* device - device number (consists of major and minor device number)
* block - linear media block number
* bd - address of variable to store pointer to the buffer descriptor
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* bufget_sema and transfer_sema semaphores obtained by this primitive.
*/
rtems_status_code
rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
/* rtems_bdbuf_release --
* Release buffer allocated before. This primitive decrease the
* usage counter. If it is zero, further destiny of buffer depends on
* 'modified' status. If buffer was modified, it is placed to the end of
* mod list and flush task waken up. If buffer was not modified,
* it is placed to the end of lru list, and bufget_sema released, allowing
* to reuse this buffer.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* flush_sema and bufget_sema semaphores may be released by this primitive.
*/
rtems_status_code
rtems_bdbuf_release(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_release_modified --
* Release buffer allocated before, assuming that it is _modified_ by
* it's owner. This primitive decrease usage counter for buffer, mark
* buffer descriptor as modified. If usage counter is 0, insert it at
* end of mod chain and release flush_sema semaphore to activate the
* flush task.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* flush_sema semaphore may be released by this primitive.
*/
rtems_status_code
rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_sync --
* Wait until specified buffer synchronized with disk. Invoked on exchanges
* critical for data consistency on the media. This primitive mark owned
* block as modified, decrease usage counter. If usage counter is 0,
* block inserted to the mod chain and flush_sema semaphore released.
* Finally, primitives blocked on transfer_sema semaphore.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* Primitive may be blocked on transfer_sema semaphore.
*/
rtems_status_code
rtems_bdbuf_sync(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_syncdev --
* Synchronize with disk all buffers containing the blocks belonging to
* specified device.
*
* PARAMETERS:
* dev - block device number
*
* RETURNS:
* 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);
/* rtems_bdbuf_find_pool --
* Find first appropriate buffer pool. This primitive returns the index
* of first buffer pool which block size is greater than or equal to
* specified size.
*
* PARAMETERS:
* block_size - requested block size
* pool - placeholder for result
*
* RETURNS:
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
* RTEMS_INVALID_SIZE if specified block size is invalid (not a power
* of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
* is not configured.
*/
rtems_status_code
rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool);
/* rtems_bdbuf_get_pool_info --
* Obtain characteristics of buffer pool with specified number.
*
* PARAMETERS:
* pool - buffer pool number
* block_size - block size for which buffer pool is configured returned
* there
* blocks - number of buffers in buffer pool returned there
*
* RETURNS:
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
* RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
*
* NOTE:
* Buffer pools enumerated contiguously starting from 0.
*/
rtems_status_code
rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,147 @@
/*
* blkdev.h - block device driver interface definitions
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_BLKDEV_H__
#define __RTEMS_LIBBLOCK_BLKDEV_H__
#include <rtems.h>
#include <sys/ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Interface with device drivers
* Block device looks, initialized and behaves like traditional RTEMS device
* driver. Heart of the block device driver is in BIOREQUEST ioctl. This call
* puts I/O request to the block device queue, in priority order, for
* asynchronous processing. When driver executes request, req_done
* function invoked, so callee knows about it. Look for details below.
*/
/* Block device block number datatype */
typedef rtems_unsigned32 blkdev_bnum;
/* Block device request type */
typedef enum blkdev_request_op {
BLKDEV_REQ_READ, /* Read operation */
BLKDEV_REQ_WRITE /* Write operation */
} blkdev_request_op;
/* Type for block device request done callback function.
*
* PARAMETERS:
* arg - argument supplied in blkdev_request
* status - rtems status code for this operation
* errno - errno value to be passed to the user when
* status != RTEMS_SUCCESSFUL
*/
typedef void (* blkdev_request_cb)(void *arg,
rtems_status_code status,
int error);
/* blkdev_sg_buffer
* Block device scatter/gather buffer structure
*/
typedef struct blkdev_sg_buffer {
rtems_unsigned32 length; /* Buffer length */
void *buffer; /* Buffer pointer */
} blkdev_sg_buffer;
/* blkdev_request (Block Device Request) structure is
* used to read/write a number of blocks from/to device.
*/
typedef struct blkdev_request {
blkdev_request_op req; /* Block device operation (read or write) */
blkdev_request_cb req_done; /* Callback function */
void *done_arg; /* Argument to be passed to callback function*/
blkdev_bnum start; /* Start block number */
rtems_unsigned32 count; /* Number of blocks to be exchanged */
rtems_unsigned32 bufnum; /* Number of buffers provided */
blkdev_sg_buffer bufs[0];/* List of scatter/gather buffers */
} blkdev_request;
/* Block device IOCTL request codes */
#define BLKIO_REQUEST _IOWR('B', 1, blkdev_request)
#define BLKIO_GETBLKSIZE _IO('B', 2)
#define BLKIO_GETSIZE _IO('B', 3)
#define BLKIO_SYNCDEV _IO('B', 4)
/* Device driver interface conventions suppose that driver may
* contain initialize/open/close/read/write/ioctl entry points. These
* primitives (except initialize) can be implemented in generic fashion,
* based upon supplied block device driver ioctl handler. Every block
* device driver should provide initialize entry point, which is register
* all block devices and appropriate ioctl handlers.
*/
#define 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
/* blkdev_generic_read --
* 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
);
/* blkdev_generic_write --
* Generic block device driver 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
);
/* blkdev_generic_open --
* Generic block device open primitive.
*/
rtems_device_driver
rtems_blkdev_generic_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
/* blkdev_generic_close --
* Generic block device close primitive.
*/
rtems_device_driver
rtems_blkdev_generic_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
/* blkdev_generic_ioctl --
* Generic block device ioctl primitive.
*/
rtems_device_driver
rtems_blkdev_generic_ioctl(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,206 @@
/*
* logdisk.h - Physical and logical block devices (disks) support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_LOGDISK_H__
#define __RTEMS_LIBBLOCK_LOGDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include "rtems/blkdev.h"
/* Buffer pool identifier */
typedef int rtems_bdpool_id;
/* Block device ioctl handler */
typedef int (* block_device_ioctl) (dev_t dev, int req, void *argp);
/* disk_device: Entry of this type created for every disk device (both for
* logical and physical disks).
* Array of arrays of pointers to disk_device structures maintained. First
* table indexed by major number and second table indexed by minor number.
* Such data organization allow quick lookup using data structure of
* moderated size.
*/
typedef struct disk_device {
dev_t dev; /* Device ID (major + minor) */
struct disk_device *phys_dev; /* Physical device ID (the same
as dev if this entry specifies
the physical device) */
char *name; /* Disk device name */
int uses; /* Use counter. Device couldn't be
removed if it is in use. */
int start; /* Starting block number (0 for
physical devices, block offset
on the related physical device
for logical device) */
int size; /* Size of physical or logical disk
in disk blocks */
int block_size; /* Size of device block (minimum
transfer unit) in bytes
(must be power of 2) */
int block_size_log2; /* log2 of block_size */
rtems_bdpool_id pool; /* Buffer pool assigned to this
device */
block_device_ioctl ioctl; /* ioctl handler for this block
device */
} disk_device;
/* rtems_disk_create_phys --
* Create physical disk entry. This function usually invoked from
* block device driver initialization code when physical device
* detected in the system. Device driver should provide ioctl handler
* to allow block device access operations. This primitive will register
* device in rtems (invoke rtems_io_register_name).
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* block_size - size of disk block (minimum data transfer unit); must be
* power of 2
* disk_size - number of blocks on device
* handler - IOCTL handler (function providing basic block input/output
* request handling BIOREQUEST and other device management
* operations)
* name - character name of device (e.g. /dev/hda)
*
* RETURNS:
* RTEMS_SUCCESSFUL if information about new physical disk added, or
* error code if error occured (device already registered, wrong block
* size value, no memory available).
*/
rtems_status_code
rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
block_device_ioctl handler,
char *name);
/* rtems_disk_create_log --
* Create logical disk entry. Logical disk is contiguous area on physical
* disk. Disk may be splitted to several logical disks in several ways:
* manually or using information stored in blocks on physical disk
* (DOS-like partition table, BSD disk label, etc). This function usually
* invoked from application when application-specific splitting are in use,
* or from generic code which handle different logical disk organizations.
* This primitive will register device in rtems (invoke
* rtems_io_register_name).
*
* PARAMETERS:
* dev - logical device identifier (major, minor numbers)
* phys - physical device (block device which holds this logical disk)
* identifier
* start - starting block number on the physical device
* size - logical disk size in blocks
* name - logical disk name
*
* RETURNS:
* RTEMS_SUCCESSFUL if logical device successfully added, or error code
* if error occured (device already registered, no physical device
* exists, logical disk is out of physical disk boundaries, no memory
* available).
*/
rtems_status_code
rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name);
/* rtems_disk_delete --
* Delete physical or logical disk device. Device may be deleted if its
* use counter (and use counters of all logical devices - if it is
* physical device) equal to 0. When physical device deleted,
* all logical devices deleted inherently. Appropriate devices removed
* from "/dev" filesystem.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* RTEMS_SUCCESSFUL if block device successfully deleted, or error code
* if error occured (device is not defined, device is in use).
*/
rtems_status_code
rtems_disk_delete(dev_t dev);
/* rtems_disk_lookup --
* Find block device descriptor by its device identifier. This function
* increment usage counter to 1. User should release disk_device structure
* by invoking rtems_disk_release primitive.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* pointer to the block device descriptor, or NULL if no such device
* exists.
*/
disk_device *
rtems_disk_lookup(dev_t dev);
/* rtems_disk_release --
* Release disk_device structure (decrement usage counter to 1).
*
* PARAMETERS:
* dd - pointer to disk device structure
*
* RETURNS:
* RTEMS_SUCCESSFUL
*
* NOTE:
* It should be implemented as inline function.
*/
rtems_status_code
rtems_disk_release(disk_device *dd);
/* rtems_disk_next --
* Disk device enumerator. Looking for device having device number larger
* than dev and return disk device descriptor for it. If there are no
* such device, NULL value returned.
*
* PARAMETERS:
* dev - device number (use -1 to start search)
*
* RETURNS:
* Pointer to the disk descriptor for next disk device, or NULL if all
* devices enumerated. */
disk_device *
rtems_disk_next(dev_t dev);
/* rtems_diskio_initialize --
* Initialization of disk device library (initialize all data structures,
* etc.)
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if library initialized, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_initialize(void);
/* rtems_diskio_done --
* Release all resources allocated for disk device interface.
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if all resources released, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_done(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,52 @@
/* ramdisk.c -- RAM disk block device implementation
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_RAMDISK_H__
#define __RTEMS_LIBBLOCK_RAMDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include "rtems/blkdev.h"
/* RAM disk configuration table entry */
typedef struct rtems_ramdisk_config {
int block_size; /* RAM disk block size */
int block_num; /* Number of blocks on this RAM disk */
void *location; /* RAM disk permanent location (out of RTEMS controlled
memory), or NULL if RAM disk memory should be
allocated dynamically */
} rtems_ramdisk_config;
/* If application want to use RAM disk, it should specify configuration of
* available RAM disks.
* The following is definitions for RAM disk configuration table
*/
extern rtems_ramdisk_config rtems_ramdisk_configuration[];
extern int rtems_ramdisk_configuration_size;
/* ramdisk_initialize --
* RAM disk driver initialization entry point.
*/
rtems_device_driver
ramdisk_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg);
#define RAMDISK_DRIVER_TABLE_ENTRY \
{ ramdisk_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,33 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.5
LIBNAME = libblock
LIB = ${ARCH}/${LIBNAME}.a
C_FILES = bdbuf.c blkdev.c diskdevs.c ramdisk.c
C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
SRCS = $(C_FILES)
OBJS = $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../../../automake/compile.am
include $(top_srcdir)/../../../automake/lib.am
AM_CFLAGS += $(LIBC_DEFINES)
TMPINSTALL_FILES += $(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a
$(LIB): ${OBJS}
$(make-library)
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@
all-local: ${ARCH} $(PREINSTALL_FILES) $(TMPINSTALL_FILES)
include $(top_srcdir)/../../../automake/local.am

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
/*
* blkdev.h - block device driver generic support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <sys/ioctl.h>
#include "rtems/diskdevs.h"
#include "rtems/bdbuf.h"
/* rtems_blkdev_generic_read --
* 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)
{
rtems_libio_rw_args_t *args = arg;
int block_size_log2;
int block_size;
char *buf;
unsigned int count;
unsigned int block;
unsigned int blkofs;
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
block_size_log2 = dd->block_size_log2;
block_size = dd->block_size;
buf = args->buffer;
count = args->count;
args->bytes_moved = 0;
block = args->offset >> block_size_log2;
blkofs = args->offset & (block_size - 1);
while (count > 0)
{
bdbuf_buffer *diskbuf;
int copy;
rtems_status_code rc;
rc = rtems_bdbuf_read(dev, block, &diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
copy = block_size - blkofs;
if (copy > count)
copy = count;
memcpy(buf, (char *)diskbuf->buffer + blkofs, copy);
rc = rtems_bdbuf_release(diskbuf);
args->bytes_moved += copy;
if (rc != RTEMS_SUCCESSFUL)
return rc;
count -= copy;
buf += copy;
blkofs = 0;
block++;
}
return RTEMS_SUCCESSFUL;
}
/* rtems_blkdev_generic_write --
* 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)
{
rtems_libio_rw_args_t *args = arg;
int block_size_log2;
int block_size;
char *buf;
unsigned int count;
unsigned int block;
unsigned int blkofs;
dev_t dev;
rtems_status_code rc;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
block_size_log2 = dd->block_size_log2;
block_size = dd->block_size;
buf = args->buffer;
count = args->count;
args->bytes_moved = 0;
block = args->offset >> block_size_log2;
blkofs = args->offset & (block_size - 1);
while (count > 0)
{
bdbuf_buffer *diskbuf;
int copy;
if ((blkofs == 0) && (count > block_size))
rc = rtems_bdbuf_get(dev, block, &diskbuf);
else
rc = rtems_bdbuf_read(dev, block, &diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
copy = block_size - blkofs;
if (copy > count)
copy = count;
memcpy((char *)diskbuf->buffer + blkofs, buf, copy);
args->bytes_moved += copy;
rc = rtems_bdbuf_release_modified(diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
count -= copy;
buf += copy;
blkofs = 0;
block++;
}
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_open --
* Generic block device open primitive.
*/
rtems_device_driver
rtems_blkdev_generic_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
dd->uses++;
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_close --
* Generic block device close primitive.
*/
rtems_device_driver
rtems_blkdev_generic_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
dd->uses--;
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_ioctl --
* Generic block device ioctl primitive.
*/
rtems_device_driver
rtems_blkdev_generic_ioctl(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
rtems_libio_ioctl_args_t *args = arg;
dev_t dev;
disk_device *dd;
int rc;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
switch (args->command)
{
case BLKIO_GETBLKSIZE:
args->ioctl_return = dd->block_size;
break;
case BLKIO_GETSIZE:
args->ioctl_return = dd->size;
break;
case BLKIO_SYNCDEV:
rc = rtems_bdbuf_syncdev(dd->dev);
args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1);
break;
case BLKIO_REQUEST:
{
blkdev_request *req = args->buffer;
req->start += dd->start;
args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
req);
break;
}
default:
args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
args->buffer);
break;
}
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,631 @@
/*
* diskdevs.c - Physical and logical block devices (disks) support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <string.h>
#include "rtems/diskdevs.h"
#include "rtems/bdbuf.h"
#define DISKTAB_INITIAL_SIZE 32
/* Table of disk devices having the same major number */
struct disk_device_table {
disk_device **minor; /* minor-indexed disk device table */
int size; /* Number of entries in the table */
};
/* Pointer to [major].minor[minor] indexed array of disk devices */
static struct disk_device_table *disktab;
/* Number of allocated entries in disktab table */
static int disktab_size;
/* Mutual exclusion semaphore for disk devices table */
static rtems_id diskdevs_mutex;
/* Flag meaning that disk I/O, buffering etc. already has been initialized. */
static boolean disk_io_initialized = FALSE;
/* diskdevs data structures protection flag.
* Normally, only table lookup operations performed. It is quite fast, so
* it is possible to done lookups when interrupts are disabled, avoiding
* obtaining the semaphore. This flags sets immediately after entering in
* mutex-protected section and cleared before leaving this section in
* "big" primitives like add/delete new device etc. Lookup function first
* disable interrupts and check this flag. If it is set, lookup function
* will be blocked on semaphore and lookup operation will be performed in
* semaphore-protected code. If it is not set (very-very frequent case),
* we can do lookup safely, enable interrupts and return result.
*/
static volatile rtems_boolean diskdevs_protected;
/* create_disk_entry --
* Return pointer to the disk_entry structure for the specified device, or
* create one if it is not exists.
*
* PARAMETERS:
* dev - device id (major, minor)
*
* RETURNS:
* pointer to the disk device descirptor entry, or NULL if no memory
* available for its creation.
*/
static disk_device *
create_disk_entry(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device **d;
rtems_filesystem_split_dev_t (dev, major, minor);
if (major >= disktab_size)
{
struct disk_device_table *p;
int newsize;
int i;
newsize = disktab_size * 2;
if (major >= newsize)
newsize = major + 1;
p = realloc(disktab, sizeof(struct disk_device_table) * newsize);
if (p == NULL)
return NULL;
p += disktab_size;
for (i = disktab_size; i < newsize; i++, p++)
{
p->minor = NULL;
p->size = 0;
}
disktab_size = newsize;
}
if ((disktab[major].minor == NULL) ||
(minor >= disktab[major].size))
{
int newsize;
disk_device **p;
int i;
int s = disktab[major].size;
if (s == 0)
newsize = DISKTAB_INITIAL_SIZE;
else
newsize = s * 2;
if (minor >= newsize)
newsize = minor + 1;
p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize);
if (p == NULL)
return NULL;
disktab[major].minor = p;
p += s;
for (i = s; i < newsize; i++, p++)
*p = NULL;
disktab[major].size = newsize;
}
d = disktab[major].minor + minor;
if (*d == NULL)
{
*d = calloc(1, sizeof(disk_device));
}
return *d;
}
/* get_disk_entry --
* Get disk device descriptor by device number.
*
* PARAMETERS:
* dev - block device number
*
* RETURNS:
* Pointer to the disk device descriptor corresponding to the specified
* device number, or NULL if disk device with such number not exists.
*/
static inline disk_device *
get_disk_entry(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device_table *dtab;
rtems_filesystem_split_dev_t (dev, major, minor);
if ((major >= disktab_size) || (disktab == NULL))
return NULL;
dtab = disktab + major;
if ((minor >= dtab->size) || (dtab->minor == NULL))
return NULL;
return dtab->minor[minor];
}
/* create_disk --
* Check that disk entry for specified device number is not defined
* and create it.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* name - character name of device (e.g. /dev/hda)
* disdev - placeholder for pointer to created disk descriptor
*
* RETURNS:
* RTEMS_SUCCESSFUL if disk entry successfully created, or
* error code if error occured (device already registered,
* no memory available).
*/
static rtems_status_code
create_disk(dev_t dev, char *name, disk_device **diskdev)
{
disk_device *dd;
char *n;
dd = get_disk_entry(dev);
if (dd != NULL)
{
return RTEMS_RESOURCE_IN_USE;
}
if (name == NULL)
{
n = NULL;
}
else
{
int nlen = strlen(name) + 1;
n = malloc(nlen);
if (n == NULL)
return RTEMS_NO_MEMORY;
strncpy(n, name, nlen);
}
dd = create_disk_entry(dev);
if (dd == NULL)
{
free(n);
return RTEMS_NO_MEMORY;
}
dd->dev = dev;
dd->name = n;
*diskdev = dd;
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_create_phys --
* Create physical disk entry. This function usually invoked from
* block device driver initialization code when physical device
* detected in the system. Device driver should provide ioctl handler
* to allow block device access operations. This primitive will register
* device in rtems (invoke rtems_io_register_name).
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* block_size - size of disk block (minimum data transfer unit); must be
* power of 2
* disk_size - number of blocks on device
* handler - IOCTL handler (function providing basic block input/output
* request handling BIOREQUEST and other device management
* operations)
* name - character name of device (e.g. /dev/hda)
*
* RETURNS:
* RTEMS_SUCCESSFUL if information about new physical disk added, or
* error code if error occured (device already registered, wrong block
* size value, no memory available).
*/
rtems_status_code
rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
block_device_ioctl handler,
char *name)
{
int bs_log2;
int i;
disk_device *dd;
rtems_status_code rc;
rtems_bdpool_id pool;
rtems_device_major_number major;
rtems_device_minor_number minor;
rtems_filesystem_split_dev_t (dev, major, minor);
for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++);
if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */
return RTEMS_INVALID_NUMBER;
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
rc = rtems_bdbuf_find_pool(block_size, &pool);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
rc = create_disk(dev, name, &dd);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
dd->phys_dev = dd;
dd->uses = 0;
dd->start = 0;
dd->size = disk_size;
dd->block_size = block_size;
dd->block_size_log2 = bs_log2;
dd->ioctl = handler;
dd->pool = pool;
rc = rtems_io_register_name(name, major, minor);
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_create_log --
* Create logical disk entry. Logical disk is contiguous area on physical
* disk. Disk may be splitted to several logical disks in several ways:
* manually or using information stored in blocks on physical disk
* (DOS-like partition table, BSD disk label, etc). This function usually
* invoked from application when application-specific splitting are in use,
* or from generic code which handle different logical disk organizations.
* This primitive will register device in rtems (invoke
* rtems_io_register_name).
*
* PARAMETERS:
* dev - logical device identifier (major, minor numbers)
* phys - physical device (block device which holds this logical disk)
* identifier
* start - starting block number on the physical device
* size - logical disk size in blocks
* name - logical disk name
*
* RETURNS:
* RTEMS_SUCCESSFUL if logical device successfully added, or error code
* if error occured (device already registered, no physical device
* exists, logical disk is out of physical disk boundaries, no memory
* available).
*/
rtems_status_code
rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name)
{
disk_device *dd;
disk_device *pdd;
rtems_status_code rc;
rtems_device_major_number major;
rtems_device_minor_number minor;
rtems_filesystem_split_dev_t (dev, major, minor);
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
pdd = get_disk_entry(phys);
if (pdd == NULL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return RTEMS_INVALID_NUMBER;
}
rc = create_disk(dev, name, &dd);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
dd->phys_dev = pdd;
dd->uses = 0;
dd->start = start;
dd->size = size;
dd->block_size = pdd->block_size;
dd->block_size_log2 = pdd->block_size_log2;
dd->ioctl = pdd->ioctl;
rc = rtems_io_register_name(name, major, minor);
diskdevs_protected = FALSE;
rc = rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_delete --
* Delete physical or logical disk device. Device may be deleted if its
* use counter (and use counters of all logical devices - if it is
* physical device) equal to 0. When physical device deleted,
* all logical devices deleted inherently. Appropriate devices removed
* from "/dev" filesystem.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* RTEMS_SUCCESSFUL if block device successfully deleted, or error code
* if error occured (device is not defined, device is in use).
*/
rtems_status_code
rtems_disk_delete(dev_t dev)
{
rtems_status_code rc;
int used;
rtems_device_major_number maj;
rtems_device_minor_number min;
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
/* Check if this device is in use -- calculate usage counter */
used = 0;
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab + maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
if ((dd != NULL) && (dd->phys_dev->dev == dev))
used += dd->uses;
}
}
}
if (used != 0)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return RTEMS_RESOURCE_IN_USE;
}
/* Delete this device and all of its logical devices */
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab +maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
if ((dd != NULL) && (dd->phys_dev->dev == dev))
{
unlink(dd->name);
free(dd->name);
free(dd);
dtab->minor[min] = NULL;
}
}
}
}
diskdevs_protected = FALSE;
rc = rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_lookup --
* Find block device descriptor by its device identifier.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* pointer to the block device descriptor, or NULL if no such device
* exists.
*/
disk_device *
rtems_disk_lookup(dev_t dev)
{
rtems_interrupt_level level;
disk_device *dd;
rtems_status_code rc;
rtems_interrupt_disable(level);
if (diskdevs_protected)
{
rtems_interrupt_enable(level);
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return NULL;
diskdevs_protected = TRUE;
dd = get_disk_entry(dev);
dd->uses++;
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return dd;
}
else
{
/* Frequent and quickest case */
dd = get_disk_entry(dev);
dd->uses++;
rtems_interrupt_enable(level);
return dd;
}
}
/* rtems_disk_release --
* Release disk_device structure (decrement usage counter to 1).
*
* PARAMETERS:
* dd - pointer to disk device structure
*
* RETURNS:
* RTEMS_SUCCESSFUL
*/
rtems_status_code
rtems_disk_release(disk_device *dd)
{
rtems_interrupt_level level;
rtems_interrupt_disable(level);
dd->uses--;
rtems_interrupt_enable(level);
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_next --
* Disk device enumerator. Looking for device having device number larger
* than dev and return disk device descriptor for it. If there are no
* such device, NULL value returned.
*
* PARAMETERS:
* dev - device number (use -1 to start search)
*
* RETURNS:
* Pointer to the disk descriptor for next disk device, or NULL if all
* devices enumerated.
*/
disk_device *
rtems_disk_next(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device_table *dtab;
dev++;
rtems_filesystem_split_dev_t (dev, major, minor);
if (major >= disktab_size)
return NULL;
dtab = disktab + major;
while (TRUE)
{
if ((dtab == NULL) || (minor > dtab->size))
{
major++; minor = 0;
if (major >= disktab_size)
return NULL;
dtab = disktab + major;
}
else if (dtab->minor[minor] == NULL)
{
minor++;
}
else
return dtab->minor[minor];
}
}
/* rtems_disk_initialize --
* Initialization of disk device library (initialize all data structures,
* etc.)
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if library initialized, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_initialize(void)
{
rtems_status_code rc;
if (disk_io_initialized)
return RTEMS_SUCCESSFUL;
disktab_size = DISKTAB_INITIAL_SIZE;
disktab = calloc(disktab_size, sizeof(struct disk_device_table));
if (disktab == NULL)
return RTEMS_NO_MEMORY;
diskdevs_protected = FALSE;
rc = rtems_semaphore_create(
rtems_build_name('D', 'D', 'E', 'V'), 1,
RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
if (rc != RTEMS_SUCCESSFUL)
{
free(disktab);
return rc;
}
rc = rtems_bdbuf_init(rtems_bdbuf_configuration,
rtems_bdbuf_configuration_size);
if (rc != RTEMS_SUCCESSFUL)
{
rtems_semaphore_delete(diskdevs_mutex);
free(disktab);
return rc;
}
disk_io_initialized = 1;
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_io_done --
* Release all resources allocated for disk device interface.
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if all resources released, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_done(void)
{
rtems_device_major_number maj;
rtems_device_minor_number min;
rtems_status_code rc;
/* Free data structures */
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab + maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
unlink(dd->name);
free(dd->name);
free(dd);
}
free(dtab);
}
}
free(disktab);
rc = rtems_semaphore_release(diskdevs_mutex);
/* XXX bdbuf should be released too! */
disk_io_initialized = 0;
return rc;
}

View File

@@ -0,0 +1,224 @@
/* ramdisk.c -- RAM disk block device implementation
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "rtems/blkdev.h"
#include "rtems/diskdevs.h"
#include "rtems/ramdisk.h"
#define RAMDISK_DEVICE_BASE_NAME "/dev/ramdisk"
/* Internal RAM disk descriptor */
struct ramdisk {
int block_size; /* RAM disk block size */
int block_num; /* Number of blocks on this RAM disk */
void *area; /* RAM disk memory area */
rtems_boolean initialized;/* RAM disk is initialized */
rtems_boolean malloced; /* != 0, if memory allocated by malloc for this
RAM disk */
};
static struct ramdisk *ramdisk;
static int nramdisks;
/* ramdisk_read --
* RAM disk READ request handler. This primitive copies data from RAM
* disk to supplied buffer and invoke the callout function to inform
* upper layer that reading is completed.
*
* PARAMETERS:
* req - pointer to the READ block device request info
*
* RETURNS:
* ioctl return value
*/
static int
ramdisk_read(struct ramdisk *rd, blkdev_request *req)
{
char *from;
rtems_unsigned32 i;
blkdev_sg_buffer *sg;
rtems_unsigned32 remains;
from = (char *)rd->area + (req->start * rd->block_size);
remains = rd->block_size * req->count;
sg = req->bufs;
for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
{
int count = sg->length;
if (count > remains)
count = remains;
memcpy(sg->buffer, from, count);
remains -= count;
}
req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0);
return 0;
}
/* ramdisk_write --
* RAM disk WRITE request handler. This primitive copies data from
* supplied buffer to RAM disk and invoke the callout function to inform
* upper layer that writing is completed.
*
* PARAMETERS:
* req - pointer to the WRITE block device request info
*
* RETURNS:
* ioctl return value
*/
static int
ramdisk_write(struct ramdisk *rd, blkdev_request *req)
{
char *to;
rtems_unsigned32 i;
blkdev_sg_buffer *sg;
rtems_unsigned32 remains;
to = (char *)rd->area + (req->start * rd->block_size);
remains = rd->block_size * req->count;
sg = req->bufs;
for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
{
int count = sg->length;
if (count > remains)
count = remains;
memcpy(to, sg->buffer, count);
remains -= count;
}
req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0);
return 0;
}
/* ramdisk_ioctl --
* IOCTL handler for RAM disk device.
*
* PARAMETERS:
* dev - device number (major, minor number)
* req - IOCTL request code
* argp - IOCTL argument
*
* RETURNS:
* IOCTL return value
*/
static int
ramdisk_ioctl(dev_t dev, int req, void *argp)
{
switch (req)
{
case BLKIO_REQUEST:
{
rtems_device_minor_number minor;
blkdev_request *r = argp;
struct ramdisk *rd;
minor = rtems_filesystem_dev_minor_t(dev);
if ((minor >= nramdisks) || !ramdisk[minor].initialized)
{
errno = ENODEV;
return -1;
}
rd = ramdisk + minor;
switch (r->req)
{
case BLKDEV_REQ_READ:
return ramdisk_read(rd, r);
case BLKDEV_REQ_WRITE:
return ramdisk_write(rd, r);
default:
errno = EBADRQC;
return -1;
}
break;
}
default:
errno = EBADRQC;
return -1;
}
}
/* ramdisk_initialize --
* RAM disk device driver initialization. Run through RAM disk
* configuration information and configure appropriate RAM disks.
*
* PARAMETERS:
* major - RAM disk major device number
* minor - minor device number, not applicable
* arg - initialization argument, not applicable
*
* RETURNS:
* none
*/
rtems_device_driver
ramdisk_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_device_minor_number i;
rtems_ramdisk_config *c = rtems_ramdisk_configuration;
struct ramdisk *r;
rtems_status_code rc;
rc = rtems_disk_io_initialize();
if (rc != RTEMS_SUCCESSFUL)
return rc;
r = ramdisk = calloc(rtems_ramdisk_configuration_size,
sizeof(struct ramdisk));
for (i = 0; i < rtems_ramdisk_configuration_size; i++, c++, r++)
{
dev_t dev = rtems_filesystem_make_dev_t(major, i);
char name[sizeof(RAMDISK_DEVICE_BASE_NAME "0123456789")];
snprintf(name, sizeof(name), RAMDISK_DEVICE_BASE_NAME "%d", i);
r->block_size = c->block_size;
r->block_num = c->block_num;
if (c->location == NULL)
{
r->malloced = TRUE;
r->area = malloc(r->block_size * r->block_num);
if (r->area == NULL) /* No enough memory for this disk */
{
r->initialized = FALSE;
continue;
}
else
{
r->initialized = TRUE;
}
}
else
{
r->malloced = FALSE;
r->initialized = TRUE;
r->area = c->location;
}
rc = rtems_disk_create_phys(dev, c->block_size, c->block_num,
ramdisk_ioctl, name);
if (rc != RTEMS_SUCCESSFUL)
{
if (r->malloced)
{
free(r->area);
}
r->initialized = FALSE;
}
}
nramdisks = rtems_ramdisk_configuration_size;
return RTEMS_SUCCESSFUL;
}

14
c/src/libblock/.cvsignore Normal file
View File

@@ -0,0 +1,14 @@
Makefile
Makefile.in
aclocal.m4
autom4te.cache
config.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
missing
mkinstalldirs

25
c/src/libblock/ChangeLog Normal file
View File

@@ -0,0 +1,25 @@
2002-02-28 Joel Sherrill <joel@OARcorp.com>
* Submitted by Victor V. Vengerov <vvv@oktet.ru> and merged
into the RTEMS source.
* ChangeLog, Makefile.am, README, configure.ac, include/Makefile.am,
include/rtems/bdbuf.h, include/rtems/blkdev.h, include/rtems/diskdevs.h,
include/rtems/ramdisk.h, include/rtems/.cvsignore, include/.cvsignore,
src/Makefile.am, src/bdbuf.c, src/blkdev.c, src/diskdevs.c,
src/ramdisk.c, src/.cvsignore, .cvsignore: New files.
2001-11-29 Victor V. Vengerov <vvv@oktet.ru>
* AVL trees implementation added.
2001-11-16 Victor V. Vengerov <vvv@oktet.ru>
* include/rtems/bdbuf.h, src/bdbuf.c(rtems_bdbuf_syncdev): New.
2001-11-07 Victor V. Vengerov <vvv@oktet.ru>
* ChangeLog: New file.
* src/, include/, include/rtems/: New directories.
* README, configure.ac, Makefile.am, src/Makefile.am,
include/Makefile.am: New files.
* include/rtems/bdbuf.h include/rtems/blkdev.h
include/rtems/diskdevs.h include/rtems/ramdisk.h
src/bdbuf.c src/blkdev.c src/diskdevs.c src/ramdisk.c: New files.

View File

@@ -0,0 +1,13 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I ../../../aclocal
SUBDIRS = include src
EXTRA_DIST = README
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am

14
c/src/libblock/README Normal file
View File

@@ -0,0 +1,14 @@
#
# $Id$
#
This directory contains the block device (HDD, CDROMs, etc) support code.
It includes:
- block device driver interface
- generic open/close/read/write/ioctl primitives for block device drivers
- disk I/O buffering
- logical disk support
- RAM disk block device driver
Victor V. Vengerov, <vvv@oktet.ru>
November, 7 2001

View File

@@ -0,0 +1,32 @@
## Process this file with autoconf to produce a configure script.
##
## $Id$
AC_PREREQ(2.52)
AC_INIT
AC_CONFIG_SRCDIR([src/bdbuf.c])
RTEMS_TOP(../../..)
AC_CONFIG_AUX_DIR(../../..)
RTEMS_CANONICAL_TARGET_CPU
RTEMS_CANONICAL_HOST
AM_INIT_AUTOMAKE(rtems-c-src-libblock,$RTEMS_VERSION,no)
AM_MAINTAINER_MODE
RTEMS_ENV_RTEMSBSP
RTEMS_CHECK_CPU
RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
RTEMS_PROG_CC_FOR_TARGET
RTEMS_ENABLE_BARE
RTEMS_CANONICALIZE_TOOLS
RTEMS_PROJECT_ROOT
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
include/Makefile
src/Makefile
])
AC_OUTPUT

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,23 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.5
include_rtemsdir = $(includedir)/rtems
$(PROJECT_INCLUDE)/%.h: %.h
$(INSTALL_DATA) $< $@
$(PROJECT_INCLUDE)/rtems:
@$(mkinstalldirs) $@
include_rtems_HEADERS = \
rtems/bdbuf.h rtems/blkdev.h rtems/diskdevs.h rtems/ramdisk.h
PREINSTALL_FILES = $(PROJECT_INCLUDE)/rtems \
$(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/%)
all-local: $(PREINSTALL_FILES)
include $(top_srcdir)/../../../automake/local.am

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,282 @@
/* bdbuf.h -- block device buffer management
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_BDBUF_H__
#define __RTEMS_LIBBLOCK_BDBUF_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include <rtems/libio.h>
#include <chain.h>
#include "rtems/blkdev.h"
#include "rtems/diskdevs.h"
/*
* To manage buffers we using Buffer Descriptors.
* To speed-up buffer lookup descriptors are organized in AVL-Tree.
* The fields 'dev' and 'block' are search key.
*/
/* Buffer descriptors
* Descriptors organized in AVL-tree to speedup buffer lookup.
* dev and block fields are search key in AVL-tree.
* Modified buffers, free buffers and used buffers linked in 'mod', 'free' and
* 'lru' chains appropriately.
*/
typedef struct bdbuf_buffer {
Chain_Node link; /* Link in the lru, mod or free chains */
#ifdef BINARY_TREE
struct bdbuf_avl_node {
struct bdbuf_buffer *left; /* link to the left sub-tree */
struct bdbuf_buffer *right; /* link to the right sub-tree */
int bf; /* AVL tree node balance factor */
} avl; /* AVL-tree links */
#else /* AVL TREE */
struct bdbuf_avl_node {
char cache; /* Cache */
struct bdbuf_buffer* link[2]; /* Left and Right Kids */
char bal; /* The balance of the sub-tree */
} avl;
#endif
dev_t dev; /* device number */
blkdev_bnum block; /* block number on the device */
char *buffer; /* Pointer to the buffer memory area */
rtems_status_code status; /* Last I/O operation completion status */
int error; /* If status != RTEMS_SUCCESSFUL, this field contains
errno value which can be used by user later */
boolean modified:1; /* =1 if buffer was modified */
boolean in_progress:1; /* =1 if exchange with disk is in progress;
need to wait on semaphore */
boolean actual:1; /* Buffer contains actual data */
int use_count; /* Usage counter; incremented when somebody use
this buffer; decremented when buffer released
without modification or when buffer is flushed
by swapout task */
rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer
belongs */
CORE_mutex_Control transfer_sema;
/* Transfer operation semaphore */
} bdbuf_buffer;
/* bdbuf_config structure describes block configuration (size,
* amount, memory location) for buffering layer
*/
typedef struct rtems_bdbuf_config {
int size; /* Size of block */
int num; /* Number of blocks of appropriate size */
char *mem_area; /* Pointer to the blocks location or NULL, in this
case memory for blocks will be allocated by
Buffering Layer with the help of RTEMS partition
manager */
} rtems_bdbuf_config;
extern rtems_bdbuf_config rtems_bdbuf_configuration[];
extern int rtems_bdbuf_configuration_size;
/* rtems_bdbuf_init --
* Prepare buffering layer to work - initialize buffer descritors
* and (if it is neccessary) buffers. Buffers will be allocated accoriding
* to the configuration table, each entry describes kind of block and
* amount requested. After initialization all blocks is placed into
* free elements lists.
*
* PARAMETERS:
* conf_table - pointer to the buffers configuration table
* size - number of entries in configuration table
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*/
rtems_status_code
rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size);
/* rtems_bdbuf_get --
* Obtain block buffer. If specified block already cached (i.e. there's
* block in the _modified_, or _recently_used_), return address
* of appropriate buffer descriptor and increment reference counter to 1.
* If block is not cached, allocate new buffer and return it. Data
* shouldn't be read to the buffer from media; buffer may contains
* arbitrary data. This primitive may be blocked if there are no free
* buffer descriptors available and there are no unused non-modified
* (or synchronized with media) buffers available.
*
* PARAMETERS:
* device - device number (constructed of major and minor device number)
* block - linear media block number
* bd - address of variable to store pointer to the buffer descriptor
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* bufget_sema semaphore obtained by this primitive.
*/
rtems_status_code
rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
/* rtems_bdbuf_read --
* (Similar to the rtems_bdbuf_get, except reading data from media)
* Obtain block buffer. If specified block already cached, return address
* of appropriate buffer and increment reference counter to 1. If block is
* not cached, allocate new buffer and read data to it from the media.
* This primitive may be blocked on waiting until data to be read from
* media, if there are no free buffer descriptors available and there are
* no unused non-modified (or synchronized with media) buffers available.
*
* PARAMETERS:
* device - device number (consists of major and minor device number)
* block - linear media block number
* bd - address of variable to store pointer to the buffer descriptor
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* bufget_sema and transfer_sema semaphores obtained by this primitive.
*/
rtems_status_code
rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
/* rtems_bdbuf_release --
* Release buffer allocated before. This primitive decrease the
* usage counter. If it is zero, further destiny of buffer depends on
* 'modified' status. If buffer was modified, it is placed to the end of
* mod list and flush task waken up. If buffer was not modified,
* it is placed to the end of lru list, and bufget_sema released, allowing
* to reuse this buffer.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* flush_sema and bufget_sema semaphores may be released by this primitive.
*/
rtems_status_code
rtems_bdbuf_release(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_release_modified --
* Release buffer allocated before, assuming that it is _modified_ by
* it's owner. This primitive decrease usage counter for buffer, mark
* buffer descriptor as modified. If usage counter is 0, insert it at
* end of mod chain and release flush_sema semaphore to activate the
* flush task.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* flush_sema semaphore may be released by this primitive.
*/
rtems_status_code
rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_sync --
* Wait until specified buffer synchronized with disk. Invoked on exchanges
* critical for data consistency on the media. This primitive mark owned
* block as modified, decrease usage counter. If usage counter is 0,
* block inserted to the mod chain and flush_sema semaphore released.
* Finally, primitives blocked on transfer_sema semaphore.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* Primitive may be blocked on transfer_sema semaphore.
*/
rtems_status_code
rtems_bdbuf_sync(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_syncdev --
* Synchronize with disk all buffers containing the blocks belonging to
* specified device.
*
* PARAMETERS:
* dev - block device number
*
* RETURNS:
* 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);
/* rtems_bdbuf_find_pool --
* Find first appropriate buffer pool. This primitive returns the index
* of first buffer pool which block size is greater than or equal to
* specified size.
*
* PARAMETERS:
* block_size - requested block size
* pool - placeholder for result
*
* RETURNS:
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
* RTEMS_INVALID_SIZE if specified block size is invalid (not a power
* of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
* is not configured.
*/
rtems_status_code
rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool);
/* rtems_bdbuf_get_pool_info --
* Obtain characteristics of buffer pool with specified number.
*
* PARAMETERS:
* pool - buffer pool number
* block_size - block size for which buffer pool is configured returned
* there
* blocks - number of buffers in buffer pool returned there
*
* RETURNS:
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
* RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
*
* NOTE:
* Buffer pools enumerated contiguously starting from 0.
*/
rtems_status_code
rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,147 @@
/*
* blkdev.h - block device driver interface definitions
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_BLKDEV_H__
#define __RTEMS_LIBBLOCK_BLKDEV_H__
#include <rtems.h>
#include <sys/ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Interface with device drivers
* Block device looks, initialized and behaves like traditional RTEMS device
* driver. Heart of the block device driver is in BIOREQUEST ioctl. This call
* puts I/O request to the block device queue, in priority order, for
* asynchronous processing. When driver executes request, req_done
* function invoked, so callee knows about it. Look for details below.
*/
/* Block device block number datatype */
typedef rtems_unsigned32 blkdev_bnum;
/* Block device request type */
typedef enum blkdev_request_op {
BLKDEV_REQ_READ, /* Read operation */
BLKDEV_REQ_WRITE /* Write operation */
} blkdev_request_op;
/* Type for block device request done callback function.
*
* PARAMETERS:
* arg - argument supplied in blkdev_request
* status - rtems status code for this operation
* errno - errno value to be passed to the user when
* status != RTEMS_SUCCESSFUL
*/
typedef void (* blkdev_request_cb)(void *arg,
rtems_status_code status,
int error);
/* blkdev_sg_buffer
* Block device scatter/gather buffer structure
*/
typedef struct blkdev_sg_buffer {
rtems_unsigned32 length; /* Buffer length */
void *buffer; /* Buffer pointer */
} blkdev_sg_buffer;
/* blkdev_request (Block Device Request) structure is
* used to read/write a number of blocks from/to device.
*/
typedef struct blkdev_request {
blkdev_request_op req; /* Block device operation (read or write) */
blkdev_request_cb req_done; /* Callback function */
void *done_arg; /* Argument to be passed to callback function*/
blkdev_bnum start; /* Start block number */
rtems_unsigned32 count; /* Number of blocks to be exchanged */
rtems_unsigned32 bufnum; /* Number of buffers provided */
blkdev_sg_buffer bufs[0];/* List of scatter/gather buffers */
} blkdev_request;
/* Block device IOCTL request codes */
#define BLKIO_REQUEST _IOWR('B', 1, blkdev_request)
#define BLKIO_GETBLKSIZE _IO('B', 2)
#define BLKIO_GETSIZE _IO('B', 3)
#define BLKIO_SYNCDEV _IO('B', 4)
/* Device driver interface conventions suppose that driver may
* contain initialize/open/close/read/write/ioctl entry points. These
* primitives (except initialize) can be implemented in generic fashion,
* based upon supplied block device driver ioctl handler. Every block
* device driver should provide initialize entry point, which is register
* all block devices and appropriate ioctl handlers.
*/
#define 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
/* blkdev_generic_read --
* 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
);
/* blkdev_generic_write --
* Generic block device driver 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
);
/* blkdev_generic_open --
* Generic block device open primitive.
*/
rtems_device_driver
rtems_blkdev_generic_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
/* blkdev_generic_close --
* Generic block device close primitive.
*/
rtems_device_driver
rtems_blkdev_generic_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
/* blkdev_generic_ioctl --
* Generic block device ioctl primitive.
*/
rtems_device_driver
rtems_blkdev_generic_ioctl(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,206 @@
/*
* logdisk.h - Physical and logical block devices (disks) support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_LOGDISK_H__
#define __RTEMS_LIBBLOCK_LOGDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include "rtems/blkdev.h"
/* Buffer pool identifier */
typedef int rtems_bdpool_id;
/* Block device ioctl handler */
typedef int (* block_device_ioctl) (dev_t dev, int req, void *argp);
/* disk_device: Entry of this type created for every disk device (both for
* logical and physical disks).
* Array of arrays of pointers to disk_device structures maintained. First
* table indexed by major number and second table indexed by minor number.
* Such data organization allow quick lookup using data structure of
* moderated size.
*/
typedef struct disk_device {
dev_t dev; /* Device ID (major + minor) */
struct disk_device *phys_dev; /* Physical device ID (the same
as dev if this entry specifies
the physical device) */
char *name; /* Disk device name */
int uses; /* Use counter. Device couldn't be
removed if it is in use. */
int start; /* Starting block number (0 for
physical devices, block offset
on the related physical device
for logical device) */
int size; /* Size of physical or logical disk
in disk blocks */
int block_size; /* Size of device block (minimum
transfer unit) in bytes
(must be power of 2) */
int block_size_log2; /* log2 of block_size */
rtems_bdpool_id pool; /* Buffer pool assigned to this
device */
block_device_ioctl ioctl; /* ioctl handler for this block
device */
} disk_device;
/* rtems_disk_create_phys --
* Create physical disk entry. This function usually invoked from
* block device driver initialization code when physical device
* detected in the system. Device driver should provide ioctl handler
* to allow block device access operations. This primitive will register
* device in rtems (invoke rtems_io_register_name).
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* block_size - size of disk block (minimum data transfer unit); must be
* power of 2
* disk_size - number of blocks on device
* handler - IOCTL handler (function providing basic block input/output
* request handling BIOREQUEST and other device management
* operations)
* name - character name of device (e.g. /dev/hda)
*
* RETURNS:
* RTEMS_SUCCESSFUL if information about new physical disk added, or
* error code if error occured (device already registered, wrong block
* size value, no memory available).
*/
rtems_status_code
rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
block_device_ioctl handler,
char *name);
/* rtems_disk_create_log --
* Create logical disk entry. Logical disk is contiguous area on physical
* disk. Disk may be splitted to several logical disks in several ways:
* manually or using information stored in blocks on physical disk
* (DOS-like partition table, BSD disk label, etc). This function usually
* invoked from application when application-specific splitting are in use,
* or from generic code which handle different logical disk organizations.
* This primitive will register device in rtems (invoke
* rtems_io_register_name).
*
* PARAMETERS:
* dev - logical device identifier (major, minor numbers)
* phys - physical device (block device which holds this logical disk)
* identifier
* start - starting block number on the physical device
* size - logical disk size in blocks
* name - logical disk name
*
* RETURNS:
* RTEMS_SUCCESSFUL if logical device successfully added, or error code
* if error occured (device already registered, no physical device
* exists, logical disk is out of physical disk boundaries, no memory
* available).
*/
rtems_status_code
rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name);
/* rtems_disk_delete --
* Delete physical or logical disk device. Device may be deleted if its
* use counter (and use counters of all logical devices - if it is
* physical device) equal to 0. When physical device deleted,
* all logical devices deleted inherently. Appropriate devices removed
* from "/dev" filesystem.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* RTEMS_SUCCESSFUL if block device successfully deleted, or error code
* if error occured (device is not defined, device is in use).
*/
rtems_status_code
rtems_disk_delete(dev_t dev);
/* rtems_disk_lookup --
* Find block device descriptor by its device identifier. This function
* increment usage counter to 1. User should release disk_device structure
* by invoking rtems_disk_release primitive.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* pointer to the block device descriptor, or NULL if no such device
* exists.
*/
disk_device *
rtems_disk_lookup(dev_t dev);
/* rtems_disk_release --
* Release disk_device structure (decrement usage counter to 1).
*
* PARAMETERS:
* dd - pointer to disk device structure
*
* RETURNS:
* RTEMS_SUCCESSFUL
*
* NOTE:
* It should be implemented as inline function.
*/
rtems_status_code
rtems_disk_release(disk_device *dd);
/* rtems_disk_next --
* Disk device enumerator. Looking for device having device number larger
* than dev and return disk device descriptor for it. If there are no
* such device, NULL value returned.
*
* PARAMETERS:
* dev - device number (use -1 to start search)
*
* RETURNS:
* Pointer to the disk descriptor for next disk device, or NULL if all
* devices enumerated. */
disk_device *
rtems_disk_next(dev_t dev);
/* rtems_diskio_initialize --
* Initialization of disk device library (initialize all data structures,
* etc.)
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if library initialized, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_initialize(void);
/* rtems_diskio_done --
* Release all resources allocated for disk device interface.
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if all resources released, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_done(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,52 @@
/* ramdisk.c -- RAM disk block device implementation
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_RAMDISK_H__
#define __RTEMS_LIBBLOCK_RAMDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include "rtems/blkdev.h"
/* RAM disk configuration table entry */
typedef struct rtems_ramdisk_config {
int block_size; /* RAM disk block size */
int block_num; /* Number of blocks on this RAM disk */
void *location; /* RAM disk permanent location (out of RTEMS controlled
memory), or NULL if RAM disk memory should be
allocated dynamically */
} rtems_ramdisk_config;
/* If application want to use RAM disk, it should specify configuration of
* available RAM disks.
* The following is definitions for RAM disk configuration table
*/
extern rtems_ramdisk_config rtems_ramdisk_configuration[];
extern int rtems_ramdisk_configuration_size;
/* ramdisk_initialize --
* RAM disk driver initialization entry point.
*/
rtems_device_driver
ramdisk_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg);
#define RAMDISK_DRIVER_TABLE_ENTRY \
{ ramdisk_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,33 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.5
LIBNAME = libblock
LIB = ${ARCH}/${LIBNAME}.a
C_FILES = bdbuf.c blkdev.c diskdevs.c ramdisk.c
C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
SRCS = $(C_FILES)
OBJS = $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../../../automake/compile.am
include $(top_srcdir)/../../../automake/lib.am
AM_CFLAGS += $(LIBC_DEFINES)
TMPINSTALL_FILES += $(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a
$(LIB): ${OBJS}
$(make-library)
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@
all-local: ${ARCH} $(PREINSTALL_FILES) $(TMPINSTALL_FILES)
include $(top_srcdir)/../../../automake/local.am

1876
c/src/libblock/src/bdbuf.c Normal file

File diff suppressed because it is too large Load Diff

243
c/src/libblock/src/blkdev.c Normal file
View File

@@ -0,0 +1,243 @@
/*
* blkdev.h - block device driver generic support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <sys/ioctl.h>
#include "rtems/diskdevs.h"
#include "rtems/bdbuf.h"
/* rtems_blkdev_generic_read --
* 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)
{
rtems_libio_rw_args_t *args = arg;
int block_size_log2;
int block_size;
char *buf;
unsigned int count;
unsigned int block;
unsigned int blkofs;
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
block_size_log2 = dd->block_size_log2;
block_size = dd->block_size;
buf = args->buffer;
count = args->count;
args->bytes_moved = 0;
block = args->offset >> block_size_log2;
blkofs = args->offset & (block_size - 1);
while (count > 0)
{
bdbuf_buffer *diskbuf;
int copy;
rtems_status_code rc;
rc = rtems_bdbuf_read(dev, block, &diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
copy = block_size - blkofs;
if (copy > count)
copy = count;
memcpy(buf, (char *)diskbuf->buffer + blkofs, copy);
rc = rtems_bdbuf_release(diskbuf);
args->bytes_moved += copy;
if (rc != RTEMS_SUCCESSFUL)
return rc;
count -= copy;
buf += copy;
blkofs = 0;
block++;
}
return RTEMS_SUCCESSFUL;
}
/* rtems_blkdev_generic_write --
* 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)
{
rtems_libio_rw_args_t *args = arg;
int block_size_log2;
int block_size;
char *buf;
unsigned int count;
unsigned int block;
unsigned int blkofs;
dev_t dev;
rtems_status_code rc;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
block_size_log2 = dd->block_size_log2;
block_size = dd->block_size;
buf = args->buffer;
count = args->count;
args->bytes_moved = 0;
block = args->offset >> block_size_log2;
blkofs = args->offset & (block_size - 1);
while (count > 0)
{
bdbuf_buffer *diskbuf;
int copy;
if ((blkofs == 0) && (count > block_size))
rc = rtems_bdbuf_get(dev, block, &diskbuf);
else
rc = rtems_bdbuf_read(dev, block, &diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
copy = block_size - blkofs;
if (copy > count)
copy = count;
memcpy((char *)diskbuf->buffer + blkofs, buf, copy);
args->bytes_moved += copy;
rc = rtems_bdbuf_release_modified(diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
count -= copy;
buf += copy;
blkofs = 0;
block++;
}
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_open --
* Generic block device open primitive.
*/
rtems_device_driver
rtems_blkdev_generic_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
dd->uses++;
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_close --
* Generic block device close primitive.
*/
rtems_device_driver
rtems_blkdev_generic_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
dd->uses--;
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_ioctl --
* Generic block device ioctl primitive.
*/
rtems_device_driver
rtems_blkdev_generic_ioctl(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
rtems_libio_ioctl_args_t *args = arg;
dev_t dev;
disk_device *dd;
int rc;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
switch (args->command)
{
case BLKIO_GETBLKSIZE:
args->ioctl_return = dd->block_size;
break;
case BLKIO_GETSIZE:
args->ioctl_return = dd->size;
break;
case BLKIO_SYNCDEV:
rc = rtems_bdbuf_syncdev(dd->dev);
args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1);
break;
case BLKIO_REQUEST:
{
blkdev_request *req = args->buffer;
req->start += dd->start;
args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
req);
break;
}
default:
args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
args->buffer);
break;
}
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,631 @@
/*
* diskdevs.c - Physical and logical block devices (disks) support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <string.h>
#include "rtems/diskdevs.h"
#include "rtems/bdbuf.h"
#define DISKTAB_INITIAL_SIZE 32
/* Table of disk devices having the same major number */
struct disk_device_table {
disk_device **minor; /* minor-indexed disk device table */
int size; /* Number of entries in the table */
};
/* Pointer to [major].minor[minor] indexed array of disk devices */
static struct disk_device_table *disktab;
/* Number of allocated entries in disktab table */
static int disktab_size;
/* Mutual exclusion semaphore for disk devices table */
static rtems_id diskdevs_mutex;
/* Flag meaning that disk I/O, buffering etc. already has been initialized. */
static boolean disk_io_initialized = FALSE;
/* diskdevs data structures protection flag.
* Normally, only table lookup operations performed. It is quite fast, so
* it is possible to done lookups when interrupts are disabled, avoiding
* obtaining the semaphore. This flags sets immediately after entering in
* mutex-protected section and cleared before leaving this section in
* "big" primitives like add/delete new device etc. Lookup function first
* disable interrupts and check this flag. If it is set, lookup function
* will be blocked on semaphore and lookup operation will be performed in
* semaphore-protected code. If it is not set (very-very frequent case),
* we can do lookup safely, enable interrupts and return result.
*/
static volatile rtems_boolean diskdevs_protected;
/* create_disk_entry --
* Return pointer to the disk_entry structure for the specified device, or
* create one if it is not exists.
*
* PARAMETERS:
* dev - device id (major, minor)
*
* RETURNS:
* pointer to the disk device descirptor entry, or NULL if no memory
* available for its creation.
*/
static disk_device *
create_disk_entry(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device **d;
rtems_filesystem_split_dev_t (dev, major, minor);
if (major >= disktab_size)
{
struct disk_device_table *p;
int newsize;
int i;
newsize = disktab_size * 2;
if (major >= newsize)
newsize = major + 1;
p = realloc(disktab, sizeof(struct disk_device_table) * newsize);
if (p == NULL)
return NULL;
p += disktab_size;
for (i = disktab_size; i < newsize; i++, p++)
{
p->minor = NULL;
p->size = 0;
}
disktab_size = newsize;
}
if ((disktab[major].minor == NULL) ||
(minor >= disktab[major].size))
{
int newsize;
disk_device **p;
int i;
int s = disktab[major].size;
if (s == 0)
newsize = DISKTAB_INITIAL_SIZE;
else
newsize = s * 2;
if (minor >= newsize)
newsize = minor + 1;
p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize);
if (p == NULL)
return NULL;
disktab[major].minor = p;
p += s;
for (i = s; i < newsize; i++, p++)
*p = NULL;
disktab[major].size = newsize;
}
d = disktab[major].minor + minor;
if (*d == NULL)
{
*d = calloc(1, sizeof(disk_device));
}
return *d;
}
/* get_disk_entry --
* Get disk device descriptor by device number.
*
* PARAMETERS:
* dev - block device number
*
* RETURNS:
* Pointer to the disk device descriptor corresponding to the specified
* device number, or NULL if disk device with such number not exists.
*/
static inline disk_device *
get_disk_entry(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device_table *dtab;
rtems_filesystem_split_dev_t (dev, major, minor);
if ((major >= disktab_size) || (disktab == NULL))
return NULL;
dtab = disktab + major;
if ((minor >= dtab->size) || (dtab->minor == NULL))
return NULL;
return dtab->minor[minor];
}
/* create_disk --
* Check that disk entry for specified device number is not defined
* and create it.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* name - character name of device (e.g. /dev/hda)
* disdev - placeholder for pointer to created disk descriptor
*
* RETURNS:
* RTEMS_SUCCESSFUL if disk entry successfully created, or
* error code if error occured (device already registered,
* no memory available).
*/
static rtems_status_code
create_disk(dev_t dev, char *name, disk_device **diskdev)
{
disk_device *dd;
char *n;
dd = get_disk_entry(dev);
if (dd != NULL)
{
return RTEMS_RESOURCE_IN_USE;
}
if (name == NULL)
{
n = NULL;
}
else
{
int nlen = strlen(name) + 1;
n = malloc(nlen);
if (n == NULL)
return RTEMS_NO_MEMORY;
strncpy(n, name, nlen);
}
dd = create_disk_entry(dev);
if (dd == NULL)
{
free(n);
return RTEMS_NO_MEMORY;
}
dd->dev = dev;
dd->name = n;
*diskdev = dd;
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_create_phys --
* Create physical disk entry. This function usually invoked from
* block device driver initialization code when physical device
* detected in the system. Device driver should provide ioctl handler
* to allow block device access operations. This primitive will register
* device in rtems (invoke rtems_io_register_name).
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* block_size - size of disk block (minimum data transfer unit); must be
* power of 2
* disk_size - number of blocks on device
* handler - IOCTL handler (function providing basic block input/output
* request handling BIOREQUEST and other device management
* operations)
* name - character name of device (e.g. /dev/hda)
*
* RETURNS:
* RTEMS_SUCCESSFUL if information about new physical disk added, or
* error code if error occured (device already registered, wrong block
* size value, no memory available).
*/
rtems_status_code
rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
block_device_ioctl handler,
char *name)
{
int bs_log2;
int i;
disk_device *dd;
rtems_status_code rc;
rtems_bdpool_id pool;
rtems_device_major_number major;
rtems_device_minor_number minor;
rtems_filesystem_split_dev_t (dev, major, minor);
for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++);
if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */
return RTEMS_INVALID_NUMBER;
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
rc = rtems_bdbuf_find_pool(block_size, &pool);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
rc = create_disk(dev, name, &dd);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
dd->phys_dev = dd;
dd->uses = 0;
dd->start = 0;
dd->size = disk_size;
dd->block_size = block_size;
dd->block_size_log2 = bs_log2;
dd->ioctl = handler;
dd->pool = pool;
rc = rtems_io_register_name(name, major, minor);
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_create_log --
* Create logical disk entry. Logical disk is contiguous area on physical
* disk. Disk may be splitted to several logical disks in several ways:
* manually or using information stored in blocks on physical disk
* (DOS-like partition table, BSD disk label, etc). This function usually
* invoked from application when application-specific splitting are in use,
* or from generic code which handle different logical disk organizations.
* This primitive will register device in rtems (invoke
* rtems_io_register_name).
*
* PARAMETERS:
* dev - logical device identifier (major, minor numbers)
* phys - physical device (block device which holds this logical disk)
* identifier
* start - starting block number on the physical device
* size - logical disk size in blocks
* name - logical disk name
*
* RETURNS:
* RTEMS_SUCCESSFUL if logical device successfully added, or error code
* if error occured (device already registered, no physical device
* exists, logical disk is out of physical disk boundaries, no memory
* available).
*/
rtems_status_code
rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name)
{
disk_device *dd;
disk_device *pdd;
rtems_status_code rc;
rtems_device_major_number major;
rtems_device_minor_number minor;
rtems_filesystem_split_dev_t (dev, major, minor);
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
pdd = get_disk_entry(phys);
if (pdd == NULL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return RTEMS_INVALID_NUMBER;
}
rc = create_disk(dev, name, &dd);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
dd->phys_dev = pdd;
dd->uses = 0;
dd->start = start;
dd->size = size;
dd->block_size = pdd->block_size;
dd->block_size_log2 = pdd->block_size_log2;
dd->ioctl = pdd->ioctl;
rc = rtems_io_register_name(name, major, minor);
diskdevs_protected = FALSE;
rc = rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_delete --
* Delete physical or logical disk device. Device may be deleted if its
* use counter (and use counters of all logical devices - if it is
* physical device) equal to 0. When physical device deleted,
* all logical devices deleted inherently. Appropriate devices removed
* from "/dev" filesystem.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* RTEMS_SUCCESSFUL if block device successfully deleted, or error code
* if error occured (device is not defined, device is in use).
*/
rtems_status_code
rtems_disk_delete(dev_t dev)
{
rtems_status_code rc;
int used;
rtems_device_major_number maj;
rtems_device_minor_number min;
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
/* Check if this device is in use -- calculate usage counter */
used = 0;
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab + maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
if ((dd != NULL) && (dd->phys_dev->dev == dev))
used += dd->uses;
}
}
}
if (used != 0)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return RTEMS_RESOURCE_IN_USE;
}
/* Delete this device and all of its logical devices */
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab +maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
if ((dd != NULL) && (dd->phys_dev->dev == dev))
{
unlink(dd->name);
free(dd->name);
free(dd);
dtab->minor[min] = NULL;
}
}
}
}
diskdevs_protected = FALSE;
rc = rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_lookup --
* Find block device descriptor by its device identifier.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* pointer to the block device descriptor, or NULL if no such device
* exists.
*/
disk_device *
rtems_disk_lookup(dev_t dev)
{
rtems_interrupt_level level;
disk_device *dd;
rtems_status_code rc;
rtems_interrupt_disable(level);
if (diskdevs_protected)
{
rtems_interrupt_enable(level);
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return NULL;
diskdevs_protected = TRUE;
dd = get_disk_entry(dev);
dd->uses++;
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return dd;
}
else
{
/* Frequent and quickest case */
dd = get_disk_entry(dev);
dd->uses++;
rtems_interrupt_enable(level);
return dd;
}
}
/* rtems_disk_release --
* Release disk_device structure (decrement usage counter to 1).
*
* PARAMETERS:
* dd - pointer to disk device structure
*
* RETURNS:
* RTEMS_SUCCESSFUL
*/
rtems_status_code
rtems_disk_release(disk_device *dd)
{
rtems_interrupt_level level;
rtems_interrupt_disable(level);
dd->uses--;
rtems_interrupt_enable(level);
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_next --
* Disk device enumerator. Looking for device having device number larger
* than dev and return disk device descriptor for it. If there are no
* such device, NULL value returned.
*
* PARAMETERS:
* dev - device number (use -1 to start search)
*
* RETURNS:
* Pointer to the disk descriptor for next disk device, or NULL if all
* devices enumerated.
*/
disk_device *
rtems_disk_next(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device_table *dtab;
dev++;
rtems_filesystem_split_dev_t (dev, major, minor);
if (major >= disktab_size)
return NULL;
dtab = disktab + major;
while (TRUE)
{
if ((dtab == NULL) || (minor > dtab->size))
{
major++; minor = 0;
if (major >= disktab_size)
return NULL;
dtab = disktab + major;
}
else if (dtab->minor[minor] == NULL)
{
minor++;
}
else
return dtab->minor[minor];
}
}
/* rtems_disk_initialize --
* Initialization of disk device library (initialize all data structures,
* etc.)
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if library initialized, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_initialize(void)
{
rtems_status_code rc;
if (disk_io_initialized)
return RTEMS_SUCCESSFUL;
disktab_size = DISKTAB_INITIAL_SIZE;
disktab = calloc(disktab_size, sizeof(struct disk_device_table));
if (disktab == NULL)
return RTEMS_NO_MEMORY;
diskdevs_protected = FALSE;
rc = rtems_semaphore_create(
rtems_build_name('D', 'D', 'E', 'V'), 1,
RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
if (rc != RTEMS_SUCCESSFUL)
{
free(disktab);
return rc;
}
rc = rtems_bdbuf_init(rtems_bdbuf_configuration,
rtems_bdbuf_configuration_size);
if (rc != RTEMS_SUCCESSFUL)
{
rtems_semaphore_delete(diskdevs_mutex);
free(disktab);
return rc;
}
disk_io_initialized = 1;
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_io_done --
* Release all resources allocated for disk device interface.
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if all resources released, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_done(void)
{
rtems_device_major_number maj;
rtems_device_minor_number min;
rtems_status_code rc;
/* Free data structures */
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab + maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
unlink(dd->name);
free(dd->name);
free(dd);
}
free(dtab);
}
}
free(disktab);
rc = rtems_semaphore_release(diskdevs_mutex);
/* XXX bdbuf should be released too! */
disk_io_initialized = 0;
return rc;
}

View File

@@ -0,0 +1,224 @@
/* ramdisk.c -- RAM disk block device implementation
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "rtems/blkdev.h"
#include "rtems/diskdevs.h"
#include "rtems/ramdisk.h"
#define RAMDISK_DEVICE_BASE_NAME "/dev/ramdisk"
/* Internal RAM disk descriptor */
struct ramdisk {
int block_size; /* RAM disk block size */
int block_num; /* Number of blocks on this RAM disk */
void *area; /* RAM disk memory area */
rtems_boolean initialized;/* RAM disk is initialized */
rtems_boolean malloced; /* != 0, if memory allocated by malloc for this
RAM disk */
};
static struct ramdisk *ramdisk;
static int nramdisks;
/* ramdisk_read --
* RAM disk READ request handler. This primitive copies data from RAM
* disk to supplied buffer and invoke the callout function to inform
* upper layer that reading is completed.
*
* PARAMETERS:
* req - pointer to the READ block device request info
*
* RETURNS:
* ioctl return value
*/
static int
ramdisk_read(struct ramdisk *rd, blkdev_request *req)
{
char *from;
rtems_unsigned32 i;
blkdev_sg_buffer *sg;
rtems_unsigned32 remains;
from = (char *)rd->area + (req->start * rd->block_size);
remains = rd->block_size * req->count;
sg = req->bufs;
for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
{
int count = sg->length;
if (count > remains)
count = remains;
memcpy(sg->buffer, from, count);
remains -= count;
}
req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0);
return 0;
}
/* ramdisk_write --
* RAM disk WRITE request handler. This primitive copies data from
* supplied buffer to RAM disk and invoke the callout function to inform
* upper layer that writing is completed.
*
* PARAMETERS:
* req - pointer to the WRITE block device request info
*
* RETURNS:
* ioctl return value
*/
static int
ramdisk_write(struct ramdisk *rd, blkdev_request *req)
{
char *to;
rtems_unsigned32 i;
blkdev_sg_buffer *sg;
rtems_unsigned32 remains;
to = (char *)rd->area + (req->start * rd->block_size);
remains = rd->block_size * req->count;
sg = req->bufs;
for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
{
int count = sg->length;
if (count > remains)
count = remains;
memcpy(to, sg->buffer, count);
remains -= count;
}
req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0);
return 0;
}
/* ramdisk_ioctl --
* IOCTL handler for RAM disk device.
*
* PARAMETERS:
* dev - device number (major, minor number)
* req - IOCTL request code
* argp - IOCTL argument
*
* RETURNS:
* IOCTL return value
*/
static int
ramdisk_ioctl(dev_t dev, int req, void *argp)
{
switch (req)
{
case BLKIO_REQUEST:
{
rtems_device_minor_number minor;
blkdev_request *r = argp;
struct ramdisk *rd;
minor = rtems_filesystem_dev_minor_t(dev);
if ((minor >= nramdisks) || !ramdisk[minor].initialized)
{
errno = ENODEV;
return -1;
}
rd = ramdisk + minor;
switch (r->req)
{
case BLKDEV_REQ_READ:
return ramdisk_read(rd, r);
case BLKDEV_REQ_WRITE:
return ramdisk_write(rd, r);
default:
errno = EBADRQC;
return -1;
}
break;
}
default:
errno = EBADRQC;
return -1;
}
}
/* ramdisk_initialize --
* RAM disk device driver initialization. Run through RAM disk
* configuration information and configure appropriate RAM disks.
*
* PARAMETERS:
* major - RAM disk major device number
* minor - minor device number, not applicable
* arg - initialization argument, not applicable
*
* RETURNS:
* none
*/
rtems_device_driver
ramdisk_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_device_minor_number i;
rtems_ramdisk_config *c = rtems_ramdisk_configuration;
struct ramdisk *r;
rtems_status_code rc;
rc = rtems_disk_io_initialize();
if (rc != RTEMS_SUCCESSFUL)
return rc;
r = ramdisk = calloc(rtems_ramdisk_configuration_size,
sizeof(struct ramdisk));
for (i = 0; i < rtems_ramdisk_configuration_size; i++, c++, r++)
{
dev_t dev = rtems_filesystem_make_dev_t(major, i);
char name[sizeof(RAMDISK_DEVICE_BASE_NAME "0123456789")];
snprintf(name, sizeof(name), RAMDISK_DEVICE_BASE_NAME "%d", i);
r->block_size = c->block_size;
r->block_num = c->block_num;
if (c->location == NULL)
{
r->malloced = TRUE;
r->area = malloc(r->block_size * r->block_num);
if (r->area == NULL) /* No enough memory for this disk */
{
r->initialized = FALSE;
continue;
}
else
{
r->initialized = TRUE;
}
}
else
{
r->malloced = FALSE;
r->initialized = TRUE;
r->area = c->location;
}
rc = rtems_disk_create_phys(dev, c->block_size, c->block_num,
ramdisk_ioctl, name);
if (rc != RTEMS_SUCCESSFUL)
{
if (r->malloced)
{
free(r->area);
}
r->initialized = FALSE;
}
}
nramdisks = rtems_ramdisk_configuration_size;
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,14 @@
Makefile
Makefile.in
aclocal.m4
autom4te.cache
config.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
missing
mkinstalldirs

25
cpukit/libblock/ChangeLog Normal file
View File

@@ -0,0 +1,25 @@
2002-02-28 Joel Sherrill <joel@OARcorp.com>
* Submitted by Victor V. Vengerov <vvv@oktet.ru> and merged
into the RTEMS source.
* ChangeLog, Makefile.am, README, configure.ac, include/Makefile.am,
include/rtems/bdbuf.h, include/rtems/blkdev.h, include/rtems/diskdevs.h,
include/rtems/ramdisk.h, include/rtems/.cvsignore, include/.cvsignore,
src/Makefile.am, src/bdbuf.c, src/blkdev.c, src/diskdevs.c,
src/ramdisk.c, src/.cvsignore, .cvsignore: New files.
2001-11-29 Victor V. Vengerov <vvv@oktet.ru>
* AVL trees implementation added.
2001-11-16 Victor V. Vengerov <vvv@oktet.ru>
* include/rtems/bdbuf.h, src/bdbuf.c(rtems_bdbuf_syncdev): New.
2001-11-07 Victor V. Vengerov <vvv@oktet.ru>
* ChangeLog: New file.
* src/, include/, include/rtems/: New directories.
* README, configure.ac, Makefile.am, src/Makefile.am,
include/Makefile.am: New files.
* include/rtems/bdbuf.h include/rtems/blkdev.h
include/rtems/diskdevs.h include/rtems/ramdisk.h
src/bdbuf.c src/blkdev.c src/diskdevs.c src/ramdisk.c: New files.

View File

@@ -0,0 +1,13 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I ../../../aclocal
SUBDIRS = include src
EXTRA_DIST = README
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am

14
cpukit/libblock/README Normal file
View File

@@ -0,0 +1,14 @@
#
# $Id$
#
This directory contains the block device (HDD, CDROMs, etc) support code.
It includes:
- block device driver interface
- generic open/close/read/write/ioctl primitives for block device drivers
- disk I/O buffering
- logical disk support
- RAM disk block device driver
Victor V. Vengerov, <vvv@oktet.ru>
November, 7 2001

View File

@@ -0,0 +1,32 @@
## Process this file with autoconf to produce a configure script.
##
## $Id$
AC_PREREQ(2.52)
AC_INIT
AC_CONFIG_SRCDIR([src/bdbuf.c])
RTEMS_TOP(../../..)
AC_CONFIG_AUX_DIR(../../..)
RTEMS_CANONICAL_TARGET_CPU
RTEMS_CANONICAL_HOST
AM_INIT_AUTOMAKE(rtems-c-src-libblock,$RTEMS_VERSION,no)
AM_MAINTAINER_MODE
RTEMS_ENV_RTEMSBSP
RTEMS_CHECK_CPU
RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
RTEMS_PROG_CC_FOR_TARGET
RTEMS_ENABLE_BARE
RTEMS_CANONICALIZE_TOOLS
RTEMS_PROJECT_ROOT
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
include/Makefile
src/Makefile
])
AC_OUTPUT

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,282 @@
/* bdbuf.h -- block device buffer management
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_BDBUF_H__
#define __RTEMS_LIBBLOCK_BDBUF_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include <rtems/libio.h>
#include <chain.h>
#include "rtems/blkdev.h"
#include "rtems/diskdevs.h"
/*
* To manage buffers we using Buffer Descriptors.
* To speed-up buffer lookup descriptors are organized in AVL-Tree.
* The fields 'dev' and 'block' are search key.
*/
/* Buffer descriptors
* Descriptors organized in AVL-tree to speedup buffer lookup.
* dev and block fields are search key in AVL-tree.
* Modified buffers, free buffers and used buffers linked in 'mod', 'free' and
* 'lru' chains appropriately.
*/
typedef struct bdbuf_buffer {
Chain_Node link; /* Link in the lru, mod or free chains */
#ifdef BINARY_TREE
struct bdbuf_avl_node {
struct bdbuf_buffer *left; /* link to the left sub-tree */
struct bdbuf_buffer *right; /* link to the right sub-tree */
int bf; /* AVL tree node balance factor */
} avl; /* AVL-tree links */
#else /* AVL TREE */
struct bdbuf_avl_node {
char cache; /* Cache */
struct bdbuf_buffer* link[2]; /* Left and Right Kids */
char bal; /* The balance of the sub-tree */
} avl;
#endif
dev_t dev; /* device number */
blkdev_bnum block; /* block number on the device */
char *buffer; /* Pointer to the buffer memory area */
rtems_status_code status; /* Last I/O operation completion status */
int error; /* If status != RTEMS_SUCCESSFUL, this field contains
errno value which can be used by user later */
boolean modified:1; /* =1 if buffer was modified */
boolean in_progress:1; /* =1 if exchange with disk is in progress;
need to wait on semaphore */
boolean actual:1; /* Buffer contains actual data */
int use_count; /* Usage counter; incremented when somebody use
this buffer; decremented when buffer released
without modification or when buffer is flushed
by swapout task */
rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer
belongs */
CORE_mutex_Control transfer_sema;
/* Transfer operation semaphore */
} bdbuf_buffer;
/* bdbuf_config structure describes block configuration (size,
* amount, memory location) for buffering layer
*/
typedef struct rtems_bdbuf_config {
int size; /* Size of block */
int num; /* Number of blocks of appropriate size */
char *mem_area; /* Pointer to the blocks location or NULL, in this
case memory for blocks will be allocated by
Buffering Layer with the help of RTEMS partition
manager */
} rtems_bdbuf_config;
extern rtems_bdbuf_config rtems_bdbuf_configuration[];
extern int rtems_bdbuf_configuration_size;
/* rtems_bdbuf_init --
* Prepare buffering layer to work - initialize buffer descritors
* and (if it is neccessary) buffers. Buffers will be allocated accoriding
* to the configuration table, each entry describes kind of block and
* amount requested. After initialization all blocks is placed into
* free elements lists.
*
* PARAMETERS:
* conf_table - pointer to the buffers configuration table
* size - number of entries in configuration table
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*/
rtems_status_code
rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size);
/* rtems_bdbuf_get --
* Obtain block buffer. If specified block already cached (i.e. there's
* block in the _modified_, or _recently_used_), return address
* of appropriate buffer descriptor and increment reference counter to 1.
* If block is not cached, allocate new buffer and return it. Data
* shouldn't be read to the buffer from media; buffer may contains
* arbitrary data. This primitive may be blocked if there are no free
* buffer descriptors available and there are no unused non-modified
* (or synchronized with media) buffers available.
*
* PARAMETERS:
* device - device number (constructed of major and minor device number)
* block - linear media block number
* bd - address of variable to store pointer to the buffer descriptor
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* bufget_sema semaphore obtained by this primitive.
*/
rtems_status_code
rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
/* rtems_bdbuf_read --
* (Similar to the rtems_bdbuf_get, except reading data from media)
* Obtain block buffer. If specified block already cached, return address
* of appropriate buffer and increment reference counter to 1. If block is
* not cached, allocate new buffer and read data to it from the media.
* This primitive may be blocked on waiting until data to be read from
* media, if there are no free buffer descriptors available and there are
* no unused non-modified (or synchronized with media) buffers available.
*
* PARAMETERS:
* device - device number (consists of major and minor device number)
* block - linear media block number
* bd - address of variable to store pointer to the buffer descriptor
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* bufget_sema and transfer_sema semaphores obtained by this primitive.
*/
rtems_status_code
rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
/* rtems_bdbuf_release --
* Release buffer allocated before. This primitive decrease the
* usage counter. If it is zero, further destiny of buffer depends on
* 'modified' status. If buffer was modified, it is placed to the end of
* mod list and flush task waken up. If buffer was not modified,
* it is placed to the end of lru list, and bufget_sema released, allowing
* to reuse this buffer.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* flush_sema and bufget_sema semaphores may be released by this primitive.
*/
rtems_status_code
rtems_bdbuf_release(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_release_modified --
* Release buffer allocated before, assuming that it is _modified_ by
* it's owner. This primitive decrease usage counter for buffer, mark
* buffer descriptor as modified. If usage counter is 0, insert it at
* end of mod chain and release flush_sema semaphore to activate the
* flush task.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* flush_sema semaphore may be released by this primitive.
*/
rtems_status_code
rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_sync --
* Wait until specified buffer synchronized with disk. Invoked on exchanges
* critical for data consistency on the media. This primitive mark owned
* block as modified, decrease usage counter. If usage counter is 0,
* block inserted to the mod chain and flush_sema semaphore released.
* Finally, primitives blocked on transfer_sema semaphore.
*
* PARAMETERS:
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
* get/read primitive.
*
* RETURNS:
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
* or error code if error is occured)
*
* SIDE EFFECTS:
* Primitive may be blocked on transfer_sema semaphore.
*/
rtems_status_code
rtems_bdbuf_sync(bdbuf_buffer *bd_buf);
/* rtems_bdbuf_syncdev --
* Synchronize with disk all buffers containing the blocks belonging to
* specified device.
*
* PARAMETERS:
* dev - block device number
*
* RETURNS:
* 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);
/* rtems_bdbuf_find_pool --
* Find first appropriate buffer pool. This primitive returns the index
* of first buffer pool which block size is greater than or equal to
* specified size.
*
* PARAMETERS:
* block_size - requested block size
* pool - placeholder for result
*
* RETURNS:
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
* RTEMS_INVALID_SIZE if specified block size is invalid (not a power
* of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
* is not configured.
*/
rtems_status_code
rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool);
/* rtems_bdbuf_get_pool_info --
* Obtain characteristics of buffer pool with specified number.
*
* PARAMETERS:
* pool - buffer pool number
* block_size - block size for which buffer pool is configured returned
* there
* blocks - number of buffers in buffer pool returned there
*
* RETURNS:
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
* RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
*
* NOTE:
* Buffer pools enumerated contiguously starting from 0.
*/
rtems_status_code
rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,147 @@
/*
* blkdev.h - block device driver interface definitions
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_BLKDEV_H__
#define __RTEMS_LIBBLOCK_BLKDEV_H__
#include <rtems.h>
#include <sys/ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Interface with device drivers
* Block device looks, initialized and behaves like traditional RTEMS device
* driver. Heart of the block device driver is in BIOREQUEST ioctl. This call
* puts I/O request to the block device queue, in priority order, for
* asynchronous processing. When driver executes request, req_done
* function invoked, so callee knows about it. Look for details below.
*/
/* Block device block number datatype */
typedef rtems_unsigned32 blkdev_bnum;
/* Block device request type */
typedef enum blkdev_request_op {
BLKDEV_REQ_READ, /* Read operation */
BLKDEV_REQ_WRITE /* Write operation */
} blkdev_request_op;
/* Type for block device request done callback function.
*
* PARAMETERS:
* arg - argument supplied in blkdev_request
* status - rtems status code for this operation
* errno - errno value to be passed to the user when
* status != RTEMS_SUCCESSFUL
*/
typedef void (* blkdev_request_cb)(void *arg,
rtems_status_code status,
int error);
/* blkdev_sg_buffer
* Block device scatter/gather buffer structure
*/
typedef struct blkdev_sg_buffer {
rtems_unsigned32 length; /* Buffer length */
void *buffer; /* Buffer pointer */
} blkdev_sg_buffer;
/* blkdev_request (Block Device Request) structure is
* used to read/write a number of blocks from/to device.
*/
typedef struct blkdev_request {
blkdev_request_op req; /* Block device operation (read or write) */
blkdev_request_cb req_done; /* Callback function */
void *done_arg; /* Argument to be passed to callback function*/
blkdev_bnum start; /* Start block number */
rtems_unsigned32 count; /* Number of blocks to be exchanged */
rtems_unsigned32 bufnum; /* Number of buffers provided */
blkdev_sg_buffer bufs[0];/* List of scatter/gather buffers */
} blkdev_request;
/* Block device IOCTL request codes */
#define BLKIO_REQUEST _IOWR('B', 1, blkdev_request)
#define BLKIO_GETBLKSIZE _IO('B', 2)
#define BLKIO_GETSIZE _IO('B', 3)
#define BLKIO_SYNCDEV _IO('B', 4)
/* Device driver interface conventions suppose that driver may
* contain initialize/open/close/read/write/ioctl entry points. These
* primitives (except initialize) can be implemented in generic fashion,
* based upon supplied block device driver ioctl handler. Every block
* device driver should provide initialize entry point, which is register
* all block devices and appropriate ioctl handlers.
*/
#define 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
/* blkdev_generic_read --
* 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
);
/* blkdev_generic_write --
* Generic block device driver 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
);
/* blkdev_generic_open --
* Generic block device open primitive.
*/
rtems_device_driver
rtems_blkdev_generic_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
/* blkdev_generic_close --
* Generic block device close primitive.
*/
rtems_device_driver
rtems_blkdev_generic_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
/* blkdev_generic_ioctl --
* Generic block device ioctl primitive.
*/
rtems_device_driver
rtems_blkdev_generic_ioctl(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,206 @@
/*
* logdisk.h - Physical and logical block devices (disks) support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_LOGDISK_H__
#define __RTEMS_LIBBLOCK_LOGDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include "rtems/blkdev.h"
/* Buffer pool identifier */
typedef int rtems_bdpool_id;
/* Block device ioctl handler */
typedef int (* block_device_ioctl) (dev_t dev, int req, void *argp);
/* disk_device: Entry of this type created for every disk device (both for
* logical and physical disks).
* Array of arrays of pointers to disk_device structures maintained. First
* table indexed by major number and second table indexed by minor number.
* Such data organization allow quick lookup using data structure of
* moderated size.
*/
typedef struct disk_device {
dev_t dev; /* Device ID (major + minor) */
struct disk_device *phys_dev; /* Physical device ID (the same
as dev if this entry specifies
the physical device) */
char *name; /* Disk device name */
int uses; /* Use counter. Device couldn't be
removed if it is in use. */
int start; /* Starting block number (0 for
physical devices, block offset
on the related physical device
for logical device) */
int size; /* Size of physical or logical disk
in disk blocks */
int block_size; /* Size of device block (minimum
transfer unit) in bytes
(must be power of 2) */
int block_size_log2; /* log2 of block_size */
rtems_bdpool_id pool; /* Buffer pool assigned to this
device */
block_device_ioctl ioctl; /* ioctl handler for this block
device */
} disk_device;
/* rtems_disk_create_phys --
* Create physical disk entry. This function usually invoked from
* block device driver initialization code when physical device
* detected in the system. Device driver should provide ioctl handler
* to allow block device access operations. This primitive will register
* device in rtems (invoke rtems_io_register_name).
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* block_size - size of disk block (minimum data transfer unit); must be
* power of 2
* disk_size - number of blocks on device
* handler - IOCTL handler (function providing basic block input/output
* request handling BIOREQUEST and other device management
* operations)
* name - character name of device (e.g. /dev/hda)
*
* RETURNS:
* RTEMS_SUCCESSFUL if information about new physical disk added, or
* error code if error occured (device already registered, wrong block
* size value, no memory available).
*/
rtems_status_code
rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
block_device_ioctl handler,
char *name);
/* rtems_disk_create_log --
* Create logical disk entry. Logical disk is contiguous area on physical
* disk. Disk may be splitted to several logical disks in several ways:
* manually or using information stored in blocks on physical disk
* (DOS-like partition table, BSD disk label, etc). This function usually
* invoked from application when application-specific splitting are in use,
* or from generic code which handle different logical disk organizations.
* This primitive will register device in rtems (invoke
* rtems_io_register_name).
*
* PARAMETERS:
* dev - logical device identifier (major, minor numbers)
* phys - physical device (block device which holds this logical disk)
* identifier
* start - starting block number on the physical device
* size - logical disk size in blocks
* name - logical disk name
*
* RETURNS:
* RTEMS_SUCCESSFUL if logical device successfully added, or error code
* if error occured (device already registered, no physical device
* exists, logical disk is out of physical disk boundaries, no memory
* available).
*/
rtems_status_code
rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name);
/* rtems_disk_delete --
* Delete physical or logical disk device. Device may be deleted if its
* use counter (and use counters of all logical devices - if it is
* physical device) equal to 0. When physical device deleted,
* all logical devices deleted inherently. Appropriate devices removed
* from "/dev" filesystem.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* RTEMS_SUCCESSFUL if block device successfully deleted, or error code
* if error occured (device is not defined, device is in use).
*/
rtems_status_code
rtems_disk_delete(dev_t dev);
/* rtems_disk_lookup --
* Find block device descriptor by its device identifier. This function
* increment usage counter to 1. User should release disk_device structure
* by invoking rtems_disk_release primitive.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* pointer to the block device descriptor, or NULL if no such device
* exists.
*/
disk_device *
rtems_disk_lookup(dev_t dev);
/* rtems_disk_release --
* Release disk_device structure (decrement usage counter to 1).
*
* PARAMETERS:
* dd - pointer to disk device structure
*
* RETURNS:
* RTEMS_SUCCESSFUL
*
* NOTE:
* It should be implemented as inline function.
*/
rtems_status_code
rtems_disk_release(disk_device *dd);
/* rtems_disk_next --
* Disk device enumerator. Looking for device having device number larger
* than dev and return disk device descriptor for it. If there are no
* such device, NULL value returned.
*
* PARAMETERS:
* dev - device number (use -1 to start search)
*
* RETURNS:
* Pointer to the disk descriptor for next disk device, or NULL if all
* devices enumerated. */
disk_device *
rtems_disk_next(dev_t dev);
/* rtems_diskio_initialize --
* Initialization of disk device library (initialize all data structures,
* etc.)
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if library initialized, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_initialize(void);
/* rtems_diskio_done --
* Release all resources allocated for disk device interface.
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if all resources released, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_done(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,52 @@
/* ramdisk.c -- RAM disk block device implementation
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#ifndef __RTEMS_LIBBLOCK_RAMDISK_H__
#define __RTEMS_LIBBLOCK_RAMDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems.h>
#include "rtems/blkdev.h"
/* RAM disk configuration table entry */
typedef struct rtems_ramdisk_config {
int block_size; /* RAM disk block size */
int block_num; /* Number of blocks on this RAM disk */
void *location; /* RAM disk permanent location (out of RTEMS controlled
memory), or NULL if RAM disk memory should be
allocated dynamically */
} rtems_ramdisk_config;
/* If application want to use RAM disk, it should specify configuration of
* available RAM disks.
* The following is definitions for RAM disk configuration table
*/
extern rtems_ramdisk_config rtems_ramdisk_configuration[];
extern int rtems_ramdisk_configuration_size;
/* ramdisk_initialize --
* RAM disk driver initialization entry point.
*/
rtems_device_driver
ramdisk_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg);
#define RAMDISK_DRIVER_TABLE_ENTRY \
{ ramdisk_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@@ -0,0 +1,33 @@
##
## $Id$
##
AUTOMAKE_OPTIONS = foreign 1.5
LIBNAME = libblock
LIB = ${ARCH}/${LIBNAME}.a
C_FILES = bdbuf.c blkdev.c diskdevs.c ramdisk.c
C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
SRCS = $(C_FILES)
OBJS = $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../../../automake/compile.am
include $(top_srcdir)/../../../automake/lib.am
AM_CFLAGS += $(LIBC_DEFINES)
TMPINSTALL_FILES += $(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a
$(LIB): ${OBJS}
$(make-library)
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@
all-local: ${ARCH} $(PREINSTALL_FILES) $(TMPINSTALL_FILES)
include $(top_srcdir)/../../../automake/local.am

1876
cpukit/libblock/src/bdbuf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
/*
* blkdev.h - block device driver generic support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <sys/ioctl.h>
#include "rtems/diskdevs.h"
#include "rtems/bdbuf.h"
/* rtems_blkdev_generic_read --
* 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)
{
rtems_libio_rw_args_t *args = arg;
int block_size_log2;
int block_size;
char *buf;
unsigned int count;
unsigned int block;
unsigned int blkofs;
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
block_size_log2 = dd->block_size_log2;
block_size = dd->block_size;
buf = args->buffer;
count = args->count;
args->bytes_moved = 0;
block = args->offset >> block_size_log2;
blkofs = args->offset & (block_size - 1);
while (count > 0)
{
bdbuf_buffer *diskbuf;
int copy;
rtems_status_code rc;
rc = rtems_bdbuf_read(dev, block, &diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
copy = block_size - blkofs;
if (copy > count)
copy = count;
memcpy(buf, (char *)diskbuf->buffer + blkofs, copy);
rc = rtems_bdbuf_release(diskbuf);
args->bytes_moved += copy;
if (rc != RTEMS_SUCCESSFUL)
return rc;
count -= copy;
buf += copy;
blkofs = 0;
block++;
}
return RTEMS_SUCCESSFUL;
}
/* rtems_blkdev_generic_write --
* 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)
{
rtems_libio_rw_args_t *args = arg;
int block_size_log2;
int block_size;
char *buf;
unsigned int count;
unsigned int block;
unsigned int blkofs;
dev_t dev;
rtems_status_code rc;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
block_size_log2 = dd->block_size_log2;
block_size = dd->block_size;
buf = args->buffer;
count = args->count;
args->bytes_moved = 0;
block = args->offset >> block_size_log2;
blkofs = args->offset & (block_size - 1);
while (count > 0)
{
bdbuf_buffer *diskbuf;
int copy;
if ((blkofs == 0) && (count > block_size))
rc = rtems_bdbuf_get(dev, block, &diskbuf);
else
rc = rtems_bdbuf_read(dev, block, &diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
copy = block_size - blkofs;
if (copy > count)
copy = count;
memcpy((char *)diskbuf->buffer + blkofs, buf, copy);
args->bytes_moved += copy;
rc = rtems_bdbuf_release_modified(diskbuf);
if (rc != RTEMS_SUCCESSFUL)
return rc;
count -= copy;
buf += copy;
blkofs = 0;
block++;
}
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_open --
* Generic block device open primitive.
*/
rtems_device_driver
rtems_blkdev_generic_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
dd->uses++;
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_close --
* Generic block device close primitive.
*/
rtems_device_driver
rtems_blkdev_generic_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
dev_t dev;
disk_device *dd;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
dd->uses--;
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}
/* blkdev_generic_ioctl --
* Generic block device ioctl primitive.
*/
rtems_device_driver
rtems_blkdev_generic_ioctl(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
rtems_libio_ioctl_args_t *args = arg;
dev_t dev;
disk_device *dd;
int rc;
dev = rtems_filesystem_make_dev_t(major, minor);
dd = rtems_disk_lookup(dev);
if (dd == NULL)
return RTEMS_INVALID_NUMBER;
switch (args->command)
{
case BLKIO_GETBLKSIZE:
args->ioctl_return = dd->block_size;
break;
case BLKIO_GETSIZE:
args->ioctl_return = dd->size;
break;
case BLKIO_SYNCDEV:
rc = rtems_bdbuf_syncdev(dd->dev);
args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1);
break;
case BLKIO_REQUEST:
{
blkdev_request *req = args->buffer;
req->start += dd->start;
args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
req);
break;
}
default:
args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
args->buffer);
break;
}
rtems_disk_release(dd);
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,631 @@
/*
* diskdevs.c - Physical and logical block devices (disks) support
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <string.h>
#include "rtems/diskdevs.h"
#include "rtems/bdbuf.h"
#define DISKTAB_INITIAL_SIZE 32
/* Table of disk devices having the same major number */
struct disk_device_table {
disk_device **minor; /* minor-indexed disk device table */
int size; /* Number of entries in the table */
};
/* Pointer to [major].minor[minor] indexed array of disk devices */
static struct disk_device_table *disktab;
/* Number of allocated entries in disktab table */
static int disktab_size;
/* Mutual exclusion semaphore for disk devices table */
static rtems_id diskdevs_mutex;
/* Flag meaning that disk I/O, buffering etc. already has been initialized. */
static boolean disk_io_initialized = FALSE;
/* diskdevs data structures protection flag.
* Normally, only table lookup operations performed. It is quite fast, so
* it is possible to done lookups when interrupts are disabled, avoiding
* obtaining the semaphore. This flags sets immediately after entering in
* mutex-protected section and cleared before leaving this section in
* "big" primitives like add/delete new device etc. Lookup function first
* disable interrupts and check this flag. If it is set, lookup function
* will be blocked on semaphore and lookup operation will be performed in
* semaphore-protected code. If it is not set (very-very frequent case),
* we can do lookup safely, enable interrupts and return result.
*/
static volatile rtems_boolean diskdevs_protected;
/* create_disk_entry --
* Return pointer to the disk_entry structure for the specified device, or
* create one if it is not exists.
*
* PARAMETERS:
* dev - device id (major, minor)
*
* RETURNS:
* pointer to the disk device descirptor entry, or NULL if no memory
* available for its creation.
*/
static disk_device *
create_disk_entry(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device **d;
rtems_filesystem_split_dev_t (dev, major, minor);
if (major >= disktab_size)
{
struct disk_device_table *p;
int newsize;
int i;
newsize = disktab_size * 2;
if (major >= newsize)
newsize = major + 1;
p = realloc(disktab, sizeof(struct disk_device_table) * newsize);
if (p == NULL)
return NULL;
p += disktab_size;
for (i = disktab_size; i < newsize; i++, p++)
{
p->minor = NULL;
p->size = 0;
}
disktab_size = newsize;
}
if ((disktab[major].minor == NULL) ||
(minor >= disktab[major].size))
{
int newsize;
disk_device **p;
int i;
int s = disktab[major].size;
if (s == 0)
newsize = DISKTAB_INITIAL_SIZE;
else
newsize = s * 2;
if (minor >= newsize)
newsize = minor + 1;
p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize);
if (p == NULL)
return NULL;
disktab[major].minor = p;
p += s;
for (i = s; i < newsize; i++, p++)
*p = NULL;
disktab[major].size = newsize;
}
d = disktab[major].minor + minor;
if (*d == NULL)
{
*d = calloc(1, sizeof(disk_device));
}
return *d;
}
/* get_disk_entry --
* Get disk device descriptor by device number.
*
* PARAMETERS:
* dev - block device number
*
* RETURNS:
* Pointer to the disk device descriptor corresponding to the specified
* device number, or NULL if disk device with such number not exists.
*/
static inline disk_device *
get_disk_entry(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device_table *dtab;
rtems_filesystem_split_dev_t (dev, major, minor);
if ((major >= disktab_size) || (disktab == NULL))
return NULL;
dtab = disktab + major;
if ((minor >= dtab->size) || (dtab->minor == NULL))
return NULL;
return dtab->minor[minor];
}
/* create_disk --
* Check that disk entry for specified device number is not defined
* and create it.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* name - character name of device (e.g. /dev/hda)
* disdev - placeholder for pointer to created disk descriptor
*
* RETURNS:
* RTEMS_SUCCESSFUL if disk entry successfully created, or
* error code if error occured (device already registered,
* no memory available).
*/
static rtems_status_code
create_disk(dev_t dev, char *name, disk_device **diskdev)
{
disk_device *dd;
char *n;
dd = get_disk_entry(dev);
if (dd != NULL)
{
return RTEMS_RESOURCE_IN_USE;
}
if (name == NULL)
{
n = NULL;
}
else
{
int nlen = strlen(name) + 1;
n = malloc(nlen);
if (n == NULL)
return RTEMS_NO_MEMORY;
strncpy(n, name, nlen);
}
dd = create_disk_entry(dev);
if (dd == NULL)
{
free(n);
return RTEMS_NO_MEMORY;
}
dd->dev = dev;
dd->name = n;
*diskdev = dd;
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_create_phys --
* Create physical disk entry. This function usually invoked from
* block device driver initialization code when physical device
* detected in the system. Device driver should provide ioctl handler
* to allow block device access operations. This primitive will register
* device in rtems (invoke rtems_io_register_name).
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
* block_size - size of disk block (minimum data transfer unit); must be
* power of 2
* disk_size - number of blocks on device
* handler - IOCTL handler (function providing basic block input/output
* request handling BIOREQUEST and other device management
* operations)
* name - character name of device (e.g. /dev/hda)
*
* RETURNS:
* RTEMS_SUCCESSFUL if information about new physical disk added, or
* error code if error occured (device already registered, wrong block
* size value, no memory available).
*/
rtems_status_code
rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
block_device_ioctl handler,
char *name)
{
int bs_log2;
int i;
disk_device *dd;
rtems_status_code rc;
rtems_bdpool_id pool;
rtems_device_major_number major;
rtems_device_minor_number minor;
rtems_filesystem_split_dev_t (dev, major, minor);
for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++);
if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */
return RTEMS_INVALID_NUMBER;
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
rc = rtems_bdbuf_find_pool(block_size, &pool);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
rc = create_disk(dev, name, &dd);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
dd->phys_dev = dd;
dd->uses = 0;
dd->start = 0;
dd->size = disk_size;
dd->block_size = block_size;
dd->block_size_log2 = bs_log2;
dd->ioctl = handler;
dd->pool = pool;
rc = rtems_io_register_name(name, major, minor);
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_create_log --
* Create logical disk entry. Logical disk is contiguous area on physical
* disk. Disk may be splitted to several logical disks in several ways:
* manually or using information stored in blocks on physical disk
* (DOS-like partition table, BSD disk label, etc). This function usually
* invoked from application when application-specific splitting are in use,
* or from generic code which handle different logical disk organizations.
* This primitive will register device in rtems (invoke
* rtems_io_register_name).
*
* PARAMETERS:
* dev - logical device identifier (major, minor numbers)
* phys - physical device (block device which holds this logical disk)
* identifier
* start - starting block number on the physical device
* size - logical disk size in blocks
* name - logical disk name
*
* RETURNS:
* RTEMS_SUCCESSFUL if logical device successfully added, or error code
* if error occured (device already registered, no physical device
* exists, logical disk is out of physical disk boundaries, no memory
* available).
*/
rtems_status_code
rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name)
{
disk_device *dd;
disk_device *pdd;
rtems_status_code rc;
rtems_device_major_number major;
rtems_device_minor_number minor;
rtems_filesystem_split_dev_t (dev, major, minor);
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
pdd = get_disk_entry(phys);
if (pdd == NULL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return RTEMS_INVALID_NUMBER;
}
rc = create_disk(dev, name, &dd);
if (rc != RTEMS_SUCCESSFUL)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return rc;
}
dd->phys_dev = pdd;
dd->uses = 0;
dd->start = start;
dd->size = size;
dd->block_size = pdd->block_size;
dd->block_size_log2 = pdd->block_size_log2;
dd->ioctl = pdd->ioctl;
rc = rtems_io_register_name(name, major, minor);
diskdevs_protected = FALSE;
rc = rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_delete --
* Delete physical or logical disk device. Device may be deleted if its
* use counter (and use counters of all logical devices - if it is
* physical device) equal to 0. When physical device deleted,
* all logical devices deleted inherently. Appropriate devices removed
* from "/dev" filesystem.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* RTEMS_SUCCESSFUL if block device successfully deleted, or error code
* if error occured (device is not defined, device is in use).
*/
rtems_status_code
rtems_disk_delete(dev_t dev)
{
rtems_status_code rc;
int used;
rtems_device_major_number maj;
rtems_device_minor_number min;
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return rc;
diskdevs_protected = TRUE;
/* Check if this device is in use -- calculate usage counter */
used = 0;
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab + maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
if ((dd != NULL) && (dd->phys_dev->dev == dev))
used += dd->uses;
}
}
}
if (used != 0)
{
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return RTEMS_RESOURCE_IN_USE;
}
/* Delete this device and all of its logical devices */
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab +maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
if ((dd != NULL) && (dd->phys_dev->dev == dev))
{
unlink(dd->name);
free(dd->name);
free(dd);
dtab->minor[min] = NULL;
}
}
}
}
diskdevs_protected = FALSE;
rc = rtems_semaphore_release(diskdevs_mutex);
return rc;
}
/* rtems_disk_lookup --
* Find block device descriptor by its device identifier.
*
* PARAMETERS:
* dev - device identifier (major, minor numbers)
*
* RETURNS:
* pointer to the block device descriptor, or NULL if no such device
* exists.
*/
disk_device *
rtems_disk_lookup(dev_t dev)
{
rtems_interrupt_level level;
disk_device *dd;
rtems_status_code rc;
rtems_interrupt_disable(level);
if (diskdevs_protected)
{
rtems_interrupt_enable(level);
rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
RTEMS_NO_TIMEOUT);
if (rc != RTEMS_SUCCESSFUL)
return NULL;
diskdevs_protected = TRUE;
dd = get_disk_entry(dev);
dd->uses++;
diskdevs_protected = FALSE;
rtems_semaphore_release(diskdevs_mutex);
return dd;
}
else
{
/* Frequent and quickest case */
dd = get_disk_entry(dev);
dd->uses++;
rtems_interrupt_enable(level);
return dd;
}
}
/* rtems_disk_release --
* Release disk_device structure (decrement usage counter to 1).
*
* PARAMETERS:
* dd - pointer to disk device structure
*
* RETURNS:
* RTEMS_SUCCESSFUL
*/
rtems_status_code
rtems_disk_release(disk_device *dd)
{
rtems_interrupt_level level;
rtems_interrupt_disable(level);
dd->uses--;
rtems_interrupt_enable(level);
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_next --
* Disk device enumerator. Looking for device having device number larger
* than dev and return disk device descriptor for it. If there are no
* such device, NULL value returned.
*
* PARAMETERS:
* dev - device number (use -1 to start search)
*
* RETURNS:
* Pointer to the disk descriptor for next disk device, or NULL if all
* devices enumerated.
*/
disk_device *
rtems_disk_next(dev_t dev)
{
rtems_device_major_number major;
rtems_device_minor_number minor;
struct disk_device_table *dtab;
dev++;
rtems_filesystem_split_dev_t (dev, major, minor);
if (major >= disktab_size)
return NULL;
dtab = disktab + major;
while (TRUE)
{
if ((dtab == NULL) || (minor > dtab->size))
{
major++; minor = 0;
if (major >= disktab_size)
return NULL;
dtab = disktab + major;
}
else if (dtab->minor[minor] == NULL)
{
minor++;
}
else
return dtab->minor[minor];
}
}
/* rtems_disk_initialize --
* Initialization of disk device library (initialize all data structures,
* etc.)
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if library initialized, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_initialize(void)
{
rtems_status_code rc;
if (disk_io_initialized)
return RTEMS_SUCCESSFUL;
disktab_size = DISKTAB_INITIAL_SIZE;
disktab = calloc(disktab_size, sizeof(struct disk_device_table));
if (disktab == NULL)
return RTEMS_NO_MEMORY;
diskdevs_protected = FALSE;
rc = rtems_semaphore_create(
rtems_build_name('D', 'D', 'E', 'V'), 1,
RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
if (rc != RTEMS_SUCCESSFUL)
{
free(disktab);
return rc;
}
rc = rtems_bdbuf_init(rtems_bdbuf_configuration,
rtems_bdbuf_configuration_size);
if (rc != RTEMS_SUCCESSFUL)
{
rtems_semaphore_delete(diskdevs_mutex);
free(disktab);
return rc;
}
disk_io_initialized = 1;
return RTEMS_SUCCESSFUL;
}
/* rtems_disk_io_done --
* Release all resources allocated for disk device interface.
*
* PARAMETERS:
* none
*
* RETURNS:
* RTEMS_SUCCESSFUL if all resources released, or error code if error
* occured.
*/
rtems_status_code
rtems_disk_io_done(void)
{
rtems_device_major_number maj;
rtems_device_minor_number min;
rtems_status_code rc;
/* Free data structures */
for (maj = 0; maj < disktab_size; maj++)
{
struct disk_device_table *dtab = disktab + maj;
if (dtab != NULL)
{
for (min = 0; min < dtab->size; min++)
{
disk_device *dd = dtab->minor[min];
unlink(dd->name);
free(dd->name);
free(dd);
}
free(dtab);
}
}
free(disktab);
rc = rtems_semaphore_release(diskdevs_mutex);
/* XXX bdbuf should be released too! */
disk_io_initialized = 0;
return rc;
}

View File

@@ -0,0 +1,224 @@
/* ramdisk.c -- RAM disk block device implementation
*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* @(#) $Id$
*/
#include <rtems.h>
#include <rtems/libio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "rtems/blkdev.h"
#include "rtems/diskdevs.h"
#include "rtems/ramdisk.h"
#define RAMDISK_DEVICE_BASE_NAME "/dev/ramdisk"
/* Internal RAM disk descriptor */
struct ramdisk {
int block_size; /* RAM disk block size */
int block_num; /* Number of blocks on this RAM disk */
void *area; /* RAM disk memory area */
rtems_boolean initialized;/* RAM disk is initialized */
rtems_boolean malloced; /* != 0, if memory allocated by malloc for this
RAM disk */
};
static struct ramdisk *ramdisk;
static int nramdisks;
/* ramdisk_read --
* RAM disk READ request handler. This primitive copies data from RAM
* disk to supplied buffer and invoke the callout function to inform
* upper layer that reading is completed.
*
* PARAMETERS:
* req - pointer to the READ block device request info
*
* RETURNS:
* ioctl return value
*/
static int
ramdisk_read(struct ramdisk *rd, blkdev_request *req)
{
char *from;
rtems_unsigned32 i;
blkdev_sg_buffer *sg;
rtems_unsigned32 remains;
from = (char *)rd->area + (req->start * rd->block_size);
remains = rd->block_size * req->count;
sg = req->bufs;
for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
{
int count = sg->length;
if (count > remains)
count = remains;
memcpy(sg->buffer, from, count);
remains -= count;
}
req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0);
return 0;
}
/* ramdisk_write --
* RAM disk WRITE request handler. This primitive copies data from
* supplied buffer to RAM disk and invoke the callout function to inform
* upper layer that writing is completed.
*
* PARAMETERS:
* req - pointer to the WRITE block device request info
*
* RETURNS:
* ioctl return value
*/
static int
ramdisk_write(struct ramdisk *rd, blkdev_request *req)
{
char *to;
rtems_unsigned32 i;
blkdev_sg_buffer *sg;
rtems_unsigned32 remains;
to = (char *)rd->area + (req->start * rd->block_size);
remains = rd->block_size * req->count;
sg = req->bufs;
for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++)
{
int count = sg->length;
if (count > remains)
count = remains;
memcpy(to, sg->buffer, count);
remains -= count;
}
req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0);
return 0;
}
/* ramdisk_ioctl --
* IOCTL handler for RAM disk device.
*
* PARAMETERS:
* dev - device number (major, minor number)
* req - IOCTL request code
* argp - IOCTL argument
*
* RETURNS:
* IOCTL return value
*/
static int
ramdisk_ioctl(dev_t dev, int req, void *argp)
{
switch (req)
{
case BLKIO_REQUEST:
{
rtems_device_minor_number minor;
blkdev_request *r = argp;
struct ramdisk *rd;
minor = rtems_filesystem_dev_minor_t(dev);
if ((minor >= nramdisks) || !ramdisk[minor].initialized)
{
errno = ENODEV;
return -1;
}
rd = ramdisk + minor;
switch (r->req)
{
case BLKDEV_REQ_READ:
return ramdisk_read(rd, r);
case BLKDEV_REQ_WRITE:
return ramdisk_write(rd, r);
default:
errno = EBADRQC;
return -1;
}
break;
}
default:
errno = EBADRQC;
return -1;
}
}
/* ramdisk_initialize --
* RAM disk device driver initialization. Run through RAM disk
* configuration information and configure appropriate RAM disks.
*
* PARAMETERS:
* major - RAM disk major device number
* minor - minor device number, not applicable
* arg - initialization argument, not applicable
*
* RETURNS:
* none
*/
rtems_device_driver
ramdisk_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_device_minor_number i;
rtems_ramdisk_config *c = rtems_ramdisk_configuration;
struct ramdisk *r;
rtems_status_code rc;
rc = rtems_disk_io_initialize();
if (rc != RTEMS_SUCCESSFUL)
return rc;
r = ramdisk = calloc(rtems_ramdisk_configuration_size,
sizeof(struct ramdisk));
for (i = 0; i < rtems_ramdisk_configuration_size; i++, c++, r++)
{
dev_t dev = rtems_filesystem_make_dev_t(major, i);
char name[sizeof(RAMDISK_DEVICE_BASE_NAME "0123456789")];
snprintf(name, sizeof(name), RAMDISK_DEVICE_BASE_NAME "%d", i);
r->block_size = c->block_size;
r->block_num = c->block_num;
if (c->location == NULL)
{
r->malloced = TRUE;
r->area = malloc(r->block_size * r->block_num);
if (r->area == NULL) /* No enough memory for this disk */
{
r->initialized = FALSE;
continue;
}
else
{
r->initialized = TRUE;
}
}
else
{
r->malloced = FALSE;
r->initialized = TRUE;
r->area = c->location;
}
rc = rtems_disk_create_phys(dev, c->block_size, c->block_num,
ramdisk_ioctl, name);
if (rc != RTEMS_SUCCESSFUL)
{
if (r->malloced)
{
free(r->area);
}
r->initialized = FALSE;
}
}
nramdisks = rtems_ramdisk_configuration_size;
return RTEMS_SUCCESSFUL;
}