Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 187 additions & 11 deletions fs/disk/include/disk/disk.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

#include <stddef.h>
#include <inttypes.h>
#include "os/mynewt.h"
#include <os/mynewt.h>
#include <os/link_tables.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -35,19 +36,194 @@ extern "C" {
#define DISK_EOS 4 /* OS error */
#define DISK_EUNINIT 5 /* File system not initialized */

struct disk_ops {
int (*read)(uint8_t, uint32_t, void *, uint32_t);
int (*write)(uint8_t, uint32_t, const void *, uint32_t);
int (*ioctl)(uint8_t, uint32_t, void *);
typedef struct disk disk_t;
typedef struct disk_info disk_info_t;
typedef struct disk_listener disk_listener_t;

SLIST_ENTRY(disk_ops) sc_next;
/**
* Disk information
*/
struct disk_info {
/* Disk name (information only) */
const char *name;
/* Disk block (sector) count */
uint32_t block_count;
/* Block size (usually 512) */
uint16_t block_size;
/* Set to 1 if disk is present */
uint16_t present : 1;
};

typedef struct disk_ops {
/** Get basic information about disk
*
* @param disk - disk to query
* @param info - disk information to fill
* @return 0 on success, SYS_EINVAL if arguments are incorrect
*/
int (*get_info)(const struct disk *disk, struct disk_info *info);

/**
* Inform driver that disk was just removed
* @param disk - disk that was ejected
* @return 0 on success, SYS_EINVAL if arguments are incorrect
*/
int (*eject)(struct disk *disk);
/**
* Read disk block
* @param disk - dist to read from
* @param lba - block to read
* @param buf - buffer for data
* @param block_count - number for blocks to read
* @return 0 on success
*/
int (*read)(struct disk *disk, uint32_t lba, void *buf, uint32_t block_count);
/**
* Write disk block
* @param disk - dist to write to
* @param lba - block to write to
* @param buf - data buffer
* @param block_count - number of blocks to write
* @return 0 on success
*/
int (*write)(struct disk *disk, uint32_t lba, const void *buf, uint32_t block_count);
} disk_ops_t;

/* Disk listener operations */
typedef struct disk_listener_ops {
/* New disk was inserted to driver and could be mounter */
int (*disk_added)(struct disk_listener *listener, struct disk *disk);
/* Disk was ejected and should be unmounted */
int (*disk_removed)(struct disk_listener *listener, struct disk *disk);
} disk_listener_ops_t;

/* Disk listener */
struct disk_listener {
const disk_listener_ops_t *ops;
};

int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops);
struct disk_ops *disk_ops_for(const char *disk_name);
char *disk_fs_for(const char *disk_name);
char *disk_name_from_path(const char *path);
char *disk_filepath_from_path(const char *path);
/* Base for disks */
struct disk {
const disk_ops_t *ops;
};

/**
* Function called when disk was inserted into a driver
* and system could mount it or otherwise be aware that new
* disk could be used
*
* @param disk - disk that was inserted
*
* @return 0 - for success
*/
int mn_disk_inserted(disk_t *disk);

/**
* Function called when disk was removed, if disk was
* mounted it file system can be unmounted. If disk
* was present to MSC it can no longer be advertised
* as present.
*
* @param disk - disk that was remove from driver
*
* @return 0 -for success
*/
int mn_disk_ejected(disk_t *disk);

/**
* Function return 1 if disk is present
*
* @param disk - disk to check for presence
* @return 1 - disk is present, 0 - disk is not present
*/
static inline int disk_present(disk_t *disk)
{
disk_info_t di;
disk->ops->get_info(disk, &di);

return di.present;
}

/**
* Get disk information
* Disk information consist of size information
*
* @param disk - disk to get information from
* @param di - pointer to data to received disk information
*
* @return 0 - for success
*/
static inline int mn_disk_info_get(disk_t *disk, disk_info_t *di)
{
return disk->ops->get_info(disk, di);
}

/**
* Read sector(s) from disk
*
* @param disk - disk to read data from
* @param lba - sector number
* @param buf - buffer to be filled with data from disk
* @param block_count - number of sectors to read
* @return 0 - for success
*/
static inline int mn_disk_read(disk_t *disk, uint32_t lba, void *buf, uint32_t block_count)
{
return disk->ops->read(disk, lba, buf, block_count);
}

/**
* Write sector(s) to disk
*
* @param disk - disk to write to
* @param lba - first sector to write to
* @param buf - buffer with data
* @param block_count - number of sectors to write
* @return 0 - for success
*/
static inline int mn_disk_write(disk_t *disk, uint32_t lba, const void *buf, uint32_t block_count)
{
return disk->ops->write(disk, lba, buf, block_count);
}

/**
* Eject disk
*
* Calling this function will result in calling disk listeners about
* disk being removed via disk_removed(). This may result in file
* system being unmounted.
*
* @param disk - disk to eject
* @return 0 - for success
*/
static inline int mn_disk_eject(disk_t *disk)
{
return disk->ops->eject(disk);
}

