aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authorbarthess <barthess@yandex.ru>2016-10-17 09:57:43 +0300
committerbarthess <barthess@yandex.ru>2016-10-17 15:53:08 +0300
commitae0a3ca9dec6d14b82f08a6eebc679281dd3fbb3 (patch)
tree56aa825e721dcfddc6b2f0490907c95094439d18 /os
parentcc82c5c5c033fd12bd7f4733f2e57d17efd87315 (diff)
downloadChibiOS-Contrib-ae0a3ca9dec6d14b82f08a6eebc679281dd3fbb3.tar.gz
ChibiOS-Contrib-ae0a3ca9dec6d14b82f08a6eebc679281dd3fbb3.tar.bz2
ChibiOS-Contrib-ae0a3ca9dec6d14b82f08a6eebc679281dd3fbb3.zip
USB_MSD. Initial commit.
Diffstat (limited to 'os')
-rw-r--r--os/hal/hal.mk3
-rw-r--r--os/hal/include/hal_community.h5
-rw-r--r--os/hal/include/hal_onewire.h1
-rw-r--r--os/hal/include/hal_usb_msd.h192
-rw-r--r--os/hal/src/hal_usb_msd.c386
-rw-r--r--os/various/lib_scsi.c466
-rw-r--r--os/various/lib_scsi.h267
-rw-r--r--os/various/ramdisk.c219
-rw-r--r--os/various/ramdisk.h86
9 files changed, 1623 insertions, 2 deletions
diff --git a/os/hal/hal.mk b/os/hal/hal.mk
index ce74620..f05ddbc 100644
--- a/os/hal/hal.mk
+++ b/os/hal/hal.mk
@@ -18,6 +18,7 @@ HALSRC += ${CHIBIOS_CONTRIB}/os/hal/src/hal_community.c \
${CHIBIOS_CONTRIB}/os/hal/src/hal_eeprom.c \
${CHIBIOS_CONTRIB}/os/hal/src/hal_timcap.c \
${CHIBIOS_CONTRIB}/os/hal/src/hal_qei.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/hal_usb_hid.c
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_usb_hid.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_usb_msd.c
HALINC += ${CHIBIOS_CONTRIB}/os/hal/include
diff --git a/os/hal/include/hal_community.h b/os/hal/include/hal_community.h
index 1518c7e..430df7c 100644
--- a/os/hal/include/hal_community.h
+++ b/os/hal/include/hal_community.h
@@ -67,6 +67,10 @@
#define HAL_USE_USB_HID FALSE
#endif
+#if !defined(HAL_USE_USB_MSD)
+#define HAL_USE_USB_MSD FALSE
+#endif
+
/* Abstract interfaces.*/
/* Shared headers.*/
@@ -84,6 +88,7 @@
#include "hal_crc.h"
#include "hal_eeprom.h"
#include "hal_usb_hid.h"
+#include "hal_usb_msd.h"
/*===========================================================================*/
/* Driver constants. */
diff --git a/os/hal/include/hal_onewire.h b/os/hal/include/hal_onewire.h
index 9fb5be2..0454212 100644
--- a/os/hal/include/hal_onewire.h
+++ b/os/hal/include/hal_onewire.h
@@ -328,7 +328,6 @@ extern onewireDriver OWD1;
#ifdef __cplusplus
extern "C" {
#endif
- void onewireInit(void);
void onewireObjectInit(onewireDriver *owp);
void onewireStart(onewireDriver *owp, const onewireConfig *config);
void onewireStop(onewireDriver *owp);
diff --git a/os/hal/include/hal_usb_msd.h b/os/hal/include/hal_usb_msd.h
new file mode 100644
index 0000000..08241df
--- /dev/null
+++ b/os/hal/include/hal_usb_msd.h
@@ -0,0 +1,192 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_usb_msd.h
+ * @brief USM mass storage device driver macros and structures.
+ *
+ * @addtogroup usb_msd
+ * @{
+ */
+
+#ifndef HAL_USB_MSD_H
+#define HAL_USB_MSD_H
+
+#if (HAL_USE_USB_MSD == TRUE) || defined(__DOXYGEN__)
+
+#include "lib_scsi.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define USB_MSD_DATA_EP 0x01
+#define USB_MSD_EP_SIZE 0x40
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !HAL_USE_USB
+#error "Mass storage Driver requires HAL_USE_USB"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an USB mass storage driver.
+ */
+typedef struct USBMassStorageDriver USBMassStorageDriver;
+
+/**
+ * @brief Type of a driver state machine possible states.
+ */
+typedef enum {
+ USB_MSD_UNINIT = 0,
+ USB_MSD_STOP,
+ USB_MSD_READY,
+} usbmsdstate_t;
+
+/**
+ * @brief Represents command block wrapper structure.
+ * @details See USB Mass Storage Class Specification.
+ */
+typedef struct PACKED_VAR {
+ uint32_t signature;
+ uint32_t tag;
+ uint32_t data_len;
+ uint8_t flags;
+ uint8_t lun;
+ uint8_t cmd_len;
+ uint8_t cmd_data[16];
+} msd_cbw_t;
+
+/**
+ * @brief Represents command status wrapper structure.
+ * @details See USB Mass Storage Class Specification.
+ */
+typedef struct PACKED_VAR {
+ uint32_t signature;
+ uint32_t tag;
+ uint32_t data_residue;
+ uint8_t status;
+} msd_csw_t;
+
+/**
+ * @brief Transport handler passed to SCSI layer.
+ */
+typedef struct {
+ /**
+ * @brief Pointer to the @p USBDriver object.
+ */
+ USBDriver *usbp;
+ /**
+ * @brief USB endpoint number.
+ */
+ usbep_t ep;
+} usb_scsi_transport_handler_t;
+
+
+/**
+ * @brief Structure representing an USB mass storage driver.
+ */
+struct USBMassStorageDriver {
+ /**
+ * @brief Pointer to the @p USBDriver object.
+ */
+ USBDriver *usbp;
+ /**
+ * @brief Driver state.
+ */
+ usbmsdstate_t state;
+ /**
+ * @brief CBW structure.
+ */
+ msd_cbw_t cbw;
+ /**
+ * @brief CSW structure.
+ */
+ msd_csw_t csw;
+ /**
+ * @brief Thread working area.
+ */
+ THD_WORKING_AREA( waMSDWorker, 512);
+ /**
+ * @brief Worker thread handler.
+ */
+ thread_reference_t worker;
+ /**
+ * @brief SCSI target driver structure.
+ */
+ SCSITarget scsi_target;
+ /**
+ * @brief SCSI target configuration structure.
+ */
+ SCSITargetConfig scsi_config;
+ /**
+ * @brief SCSI transport structure.
+ */
+ SCSITransport scsi_transport;
+ /**
+ * @brief SCSI over USB transport handler structure.
+ */
+ usb_scsi_transport_handler_t usb_scsi_transport_handler;
+};
+
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+extern USBMassStorageDriver USBMSD1;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void msdObjectInit(USBMassStorageDriver *msdp);
+ void msdStart(USBMassStorageDriver *msdp, USBDriver *usbp,
+ BaseBlockDevice *blkdev, uint8_t *blkbuf,
+ const scsi_inquiry_response_t *scsi_inquiry_response);
+ void msdStop(USBMassStorageDriver *msdp);
+ bool msd_request_hook(USBDriver *usbp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_USB_MSD */
+
+#endif /* HAL_USB_MSD_H */
+
+/** @} */
+
+
+
+
+
+
+
+
+
diff --git a/os/hal/src/hal_usb_msd.c b/os/hal/src/hal_usb_msd.c
new file mode 100644
index 0000000..14f1165
--- /dev/null
+++ b/os/hal/src/hal_usb_msd.c
@@ -0,0 +1,386 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_usb_msd.c
+ * @brief USM mass storage device code.
+ *
+ * @addtogroup usb_msd
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_USB_MSD == TRUE) || defined(__DOXYGEN__)
+
+#include <string.h>
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define MSD_REQ_RESET 0xFF
+#define MSD_GET_MAX_LUN 0xFE
+
+#define MSD_CBW_SIGNATURE 0x43425355
+#define MSD_CSW_SIGNATURE 0x53425355
+
+#define MSD_THD_PRIO NORMALPRIO
+
+#define CBW_FLAGS_RESERVED_MASK 0b01111111
+#define CBW_LUN_RESERVED_MASK 0b11110000
+#define CBW_CMD_LEN_RESERVED_MASK 0b11000000
+
+#define CSW_STATUS_PASSED 0x00
+#define CSW_STATUS_FAILED 0x01
+#define CSW_STATUS_PHASE_ERROR 0x02
+
+#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index+1] << 8)\
+ | (setup[index] & 0x00FF))
+
+#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2)
+#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4)
+#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+/**
+ * @brief USB mass storage driver identifier.
+ */
+USBMassStorageDriver USBMSD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Hardcoded default SCSI inquiry response structure.
+ */
+static const scsi_inquiry_response_t default_scsi_inquiry_response = {
+ 0x00, /* direct access block device */
+ 0x80, /* removable */
+ 0x04, /* SPC-2 */
+ 0x02, /* response data format */
+ 0x20, /* response has 0x20 + 4 bytes */
+ 0x00,
+ 0x00,
+ 0x00,
+ "Chibios",
+ "Mass Storage",
+ {'v',CH_KERNEL_MAJOR+'0','.',CH_KERNEL_MINOR+'0'}
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+
+ */
+/**
+ * @brief Checks validity of CBW content.
+ * @details The device shall consider the CBW valid when:
+ * • The CBW was received after the device had sent a CSW or after a reset,
+ * • the CBW is 31 (1Fh) bytes in length,
+ * • and the dCBWSignature is equal to 43425355h.
+ *
+ * @param[in] cbw pointer to the @p msd_cbw_t object
+ * @param[in] recvd number of received bytes
+ *
+ * @return Operation status.
+ * @retval true CBW is meaningful.
+ * @retval false CBW is bad.
+ *
+ * @notapi
+ */
+static bool cbw_valid(const msd_cbw_t *cbw, msg_t recvd) {
+ if ((sizeof(msd_cbw_t) != recvd) || (cbw->signature != MSD_CBW_SIGNATURE)) {
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+/**
+ * @brief Checks meaningfulness of CBW content.
+ * @details The device shall consider the contents of a valid CBW meaningful when:
+ * • no reserved bits are set,
+ * • the bCBWLUN contains a valid LUN supported by the device,
+ * • and both bCBWCBLength and the content of the CBWCB are in
+ * accordance with bInterfaceSubClass.
+ *
+ * @param[in] cbw pointer to the @p msd_cbw_t object
+ *
+ * @return Operation status.
+ * @retval true CBW is meaningful.
+ * @retval false CBW is bad.
+ *
+ * @notapi
+ */
+static bool cbw_meaningful(const msd_cbw_t *cbw) {
+ if (((cbw->cmd_len & CBW_CMD_LEN_RESERVED_MASK) != 0)
+ || ((cbw->flags & CBW_FLAGS_RESERVED_MASK) != 0)
+ || (cbw->lun != 0)) {
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+/**
+ * @brief SCSI transport transmit function.
+ *
+ * @param[in] transport pointer to the @p SCSITransport object
+ * @param[in] data payload
+ * @param[in] len number of bytes to be transmitted
+ *
+ * @return Number of successfully transmitted bytes.
+
+ * @notapi
+ */
+static uint32_t scsi_transport_transmit(const SCSITransport *transport,
+ const uint8_t *data, size_t len) {
+
+ usb_scsi_transport_handler_t *trp = transport->handler;
+ msg_t status = usbTransmit(trp->usbp, trp->ep, data, len);
+ if (MSG_OK == status)
+ return len;
+ else
+ return 0;
+}
+
+/**
+ * @brief SCSI transport receive function.
+ *
+ * @param[in] transport pointer to the @p SCSITransport object
+ * @param[in] data payload
+ * @param[in] len number bytes to be received
+ *
+ * @return Number of successfully received bytes.
+
+ * @notapi
+ */
+static uint32_t scsi_transport_receive(const SCSITransport *transport,
+ uint8_t *data, size_t len) {
+
+ usb_scsi_transport_handler_t *trp = transport->handler;
+ msg_t status = usbReceive(trp->usbp, trp->ep, data, len);
+ if (MSG_RESET != status)
+ return status;
+ else
+ return 0;
+}
+
+/**
+ * @brief Fills and sends CSW message.
+ *
+ * @param[in] msdp pointer to the @p USBMassStorageDriver object
+ * @param[in] status status returned by SCSI layer
+ * @param[in] residue number of residue bytes in case of failed transaction
+ *
+ * @notapi
+ */
+static void send_csw(USBMassStorageDriver *msdp, uint8_t status,
+ uint32_t residue) {
+
+ msdp->csw.signature = MSD_CSW_SIGNATURE;
+ msdp->csw.data_residue = residue;
+ msdp->csw.tag = msdp->cbw.tag;
+ msdp->csw.status = status;
+
+ usbTransmit(msdp->usbp, USB_MSD_DATA_EP, (uint8_t *)&msdp->csw,
+ sizeof(msd_csw_t));
+}
+
+/**
+ * @brief Mass storage worker thread.
+ *
+ * @param[in] arg pointer to the @p USBMassStorageDriver object
+ *
+ * @notapi
+ */
+static THD_FUNCTION(usb_msd_worker, arg) {
+ USBMassStorageDriver *msdp = arg;
+
+ while(! chThdShouldTerminateX()) {
+ const msg_t status = usbReceive(msdp->usbp, USB_MSD_DATA_EP,
+ (uint8_t *)&msdp->cbw, sizeof(msd_cbw_t));
+ if (MSG_RESET == status) {
+ osalThreadSleepMilliseconds(50);
+ }
+ else if (cbw_valid(&msdp->cbw, status) && cbw_meaningful(&msdp->cbw)) {
+ if (SCSI_SUCCESS == scsiExecCmd(&msdp->scsi_target, msdp->cbw.cmd_data)) {
+ send_csw(msdp, CSW_STATUS_PASSED, 0);
+ }
+ else {
+ send_csw(msdp, CSW_STATUS_FAILED, scsiResidue(&msdp->scsi_target));
+ }
+ }
+ else {
+ ; /* do NOT send CSW here. Incorrect CBW must be silently ignored */
+ }
+ }
+
+ chThdExit(MSG_OK);
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Mass storage specific request hook for USB.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+bool msd_request_hook(USBDriver *usbp) {
+
+ if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
+ ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
+ /* check that the request is for interface 0.*/
+ if (MSD_SETUP_INDEX(usbp->setup) != 0)
+ return false;
+
+ /* act depending on bRequest = setup[1] */
+ switch(usbp->setup[1]) {
+ case MSD_REQ_RESET:
+ /* check that it is a HOST2DEV request */
+ if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) ||
+ (MSD_SETUP_LENGTH(usbp->setup) != 0) ||
+ (MSD_SETUP_VALUE(usbp->setup) != 0))
+ return false;
+
+ /* reset all endpoints */
+ /* TODO!*/
+ /* The device shall NAK the status stage of the device request until
+ * the Bulk-Only Mass Storage Reset is complete.
+ */
+ return true;
+
+ case MSD_GET_MAX_LUN:
+ /* check that it is a DEV2HOST request */
+ if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) ||
+ (MSD_SETUP_LENGTH(usbp->setup) != 1) ||
+ (MSD_SETUP_VALUE(usbp->setup) != 0))
+ return false;
+
+ /* stall to indicate that we don't support LUN */
+ osalSysLockFromISR();
+ usbStallTransmitI(usbp, 0);
+ osalSysUnlockFromISR();
+ return true;
+
+ default:
+ return false;
+ break;
+ }
+ }
+ return false;
+}
+
+/**
+ * @brief Initializes the standard part of a @p USBMassStorageDriver structure.
+ *
+ * @param[out] msdp pointer to the @p USBMassStorageDriver object
+ *
+ * @init
+ */
+void msdObjectInit(USBMassStorageDriver *msdp) {
+
+ memset(msdp, 0x55, sizeof(USBMassStorageDriver));
+ msdp->state = USB_MSD_STOP;
+ msdp->usbp = NULL;
+ msdp->worker = NULL;
+
+ scsiObjectInit(&msdp->scsi_target);
+}
+
+/**
+ * @brief Stops the USB mass storage driver.
+ *
+ * @param[in] msdp pointer to the @p USBMassStorageDriver object
+ *
+ * @api
+ */
+void msdStop(USBMassStorageDriver *msdp) {
+
+ osalDbgCheck(msdp != NULL);
+ osalDbgAssert((msdp->state == USB_MSD_READY), "invalid state");
+
+ chThdTerminate(msdp->worker);
+ chThdWait(msdp->worker);
+
+ scsiStop(&msdp->scsi_target);
+
+ msdp->worker = NULL;
+ msdp->state = USB_MSD_STOP;
+ msdp->usbp = NULL;
+}
+
+/**
+ * @brief Configures and activates the USB mass storage driver.
+ *
+ * @param[in] msdp pointer to the @p USBMassStorageDriver object
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] blkdev pointer to the @p BaseBlockDevice object
+ * @param[in] blkbuf pointer to the working area buffer, must be allocated
+ * by user, must be big enough to store 1 data block
+ * @param[in] inquiry pointer to the SCSI inquiry response structure,
+ * set it to @p NULL to use default hardcoded value.
+ *
+ * @api
+ */
+void msdStart(USBMassStorageDriver *msdp, USBDriver *usbp,
+ BaseBlockDevice *blkdev, uint8_t *blkbuf,
+ const scsi_inquiry_response_t *inquiry) {
+
+ osalDbgCheck((msdp != NULL) && (usbp != NULL)
+ && (blkdev != NULL) && (blkbuf != NULL));
+ osalDbgAssert((msdp->state == USB_MSD_STOP), "invalid state");
+
+ msdp->usbp = usbp;
+
+ msdp->usb_scsi_transport_handler.usbp = msdp->usbp;
+ msdp->usb_scsi_transport_handler.ep = USB_MSD_DATA_EP;
+ msdp->scsi_transport.handler = &msdp->usb_scsi_transport_handler;
+ msdp->scsi_transport.transmit = scsi_transport_transmit;
+ msdp->scsi_transport.receive = scsi_transport_receive;
+
+ if (NULL == inquiry) {
+ msdp->scsi_config.inquiry_response = &default_scsi_inquiry_response;
+ }
+ else {
+ msdp->scsi_config.inquiry_response = inquiry;
+ }
+ msdp->scsi_config.blkbuf = blkbuf;
+ msdp->scsi_config.blkdev = blkdev;
+ msdp->scsi_config.transport = &msdp->scsi_transport;
+
+ scsiStart(&msdp->scsi_target, &msdp->scsi_config);
+
+ msdp->state = USB_MSD_READY;
+ msdp->worker = chThdCreateStatic(msdp->waMSDWorker, sizeof(msdp->waMSDWorker),
+ MSD_THD_PRIO, usb_msd_worker, msdp);
+}
+
+#endif /* HAL_USE_USB_MSD */
+
+/** @} */
diff --git a/os/various/lib_scsi.c b/os/various/lib_scsi.c
new file mode 100644
index 0000000..11842ef
--- /dev/null
+++ b/os/various/lib_scsi.c
@@ -0,0 +1,466 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file lib_scsi.c
+ * @brief SCSI target driver source code.
+ *
+ * @addtogroup SCSI
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+//#include "chprintf.h"
+
+#include "lib_scsi.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+typedef struct {
+ uint32_t first_lba;
+ uint16_t blk_cnt;
+} data_request_t;
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Byte swapping function.
+ *
+ * @notapi
+ */
+static uint32_t swap_uint32(uint32_t val) {
+ val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0x00FF00FF);
+ return ((val << 16) & 0xFFFF0000) | ((val >> 16) & 0x0000FFFF);
+}
+
+/**
+ * @brief Byte swapping function.
+ *
+ * @notapi
+ */
+static uint16_t swap_uint16(uint16_t val) {
+ return ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+}
+
+/**
+ * @brief Combines data request from byte array.
+ *
+ * @notapi
+ */
+static data_request_t decode_data_request(const uint8_t *cmd) {
+
+ data_request_t req;
+ uint32_t lba;
+ uint16_t blk;
+
+ memcpy(&lba, &cmd[2], sizeof(lba));
+ memcpy(&blk, &cmd[7], sizeof(blk));
+
+ req.first_lba = swap_uint32(lba);
+ req.blk_cnt = swap_uint16(blk);
+
+ return req;
+}
+
+/**
+ * @brief Fills sense structure.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] key SCSI sense key
+ * @param[in] code SCSI sense code
+ * @param[in] qual SCSI sense qualifier
+ *
+ * @notapi
+ */
+static void set_sense(SCSITarget *scsip, uint8_t key,
+ uint8_t code, uint8_t qual) {
+
+ scsi_sense_response_t *sense = &scsip->sense;
+ memset(sense, 0 , sizeof(scsi_sense_response_t));
+
+ sense->byte[0] = 0x70;
+ sense->byte[2] = key;
+ sense->byte[7] = 8;
+ sense->byte[12] = code;
+ sense->byte[13] = qual;
+}
+
+/**
+ * @brief Sets all values in sense data to 'success' condition.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ *
+ * @notapi
+ */
+static void set_sense_ok(SCSITarget *scsip) {
+ set_sense(scsip, SCSI_SENSE_KEY_GOOD,
+ SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+}
+
+/**
+ * @brief Transmits data via transport channel.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] data pointer to data buffer
+ * @param[in] len number of bytes to be transmitted
+ *
+ * @return The operation status.
+ *
+ * @notapi
+ */
+static bool transmit_data(SCSITarget *scsip, const uint8_t *data, uint32_t len) {
+
+ const SCSITransport *trp = scsip->config->transport;
+ const uint32_t residue = len - trp->transmit(trp, data, len);
+
+ if (residue > 0) {
+ scsip->residue = residue;
+ return SCSI_FAILED;
+ }
+ else {
+ return SCSI_SUCCESS;
+ }
+}
+
+/**
+ * @brief Stub for unhandled SCSI commands.
+ * @details Sets error flags in sense data structure and returns error error.
+ */
+static bool cmd_unhandled(SCSITarget *scsip, const uint8_t *cmd) {
+ (void)cmd;
+
+ set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_INVALID_COMMAND,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+ return SCSI_FAILED;
+}
+
+/**
+ * @brief Stub for unrealized but required SCSI commands.
+ * @details Sets sense data in 'all OK' condition and returns success status.
+ */
+static bool cmd_ignored(SCSITarget *scsip, const uint8_t *cmd) {
+ (void)scsip;
+ (void)cmd;
+
+ set_sense_ok(scsip);
+ return SCSI_SUCCESS;
+}
+
+/**
+ * @brief SCSI inquiry command handler.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ *
+ * @notapi
+ */
+static bool inquiry(SCSITarget *scsip, const uint8_t *cmd) {
+
+ if ((cmd[1] & 0b11) || cmd[2] != 0) {
+ set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_INVALID_FIELD_IN_CDB,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+ return SCSI_FAILED;
+ }
+ else {
+ return transmit_data(scsip, (const uint8_t *)scsip->config->inquiry_response,
+ sizeof(scsi_inquiry_response_t));
+ }
+}
+
+/**
+ * @brief SCSI request sense command handler.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ *
+ * @notapi
+ */
+static bool request_sense(SCSITarget *scsip, const uint8_t *cmd) {
+
+ uint32_t tmp;
+ memcpy(&tmp, &cmd[1], 3);
+
+ if ((tmp != 0) || (cmd[4] != sizeof(scsi_sense_response_t))) {
+ set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_INVALID_FIELD_IN_CDB,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+ return SCSI_FAILED;
+ }
+ else {
+ return transmit_data(scsip, (uint8_t *)&scsip->sense,
+ sizeof(scsi_sense_response_t));
+ }
+}
+
+/**
+ * @brief SCSI mode sense (6) command handler.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ *
+ * @notapi
+ */
+static bool mode_sense6(SCSITarget *scsip, const uint8_t *cmd) {
+ (void)cmd;
+
+ scsip->mode_sense.byte[0] = sizeof(scsi_mode_sense6_response_t) - 1;
+ scsip->mode_sense.byte[1] = 0;
+ if (blkIsWriteProtected(scsip->config->blkdev)) {
+ scsip->mode_sense.byte[2] = 0x01 << 7;
+ }
+ else {
+ scsip->mode_sense.byte[2] = 0;
+ }
+ scsip->mode_sense.byte[3] = 0;
+
+ return transmit_data(scsip, (uint8_t *)&scsip->mode_sense,
+ sizeof(scsi_mode_sense6_response_t));
+}
+
+/**
+ * @brief SCSI read capacity (10) command handler.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ *
+ * @notapi
+ */
+static bool read_capacity10(SCSITarget *scsip, const uint8_t *cmd) {
+
+ (void)cmd;
+
+ BlockDeviceInfo bdi;
+ blkGetInfo(scsip->config->blkdev, &bdi);
+ scsi_read_capacity10_response_t ret;
+ ret.block_size = swap_uint32(bdi.blk_size);
+ ret.last_block_addr = swap_uint32(bdi.blk_num - 1);
+
+ return transmit_data(scsip, (uint8_t *)&ret,
+ sizeof(scsi_read_capacity10_response_t));
+}
+
+/**
+ * @brief Checks data request for media overflow.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ * @retval true When media overflow detected.
+ * @retval false Otherwise.
+ *
+ * @notapi
+ */
+static bool data_overflow(SCSITarget *scsip, const data_request_t *req) {
+
+ BlockDeviceInfo bdi;
+ blkGetInfo(scsip->config->blkdev, &bdi);
+
+ if (req->first_lba + req->blk_cnt > bdi.blk_num) {
+ set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+ SCSI_ASENSE_LBA_OUT_OF_RANGE,
+ SCSI_ASENSEQ_NO_QUALIFIER);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * @brief SCSI read/write (10) command handler.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ *
+ * @notapi
+ */
+static bool data_read_write10(SCSITarget *scsip, const uint8_t *cmd) {
+
+ data_request_t req = decode_data_request(cmd);
+
+ if (data_overflow(scsip, &req)) {
+ return SCSI_FAILED;
+ }
+ else {
+ const SCSITransport *tr = scsip->config->transport;
+ BaseBlockDevice *blkdev = scsip->config->blkdev;
+ BlockDeviceInfo bdi;
+ blkGetInfo(blkdev, &bdi);
+ size_t bs = bdi.blk_size;
+ uint8_t *buf = scsip->config->blkbuf;
+
+ for (size_t i=0; i<req.blk_cnt; i++) {
+ if (cmd[0] == SCSI_CMD_READ_10) {
+ // TODO: block error handling
+ blkRead(blkdev, req.first_lba + i, buf, 1);
+ tr->transmit(tr, buf, bs);
+ }
+ else {
+ // TODO: block error handling
+ tr->receive(tr, buf, bs);
+ blkWrite(blkdev, req.first_lba + i, buf, 1);
+ }
+ }
+ }
+ return SCSI_SUCCESS;
+}
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Executes SCSI command encoded in byte array.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] cmd pointer to SCSI command data
+ *
+ * @return The operation status.
+ *
+ * @api
+ */
+bool scsiExecCmd(SCSITarget *scsip, const uint8_t *cmd) {
+
+ /* status will be overwritten later in case of error */
+ set_sense_ok(scsip);
+
+ switch (cmd[0]) {
+ case SCSI_CMD_INQUIRY:
+ //chprintf(SDDBG, "SCSI_CMD_INQUIRY\r\n");
+ return inquiry(scsip, cmd);
+
+ case SCSI_CMD_REQUEST_SENSE:
+ //chprintf(SDDBG, "SCSI_CMD_REQUEST_SENSE\r\n");
+ return request_sense(scsip, cmd);
+
+ case SCSI_CMD_READ_CAPACITY_10:
+ //chprintf(SDDBG, "SCSI_CMD_READ_CAPACITY_10\r\n");
+ return read_capacity10(scsip, cmd);
+
+ case SCSI_CMD_READ_10:
+ //chprintf(SDDBG, "SCSI_CMD_READ_10\r\n");
+ return data_read_write10(scsip, cmd);
+
+ case SCSI_CMD_WRITE_10:
+ //chprintf(SDDBG, "SCSI_CMD_WRITE_10\r\n");
+ return data_read_write10(scsip, cmd);
+
+ case SCSI_CMD_TEST_UNIT_READY:
+ //chprintf(SDDBG, "SCSI_CMD_TEST_UNIT_READY\r\n");
+ return cmd_ignored(scsip, cmd);
+
+ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ //chprintf(SDDBG, "SCSI_CMD_ALLOW_MEDIUM_REMOVAL\r\n");
+ return cmd_ignored(scsip, cmd);
+
+ case SCSI_CMD_MODE_SENSE_6:
+ //chprintf(SDDBG, "SCSI_CMD_MODE_SENSE_6\r\n");
+ return mode_sense6(scsip, cmd);
+
+ default:
+ //(SDDBG, "SCSI unhandled command: %d\r\n", cmd[0]);
+ return cmd_unhandled(scsip, cmd);
+ }
+}
+
+/**
+ * @brief Driver structure initialization.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ *
+ * @api
+ */
+void scsiObjectInit(SCSITarget *scsip) {
+
+ scsip->config = NULL;
+ scsip->residue = 0;
+ memset(&scsip->sense, 0 , sizeof(scsi_sense_response_t));
+ scsip->state = SCSI_TRGT_STOP;
+}
+
+/**
+ * @brief Starts SCSITarget driver.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ * @param[in] config pointer to @p SCSITargetConfig structure
+ *
+ * @api
+ */
+void scsiStart(SCSITarget *scsip, const SCSITargetConfig *config) {
+
+ scsip->config = config;
+ scsip->state = SCSI_TRGT_READY;
+}
+
+/**
+ * @brief Stops SCSITarget driver.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ *
+ * @api
+ */
+void scsiStop(SCSITarget *scsip) {
+
+ scsip->config = NULL;
+ scsip->state = SCSI_TRGT_STOP;
+}
+
+/**
+ * @brief Retrieves residue bytes.
+ *
+ * @param[in] scsip pointer to @p SCSITarget structure
+ *
+ * @return Residue bytes.
+ *
+ * @api
+ */
+uint32_t scsiResidue(const SCSITarget *scsip) {
+
+ return scsip->residue;
+}
+
+/** @} */
diff --git a/os/various/lib_scsi.h b/os/various/lib_scsi.h
new file mode 100644
index 0000000..21ab5d8
--- /dev/null
+++ b/os/various/lib_scsi.h
@@ -0,0 +1,267 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file wdg_lld.h
+ * @brief WDG Driver subsystem low level driver header template.
+ *
+ * @addtogroup WDG
+ * @{
+ */
+
+#ifndef LIB_SCSI_H_
+#define LIB_SCSI_H_
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define SCSI_CMD_TEST_UNIT_READY 0x00
+#define SCSI_CMD_REQUEST_SENSE 0x03
+#define SCSI_CMD_INQUIRY 0x12
+#define SCSI_CMD_MODE_SENSE_6 0x1A
+#define SCSI_CMD_START_STOP_UNIT 0x1B
+#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
+#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
+#define SCSI_CMD_READ_CAPACITY_10 0x25
+#define SCSI_CMD_READ_10 0x28
+#define SCSI_CMD_WRITE_10 0x2A
+#define SCSI_CMD_VERIFY_10 0x2F
+
+#define SCSI_SENSE_KEY_GOOD 0x00
+#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
+#define SCSI_SENSE_KEY_NOT_READY 0x02
+#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
+#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
+#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
+#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
+#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
+#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
+#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
+#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
+#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
+#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
+#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
+
+#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
+#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
+#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
+#define SCSI_ASENSE_WRITE_PROTECTED 0x27
+#define SCSI_ASENSE_FORMAT_ERROR 0x31
+#define SCSI_ASENSE_INVALID_COMMAND 0x20
+#define SCSI_ASENSE_LBA_OUT_OF_RANGE 0x21
+#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
+
+#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
+#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
+#define SCSI_ASENSEQ_INIT_COMMAND_REQUIRED 0x02
+#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
+
+#define SCSI_SUCCESS HAL_SUCCESS
+#define SCSI_FAILED HAL_FAILED
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an SCSI target.
+ */
+typedef struct SCSITarget SCSITarget;
+
+/**
+ * @brief Type of a structure representing an SCSI transport.
+ */
+typedef struct SCSITransport SCSITransport;
+
+/**
+ * @brief State of SCSI target.
+ */
+typedef enum {
+ SCSI_TRGT_UNINIT = 0,
+ SCSI_TRGT_STOP,
+ SCSI_TRGT_READY,
+} scsitrgtstate_t;
+
+/**
+ * @brief Represents SCSI sense data structure.
+ * @details See SCSI specification.
+ */
+typedef struct PACKED_VAR {
+ uint8_t byte[18];
+} scsi_sense_response_t;
+
+/**
+ * @brief Represents SCSI inquiry response structure.
+ * @details See SCSI specification.
+ */
+typedef struct PACKED_VAR {
+ uint8_t peripheral;
+ uint8_t removable;
+ uint8_t version;
+ uint8_t response_data_format;
+ uint8_t additional_length;
+ uint8_t sccstp;
+ uint8_t bqueetc;
+ uint8_t cmdque;
+ uint8_t vendorID[8];
+ uint8_t productID[16];
+ uint8_t productRev[4];
+} scsi_inquiry_response_t;
+
+/**
+ * @brief Represents SCSI mode sense (6) request structure.
+ * @details See SCSI specification.
+ */
+typedef struct PACKED_VAR {
+ uint8_t byte[6];
+} scsi_mode_sense6_request_t;
+
+/**
+ * @brief Represents SCSI mode sense (6) response structure.
+ * @details See SCSI specification.
+ */
+typedef struct PACKED_VAR{
+ uint8_t byte[4];
+} scsi_mode_sense6_response_t;
+
+/**
+ * @brief Represents SCSI read capacity (10) response structure.
+ * @details See SCSI specification.
+ */
+typedef struct PACKED_VAR {
+ uint32_t last_block_addr;
+ uint32_t block_size;
+} scsi_read_capacity10_response_t;
+
+/**
+ * @brief Type of a SCSI transport transmit call.
+ *
+ * @param[in] usbp pointer to the @p SCSITransport object
+ * @param[in] data pointer to payload buffer
+ * @param[in] len payload length
+ */
+typedef uint32_t (*scsi_transport_transmit_t)(const SCSITransport *transport,
+ const uint8_t *data, size_t len);
+
+/**
+ * @brief Type of a SCSI transport transmit call.
+ *
+ * @param[in] usbp pointer to the @p SCSITransport object
+ * @param[out] data pointer to receive buffer
+ * @param[in] len number of bytes to be received
+ */
+typedef uint32_t (*scsi_transport_receive_t)(const SCSITransport *transport,
+ uint8_t *data, size_t len);
+
+/**
+ * @brief SCSI transport structure.
+ */
+struct SCSITransport {
+ /**
+ * @brief Transmit call provided by lower level driver.
+ */
+ scsi_transport_transmit_t transmit;
+ /**
+ * @brief Receive call provided by lower level driver.
+ */
+ scsi_transport_receive_t receive;
+ /**
+ * @brief Transport handler provided by lower level driver.
+ */
+ void *handler;
+};
+
+/**
+ * @brief SCSI target config structure.
+ */
+typedef struct {
+ /**
+ * @brief Pointer to @p SCSITransport object.
+ */
+ const SCSITransport *transport;
+ /**
+ * @brief Pointer to @p BaseBlockDevice object.
+ */
+ BaseBlockDevice *blkdev;
+ /**
+ * @brief Pointer to data buffer for single block.
+ */
+ uint8_t *blkbuf;
+ /**
+ * @brief Pointer to SCSI inquiry response object.
+ */
+ const scsi_inquiry_response_t *inquiry_response;
+} SCSITargetConfig;
+
+/**
+ *
+ */
+struct SCSITarget {
+ /**
+ * @brief Pointer to @p SCSITargetConfig object.
+ */
+ const SCSITargetConfig *config;
+ /**
+ * @brief Target state.
+ */
+ scsitrgtstate_t state;
+ /**
+ * @brief SCSI sense response structure.
+ */
+ scsi_sense_response_t sense;
+ /**
+ * @brief SCSI mode sense (6) response structure.
+ */
+ scsi_mode_sense6_response_t mode_sense;
+ /**
+ * @brief Residue bytes.
+ */
+ uint32_t residue;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void scsiObjectInit(SCSITarget *scsip);
+ void scsiStart(SCSITarget *scsip, const SCSITargetConfig *config);
+ void scsiStop(SCSITarget *scsip);
+ bool scsiExecCmd(SCSITarget *scsip, const uint8_t *cmd);
+ uint32_t scsiResidue(const SCSITarget *scsip);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIB_SCSI_H_ */
+
+/** @} */
diff --git a/os/various/ramdisk.c b/os/various/ramdisk.c
new file mode 100644
index 0000000..b9a40ef
--- /dev/null
+++ b/os/various/ramdisk.c
@@ -0,0 +1,219 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file ramdisk.c
+ * @brief Virtual block devise driver source.
+ *
+ * @addtogroup ramdisk
+ * @{
+ */
+
+#include "hal.h"
+
+#include "ramdisk.h"
+
+#include <string.h>
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*
+ * Interface implementation.
+ */
+static bool overflow(const RamDisk *rd, uint32_t startblk, uint32_t n) {
+ return (startblk + n) > rd->blk_num;
+}
+
+static bool is_inserted(void *instance) {
+ (void)instance;
+ return true;
+}
+
+static bool is_protected(void *instance) {
+ RamDisk *rd = instance;
+ if (rd->state != BLK_READY) {
+ return rd->readonly;
+ }
+ else {
+ return true;
+ }
+}
+
+static bool connect(void *instance) {
+ RamDisk *rd = instance;
+ if (rd->state == BLK_STOP) {
+ rd->state = BLK_READY;
+ }
+ return HAL_SUCCESS;
+}
+
+static bool disconnect(void *instance) {
+ RamDisk *rd = instance;
+ if (rd->state != BLK_STOP) {
+ rd->state = BLK_STOP;
+ }
+ return HAL_SUCCESS;
+}
+
+static bool read(void *instance, uint32_t startblk,
+ uint8_t *buffer, uint32_t n) {
+
+ RamDisk *rd = instance;
+
+ if (overflow(rd, startblk, n)) {
+ return HAL_FAILED;
+ }
+ else {
+ const uint32_t bs = rd->blk_size;
+ memcpy(buffer, &rd->storage[startblk * bs], n * bs);
+ return HAL_SUCCESS;
+ }
+}
+
+static bool write(void *instance, uint32_t startblk,
+ const uint8_t *buffer, uint32_t n) {
+
+ RamDisk *rd = instance;
+ if (overflow(rd, startblk, n)) {
+ return HAL_FAILED;
+ }
+ else {
+ const uint32_t bs = rd->blk_size;
+ memcpy(&rd->storage[startblk * bs], buffer, n * bs);
+ return HAL_SUCCESS;
+ }
+}
+
+static bool sync(void *instance) {
+
+ RamDisk *rd = instance;
+ if (rd->state != BLK_READY) {
+ return HAL_FAILED;
+ }
+ else {
+ return HAL_SUCCESS;
+ }
+}
+
+static bool get_info(void *instance, BlockDeviceInfo *bdip) {
+
+ RamDisk *rd = instance;
+ if (rd->state != BLK_READY) {
+ return HAL_FAILED;
+ }
+ else {
+ bdip->blk_num = rd->blk_num;
+ bdip->blk_size = rd->blk_size;
+ return HAL_SUCCESS;
+ }
+}
+
+/**
+ *
+ */
+static const struct BaseBlockDeviceVMT vmt = {
+ is_inserted,
+ is_protected,
+ connect,
+ disconnect,
+ read,
+ write,
+ sync,
+ get_info
+};
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief RAM disk object initialization.
+ *
+ * @param[in] rdp pointer to @p RamDisk object
+ *
+ * @init
+ */
+void ramdiskObjectInit(RamDisk *rdp) {
+
+ rdp->vmt = &vmt;
+ rdp->state = SD_STOP;
+}
+
+/**
+ * @brief Starts RAM disk.
+ *
+ * @param[in] rdp pointer to @p RamDisk object
+ * @param[in] storage pointer to array representing disk storage
+ * @param[in] blksize size of blocks in bytes
+ * @param[in] blknum total number of blocks in device
+ * @param[in] readonly read only flag
+ *
+ * @api
+ */
+void ramdiskStart(RamDisk *rdp, uint8_t *storage, uint32_t blksize,
+ uint32_t blknum, bool readonly) {
+
+ osalDbgCheck(rdp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((rdp->state == BLK_STOP) || (rdp->state == BLK_READY),
+ "invalid state");
+ rdp->blk_num = blknum;
+ rdp->blk_size = blksize;
+ rdp->readonly = readonly;
+ rdp->storage = storage;
+ rdp->state = BLK_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Stops RAM disk.
+ *
+ * @param[in] rdp pointer to @p RamDisk object
+ *
+ * @api
+ */
+void ramdiskStop(RamDisk *rdp) {
+
+ osalDbgCheck(rdp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((rdp->state == BLK_STOP) || (rdp->state == BLK_READY),
+ "invalid state");
+ rdp->storage = NULL;
+ rdp->state = BLK_STOP;
+ osalSysUnlock();
+}
+
+/** @} */
diff --git a/os/various/ramdisk.h b/os/various/ramdisk.h
new file mode 100644
index 0000000..0860662
--- /dev/null
+++ b/os/various/ramdisk.h
@@ -0,0 +1,86 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file ramdisk.h
+ * @brief Virtual block devise driver header.
+ *
+ * @addtogroup ramdisk
+ * @{
+ */
+
+#ifndef RAMDISK_H_
+#define RAMDISK_H_
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+typedef struct RamDisk RamDisk;
+
+/**
+ *
+ */
+#define _ramdisk_device_data \
+ _base_block_device_data \
+ uint8_t *storage; \
+ uint32_t blk_size; \
+ uint32_t blk_num; \
+ bool readonly;
+
+/**
+ *
+ */
+struct RamDisk {
+ /** @brief Virtual Methods Table.*/
+ const struct BaseBlockDeviceVMT *vmt;
+ _ramdisk_device_data
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void ramdiskObjectInit(RamDisk *rdp);
+ void ramdiskStart(RamDisk *rdp, uint8_t *storage, uint32_t blksize,
+ uint32_t blknum, bool readonly);
+ void ramdiskStop(RamDisk *rdp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RAMDISK_H_ */
+
+/** @} */