Add support for an automounter that will automatically mount and unmount a file system a media is inserted and removed
This commit is contained in:
parent
b7227f0088
commit
8e506be4dd
4 changed files with 828 additions and 0 deletions
20
fs/Kconfig
20
fs/Kconfig
|
@ -9,6 +9,26 @@ config DISABLE_MOUNTPOINT
|
|||
bool "Disable support for mount points"
|
||||
default n
|
||||
|
||||
config FS_AUTOMOUNTER
|
||||
bool "Auto-mounter"
|
||||
default n
|
||||
depends on !DISABLE_MOUNTPOINT
|
||||
---help---
|
||||
The automounter provides an OS-internal mechanism for automatically
|
||||
mounting and unmounting removable media as the media is inserted and
|
||||
removed. See include/nuttx/fs/automout.h for interfacing details.
|
||||
|
||||
config FS_AUTOMOUNTER_DEBUG
|
||||
bool "Auto-mounter debug"
|
||||
default n
|
||||
depends on FS_AUTOMOUNTER && DEBUG
|
||||
---help---
|
||||
Normally, the auto-mounter will generate debug output when sub-system
|
||||
level file system debug is enabled. This option will select debug
|
||||
output from the logic related to the auto-mount feature even when file
|
||||
system debug is not enable. This is useful primarily for in vivo
|
||||
unit testing of the auto-mount feature.
|
||||
|
||||
config DISABLE_PSEUDOFS_OPERATIONS
|
||||
bool "Disable pseudo-filesystem operations"
|
||||
default y if DEFAULT_SMALL
|
||||
|
|
|
@ -106,6 +106,10 @@ ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
|
|||
|
||||
CSRCS += fs_fsync.c fs_mount.c fs_umount.c fs_foreachmountpoint.c
|
||||
|
||||
ifeq ($(CONFIG_FS_AUTOMOUNTER),y)
|
||||
CSRCS += fs_automount.c
|
||||
endif
|
||||
|
||||
include fat/Make.defs
|
||||
include romfs/Make.defs
|
||||
include nxffs/Make.defs
|
||||
|
|
613
fs/fs_automount.c
Normal file
613
fs/fs_automount.c
Normal file
|
@ -0,0 +1,613 @@
|
|||
/****************************************************************************
|
||||
* fs/fs_automount.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#if defined(CONFIG_FS_AUTOMOUNTER_DEBUG) && !defined(CONFIG_DEBUG_FS)
|
||||
# define CONFIG_DEBUG_FS 1
|
||||
#endif
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wdog.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/fs/automount.h>
|
||||
|
||||
#include "fs_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************
|
||||
*
|
||||
* CONFIG_FS_AUTOMOUNTER - Enables AUTOMOUNT support
|
||||
*/
|
||||
|
||||
/* Pre-requisites */
|
||||
|
||||
#ifndef CONFIG_SCHED_WORKQUEUE
|
||||
# error Work queue support is required (CONFIG_SCHED_WORKQUEUE)
|
||||
#endif
|
||||
|
||||
/* Return Values */
|
||||
|
||||
#define OK_EXIST 0
|
||||
#define OK_NOENT 1
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
/* This structure describes the state of the automounter */
|
||||
|
||||
struct automounter_state_s
|
||||
{
|
||||
FAR const struct automount_lower_s *lower; /* Board level interfaces */
|
||||
struct work_s work; /* Work queue support */
|
||||
WDOG_ID wdog; /* Delay to retry un-mounts */
|
||||
bool mounted; /* True: Volume has been mounted */
|
||||
bool inserted; /* True: Media has been inserted */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int automount_findinode(FAR const char *path);
|
||||
static void automount_mount(FAR struct automounter_state_s *priv);
|
||||
static int automount_unmount(FAR struct automounter_state_s *priv);
|
||||
static void automount_timeout(int argc, uint32_t arg1, ...);
|
||||
static void automount_worker(FAR void *arg);
|
||||
static int automount_interrupt(FAR const struct automount_lower_s *lower,
|
||||
FAR void *arg, bool inserted);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_findinode
|
||||
*
|
||||
* Description:
|
||||
* Find the mountpoint inode in the inode tree.
|
||||
*
|
||||
* Input Parameters:
|
||||
* mntpath - Mountpoint path
|
||||
*
|
||||
* Returned Value:
|
||||
* OK_EXIST if the inode exists
|
||||
* OK_NOENT if the indoe does not exist
|
||||
* Negated errno if some failure occurs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int automount_findinode(FAR const char *path)
|
||||
{
|
||||
FAR struct inode *node;
|
||||
FAR const char *srchpath;
|
||||
FAR const char *relpath;
|
||||
int ret;
|
||||
|
||||
/* Make sure that we were given an absolute path */
|
||||
|
||||
DEBUGASSERT(path && path[0] == '/');
|
||||
|
||||
/* Get exclusive access to the in-memory inode tree. */
|
||||
|
||||
inode_semtake();
|
||||
|
||||
/* Find the inode */
|
||||
|
||||
srchpath = path;
|
||||
node = inode_search(&srchpath, (FAR struct inode**)NULL,
|
||||
(FAR struct inode**)NULL, &relpath);
|
||||
/* Did we find it? */
|
||||
|
||||
if (!node)
|
||||
{
|
||||
/* No.. Not found */
|
||||
|
||||
ret = OK_NOENT;
|
||||
}
|
||||
|
||||
/* Yes.. is it a mount point? */
|
||||
|
||||
else if (INODE_IS_MOUNTPT(node))
|
||||
{
|
||||
/* Yes.. we found a mountpoint at this path */
|
||||
|
||||
ret = OK_EXIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. then somethin is in the way */
|
||||
|
||||
ret = -ENOTDIR;
|
||||
}
|
||||
|
||||
/* Relinquish our exclusive access to the inode try and return the result */
|
||||
|
||||
inode_semgive();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_mount
|
||||
*
|
||||
* Description:
|
||||
* Media has been inserted, mount the volume.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to out private state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void automount_mount(FAR struct automounter_state_s *priv)
|
||||
{
|
||||
FAR const struct automount_lower_s *lower = priv->lower;
|
||||
int ret;
|
||||
|
||||
/* Check if the something is already mounted at the mountpoint. */
|
||||
|
||||
ret = automount_findinode(lower->mountpoint);
|
||||
switch (ret)
|
||||
{
|
||||
case OK_EXIST:
|
||||
/* REVISIT: What should we do in this case? I think that this would
|
||||
* happen only if a previous unmount failed? I suppose that we should
|
||||
* try to unmount again because the mount might be stale.
|
||||
*/
|
||||
|
||||
fdbg("WARNING: Mountpoint %s already exists\n", lower->mountpoint);
|
||||
ret = automount_unmount(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* We failed to unmount (again?). Complain and abort. */
|
||||
|
||||
fdbg("ERROR: automount_unmount failed: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We successfully unmounted the file system. Fall through to
|
||||
* mount it again.
|
||||
*/
|
||||
|
||||
case OK_NOENT:
|
||||
/* If we get here, then the volume must not be mounted */
|
||||
|
||||
DEBUGASSERT(!priv->mounted);
|
||||
|
||||
/* Mount the file system */
|
||||
|
||||
ret = mount(lower->blockdev, lower->mountpoint, lower->fstype,
|
||||
0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
int errcode = get_errno();
|
||||
DEBUGASSERT(errcode > 0);
|
||||
|
||||
fdbg("ERROR: Mount failed: %d\n", errcode);
|
||||
UNUSED(errcode);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Indicate that the volume is mounted */
|
||||
|
||||
priv->mounted = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
fdbg("ERROR: automount_findinode failed: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_unmount
|
||||
*
|
||||
* Description:
|
||||
* Media has been removed, unmount the volume.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to out private state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if the volume was successfully mounted. A negated errno value
|
||||
* otherwise.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int automount_unmount(FAR struct automounter_state_s *priv)
|
||||
{
|
||||
FAR const struct automount_lower_s *lower = priv->lower;
|
||||
int ret;
|
||||
|
||||
/* Check if the something is already mounted at the mountpoint. */
|
||||
|
||||
ret = automount_findinode(lower->mountpoint);
|
||||
switch (ret)
|
||||
{
|
||||
case OK_EXIST:
|
||||
/* If we get here, then the volume must be mounted */
|
||||
|
||||
DEBUGASSERT(priv->mounted);
|
||||
|
||||
/* Un-mount the volume */
|
||||
|
||||
ret = umount(lower->mountpoint);
|
||||
if (ret < 0)
|
||||
{
|
||||
int errcode = get_errno();
|
||||
DEBUGASSERT(errcode > 0);
|
||||
|
||||
/* We expect the error to be EBUSY meaning that the volume could
|
||||
* not be unmounted because there are currently reference via open
|
||||
* files or directories.
|
||||
*/
|
||||
|
||||
if (errcode == EBUSY)
|
||||
{
|
||||
fvdbg("WARNING: Volume is busy, try again later\n");
|
||||
|
||||
/* Start a timer to retry the umount after a delay */
|
||||
|
||||
ret = wd_start(priv->wdog, lower->udelay, automount_timeout, 1,
|
||||
(uint32_t)((uintptr_t)priv));
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = get_errno();
|
||||
DEBUGASSERT(errcode > 0);
|
||||
|
||||
fdbg("ERROR: wd_start failed: %d\n", errcode);
|
||||
return -ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Other errors are fatal */
|
||||
|
||||
else
|
||||
{
|
||||
fvdbg("ERROR: umount failed: %d\n", errcode);
|
||||
return -errcode;
|
||||
}
|
||||
}
|
||||
|
||||
/* Successfully unmounted */
|
||||
|
||||
priv->mounted = false;
|
||||
return OK;
|
||||
|
||||
case OK_NOENT:
|
||||
/* I suppose this is okay */
|
||||
|
||||
return OK;
|
||||
|
||||
default:
|
||||
fdbg("ERROR: automount_findinode failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_timeout
|
||||
*
|
||||
* Description:
|
||||
* A previous unmount failed because the volume was busy... busy meaning
|
||||
* the volume could not be unmounted because there are open references
|
||||
* the files or directories in the volume. When this failure occurred,
|
||||
* the unmount logic setup a delay and this function is called as a result
|
||||
* of that delay timeout.
|
||||
*
|
||||
* This function will attempt the unmount again.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard wdog timeout parameters
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void automount_timeout(int argc, uint32_t arg1, ...)
|
||||
{
|
||||
FAR struct automounter_state_s *priv =
|
||||
(FAR struct automounter_state_s *)((uintptr_t)arg1);
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(argc == 1 && priv);
|
||||
|
||||
/* Check the state of things. This timeout at the interrupt level and
|
||||
* will cancel the timeout if there is any change in the insertion
|
||||
* state. So we should still have the saved state as NOT inserted and
|
||||
* there should be no pending work.
|
||||
*/
|
||||
|
||||
fllvdbg("inserted=%d\n", priv->inserted);
|
||||
DEBUGASSERT(!priv->inserted && work_available(&priv->work));
|
||||
|
||||
/* Queue work to occur immediately. */
|
||||
|
||||
ret = work_queue(LPWORK, &priv->work, automount_worker, priv, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* NOTE: Currently, work_cancel only returns success */
|
||||
|
||||
fdbg("ERROR: Failed to schedule work: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_worker
|
||||
*
|
||||
* Description:
|
||||
* Performs automount actions on the worker thread.
|
||||
*
|
||||
* Input Parameters:
|
||||
* arg - Work argument set by work_queue()
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void automount_worker(FAR void *arg)
|
||||
{
|
||||
FAR struct automounter_state_s *priv = (FAR struct automounter_state_s *)arg;
|
||||
FAR const struct automount_lower_s *lower;
|
||||
|
||||
DEBUGASSERT(priv && priv->lower);
|
||||
lower = priv->lower;
|
||||
|
||||
/* Disable interrupts. We are commit now and everything must remain
|
||||
* stable.
|
||||
*/
|
||||
|
||||
AUTOMOUNT_DISABLE(lower);
|
||||
|
||||
/* Are we mounting or unmounting? */
|
||||
|
||||
if (priv->inserted)
|
||||
{
|
||||
/* We are mounting */
|
||||
|
||||
automount_mount(priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are unmounting */
|
||||
|
||||
(void)automount_unmount(priv);
|
||||
}
|
||||
|
||||
/* Re-enable interrupts */
|
||||
|
||||
AUTOMOUNT_ENABLE(lower);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Called (probably from the interrupt level) when a media change event
|
||||
* has been detected.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - Persistent board configuration data
|
||||
* arg - Data associated with the automounter
|
||||
* inserted - True: Media has been inserted. False: media has been removed
|
||||
*
|
||||
* Returned Value:
|
||||
* OK is returned on success; a negated errno value is returned on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* Interrupts are disabled so that there is no race condition with the
|
||||
* timer expiry.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int automount_interrupt(FAR const struct automount_lower_s *lower,
|
||||
FAR void *arg, bool inserted)
|
||||
{
|
||||
FAR struct automounter_state_s *priv = (FAR struct automounter_state_s *)arg;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower && priv && priv->lower == lower);
|
||||
|
||||
fllvdbg("inserted=%d\n", inserted);
|
||||
|
||||
/* Cancel any pending work. We could get called multiple times if, for
|
||||
* example there is bounce in the detection mechanism. Work is performed
|
||||
* the low priority work queue if it is available.
|
||||
*/
|
||||
|
||||
ret = work_cancel(LPWORK, &priv->work);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* NOTE: Currently, work_cancel only returns success */
|
||||
|
||||
fdbg("ERROR: Failed to cancel work: %d\n", ret);
|
||||
}
|
||||
|
||||
/* Set the media insertion/removal state */
|
||||
|
||||
priv->inserted = inserted;
|
||||
|
||||
/* Queue work to occur after a delay. The delays performs debouncing:
|
||||
* If the insertion/removal detection logic has "chatter", then we may
|
||||
* receive this interrupt numerous times. Each time, the previous work
|
||||
* will be cancelled (above) and the new work will scheduled with the
|
||||
* delay. So the final mount operation will not be performed until the
|
||||
* insertion state is stable for that delay.
|
||||
*/
|
||||
|
||||
ret = work_queue(LPWORK, &priv->work, automount_worker, priv,
|
||||
priv->lower->ddelay);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* NOTE: Currently, work_cancel only returns success */
|
||||
|
||||
fdbg("ERROR: Failed to schedule work: %d\n", ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cancel any retry delays */
|
||||
|
||||
(void)wd_cancel(priv->wdog);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_initialize
|
||||
*
|
||||
* Description:
|
||||
* Configure the automounter.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - Persistent board configuration data
|
||||
*
|
||||
* Returned Value:
|
||||
* A void* handle. The only use for this handle is with auto_uninitialize().
|
||||
* NULL is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *automount_initialize(FAR const struct automount_lower_s *lower)
|
||||
{
|
||||
FAR struct automounter_state_s *priv;
|
||||
int ret;
|
||||
|
||||
fvdbg("lower=%p\n", lower);
|
||||
DEBUGASSERT(lower);
|
||||
|
||||
/* Allocate an automounter state structure */
|
||||
|
||||
priv = (FAR struct automounter_state_s *)
|
||||
kzalloc(sizeof(struct automounter_state_s));
|
||||
|
||||
if (!priv)
|
||||
{
|
||||
fdbg("ERROR: Failed to allocate state structure\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the automounter state structure */
|
||||
|
||||
priv->lower = lower;
|
||||
|
||||
/* Get a timer to handle unmount retries */
|
||||
|
||||
priv->wdog = wd_create();
|
||||
if (!priv->wdog)
|
||||
{
|
||||
fdbg("ERROR: Failed to create a timer\n");
|
||||
auto_uninitialize(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Attach and enable automounter interrupts */
|
||||
|
||||
ret = AUTOMOUNT_ATTACH(lower, automount_interrupt, priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("ERROR: Failed to attach automount interrupt: %d\n", ret);
|
||||
auto_uninitialize(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AUTOMOUNT_ENABLE(lower);
|
||||
return priv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: auto_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* Stop the automounter and free resources that it used.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The value previously returned by automount_initialize();
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void auto_uninitialize(FAR void *handle)
|
||||
{
|
||||
FAR struct automounter_state_s *priv = (FAR struct automounter_state_s *)handle;
|
||||
FAR const struct automount_lower_s *lower;
|
||||
|
||||
DEBUGASSERT(priv && priv->lower);
|
||||
lower = priv->lower;
|
||||
|
||||
/* Disable and detach interrupts */
|
||||
|
||||
AUTOMOUNT_DISABLE(lower);
|
||||
(void)AUTOMOUNT_DETACH(lower);
|
||||
|
||||
/* Release resources */
|
||||
|
||||
(void)wd_delete(priv->wdog);
|
||||
|
||||
/* And free the state structure */
|
||||
|
||||
kfree(priv);
|
||||
}
|
191
include/nuttx/fs/automount.h
Normal file
191
include/nuttx/fs/automount.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/audio/automount.h
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_AUDIO_AUTOMOUNT_H
|
||||
#define __INCLUDE_NUTTX_AUDIO_AUTOMOUNT_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#ifdef CONFIG_FS_AUTOMOUNTER
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************
|
||||
* Automounter configuration
|
||||
* CONFIG_FS_AUTOMOUNTER - Enables automount support
|
||||
*
|
||||
* Prequisites:
|
||||
* CONFIG_SCHED_WORKQUEUE - Work queue support is required
|
||||
* And others that would only matter if you are working in a very minimal
|
||||
* configuration.
|
||||
*/
|
||||
|
||||
/* Helper macros ************************************************************/
|
||||
|
||||
#define AUTOMOUNT_ATTACH(s,isr,arg) ((s)->attach(s,isr,arg))
|
||||
#define AUTOMOUNT_DETACH(s) ((s)->attach(s,NULL,NULL))
|
||||
#define AUTOMOUNT_ENABLE(s) ((s)->enable(s,true))
|
||||
#define AUTOMOUNT_DISABLE(s) ((s)->enable(s,false))
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
/* This is the type of the automount media change handler. The lower level
|
||||
* code will intercept the interrupt and provide the upper level with the
|
||||
* private data that was provided when the interrupt was attached and will
|
||||
* also provide an indication if the media was inserted or removed.
|
||||
*/
|
||||
|
||||
struct automount_lower_s; /* Forward reference. Defined below */
|
||||
|
||||
typedef CODE int
|
||||
(*automount_handler_t)(FAR const struct automount_lower_s *lower,
|
||||
FAR void *arg, bool inserted);
|
||||
|
||||
/* A reference to a structure of this type must be passed to the FS
|
||||
* automounter. This structure provides information about the volume to be
|
||||
* mounted and provides board-specific hooks.
|
||||
*
|
||||
* Memory for this structure is provided by the caller. It is not copied
|
||||
* by the automounter and is presumed to persist while the automounter
|
||||
* is active.
|
||||
*/
|
||||
|
||||
struct automount_lower_s
|
||||
{
|
||||
/* Volume characterization */
|
||||
|
||||
FAR const char *fstype; /* Type of file system */
|
||||
FAR const char *blockdev; /* Path to the block device */
|
||||
FAR const char *mountpoint; /* Location to mount the volume */
|
||||
|
||||
/* Debounce delay in system clock ticks. Automount operation will not
|
||||
* be performed until the insertion/removal state has been unchanges
|
||||
* for this duration.
|
||||
*/
|
||||
|
||||
uint32_t ddelay;
|
||||
|
||||
/* Unmount delay time in sysem clock ticks. If a volume has open
|
||||
* references at the time that the media is removed, then we will be
|
||||
* unable to unmount it. In that case, hopefully, the clients of the
|
||||
* mount will eventually fail with file access errors and eventually close
|
||||
* their references. So, at some time later, it should be possible to
|
||||
* unmount the volume. This delay specifies the time between umount
|
||||
* retries.
|
||||
*/
|
||||
|
||||
uint32_t udelay;
|
||||
|
||||
/* Interrupt related operations all hidden behind callbacks to isolate the
|
||||
* automounter from differences in interrupt handling by varying boards
|
||||
* and MCUs. Board interrupts should be configured both insertion and
|
||||
* removal of the media can be detected.
|
||||
*
|
||||
* attach - Attach or detach the media change interrupt handler to the
|
||||
* board level interrupt
|
||||
* enable - Enable or disable the media change interrupt
|
||||
*/
|
||||
|
||||
CODE int (*attach)(FAR const struct automount_lower_s *lower,
|
||||
automount_handler_t isr, FAR void *arg);
|
||||
CODE void (*enable)(FAR const struct automount_lower_s *lower,
|
||||
bool enable);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: automount_initialize
|
||||
*
|
||||
* Description:
|
||||
* Configure the automounter.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - Persistent board configuration data
|
||||
*
|
||||
* Returned Value:
|
||||
* A void* handle. The only use for this handle is with auto_uninitialize().
|
||||
* NULL is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *automount_initialize(FAR const struct automount_lower_s *lower);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: auto_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* Stop the automounter and free resources that it used.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The value previously returned by automount_initialize();
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void auto_uninitialize(FAR void *handle);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_FS_AUTOMOUNTER */
|
||||
#endif /* __INCLUDE_NUTTX_AUDIO_AUTOMOUNT_H */
|
Loading…
Reference in a new issue