/**
* Link time table to hold all available disk listeners
* that will be informed when disk is available and
* can be mounted or used in other ways.
*/
LINK_TABLE(disk_listener_t *, disk_listeners)

/**
* @brief Macros to put disk_listener in link table
*
* i.e.
* // Define disk_listener_t structure
* disk_listener_t mounter = {
* .opt = &mounter_ops,
* };
*
* DISK_LISTENER(mounter_entry, mounter)
*
* @param listener_entry - new pointer variable name that will be put in disk_listeners table
* @param listener - object of type disk_listener_t
*/
#define DISK_LISTENER(listener_entry, listener) \
LINK_TABLE_ELEMENT(disk_listeners, listener_entry) = &listener;

#ifdef __cplusplus
}
Expand Down
5 changes: 4 additions & 1 deletion fs/disk/pkg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
#

pkg.name: fs/disk
pkg.description: Disk management layer to glue filesystems to disk devices.
pkg.description: Disk management layer to disk devices.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:

pkg.deps:
- "@apache-mynewt-core/kernel/os"

pkg.link_tables:
- disk_listeners
141 changes: 22 additions & 119 deletions fs/disk/src/disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,135 +17,38 @@
* under the License.
*/

#include <stdlib.h>
#include <string.h>
#include "os/mynewt.h"
#include <inttypes.h>
#include <os/mynewt.h>
#include <os/link_tables.h>
#include <disk/disk.h>

struct disk_info {
const char *disk_name;
const char *fs_name;
struct disk_ops *dops;
#define DISK_EOK 0 /* Success */
#define DISK_EHW 1 /* Error accessing storage medium */
#define DISK_ENOMEM 2 /* Insufficient memory */
#define DISK_ENOENT 3 /* No such file or directory */
#define DISK_EOS 4 /* OS error */
#define DISK_EUNINIT 5 /* File system not initialized */

SLIST_ENTRY(disk_info) sc_next;
};

static SLIST_HEAD(, disk_info) disks = SLIST_HEAD_INITIALIZER();

/**
*
*/
int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops)
int
mn_disk_inserted(disk_t *disk)
{
struct disk_info *info = NULL;
struct disk_info *sc;

SLIST_FOREACH(sc, &disks, sc_next) {
if (strcmp(sc->disk_name, disk_name) == 0) {
return DISK_ENOENT;
}
}
int count = LINK_TABLE_SIZE(disk_listeners);

info = malloc(sizeof(struct disk_info));
if (!info) {
return DISK_ENOMEM;
for (int i = 0; i < count; ++i) {
disk_listener_t *listener = disk_listeners[i];
listener->ops->disk_added(listener, disk);
}

info->disk_name = disk_name;
info->fs_name = fs_name;
info->dops = dops;

SLIST_INSERT_HEAD(&disks, info, sc_next);

return 0;
}

struct disk_ops *
disk_ops_for(const char *disk_name)
int
mn_disk_ejected(disk_t *disk)
{
struct disk_info *sc;
int count = LINK_TABLE_SIZE(disk_listeners);

if (disk_name) {
SLIST_FOREACH(sc, &disks, sc_next) {
if (strcmp(sc->disk_name, disk_name) == 0) {
return sc->dops;
}
}
for (int i = 0; i < count; ++i) {
disk_listener_t *listener = disk_listeners[i];
listener->ops->disk_removed(listener, disk);
}

return NULL;
}

char *
disk_fs_for(const char *disk_name)
{
struct disk_info *sc;

if (disk_name) {
SLIST_FOREACH(sc, &disks, sc_next) {
if (strcmp(sc->disk_name, disk_name) == 0) {
return ((char *) sc->fs_name);
}
}
}

return NULL;
}

char *
disk_name_from_path(const char *path)
{
char *colon;
uint8_t len;
char *disk;

colon = (char *) path;
while (*colon && *colon != ':') {
colon++;
}

if (*colon != ':') {
return NULL;
}

len = colon - path;
disk = malloc(len + 1);
if (!disk) {
return NULL;
}
memcpy(disk, path, len);
disk[len] = '\0';

return disk;
}

/**
* @brief Returns the path with the disk prefix removed (if found)
*
* Paths should be given in the form disk<number>:/path. This routine
* will parse and return only the path, removing the disk information.
*/
char *
disk_filepath_from_path(const char *path)
{
char *colon;
char *filepath;
size_t len;

colon = (char *) path;
while (*colon && *colon != ':') {
colon++;
}

if (*colon != ':') {
filepath = strdup(path);
} else {
colon++;
len = strlen(colon);
filepath = malloc(len + 1);
memcpy(filepath, colon, len);
filepath[len] = '\0';
}

return filepath;
return 0;
}
Loading
Loading