Added USB MSC state change notifier in notifier work queue.

Added USB MSC automount for Freedom K28 using the above.
This commit is contained in:
Johannes Schock 2020-08-06 13:30:01 +02:00 committed by patacongo
parent 8807a52de6
commit 02a9228c1f
10 changed files with 572 additions and 118 deletions

View File

@ -33,4 +33,34 @@ config FRDMK28F_SDHC_AUTOMOUNT_UDELAY
default 2000
endif # FRDMK28F_SDHC_AUTOMOUNT
config FRDMK28F_USB_AUTOMOUNT
bool "USB Mass Storage automounter"
default n
depends on USBHOST_MSC && USBHOST_MSC_NOTIFIER
if FRDMK28F_USB_AUTOMOUNT
config FRDMK28F_USB_AUTOMOUNT_FSTYPE
string "USB file system type"
default "vfat"
config FRDMK28F_USB_AUTOMOUNT_BLKDEV
string "USB block device prefix"
default "/dev/sd"
config FRDMK28F_USB_AUTOMOUNT_MOUNTPOINT
string "USB mount point prefix"
default "/mnt/usb"
config FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV
int "Number of block devices to monitor."
range 1 26
default 4
config FRDMK28F_USB_AUTOMOUNT_UDELAY
int "USB unmount retry delay (milliseconds)"
default 2000
endif # FRDMK28F_USB_AUTOMOUNT
endif # ARCH_BOARD_FREEDOM_K28F

View File

@ -52,7 +52,13 @@
/* Assume we have everything */
#define HAVE_MMCSD 1
#define HAVE_AUTOMOUNTER 1
#define HAVE_USB_MSC 1
#ifdef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
# define HAVE_SDHC_AUTOMOUNTER 1
#endif
#ifdef CONFIG_FRDMK28F_USB_AUTOMOUNT
# define HAVE_USB_AUTOMOUNTER 1
#endif
/* SD card support */
@ -77,6 +83,12 @@
# define MMSCD_MINOR 0
# endif
/* Check for USB_HOST and USB_MSC */
#if defined(CONFIG_DISABLE_MOUNTPOINT) || \
!defined(CONFIG_KINETIS_USBHS) || !defined(CONFIG_USBHOST_MSC)
# undef HAVE_USB_MSC
#endif
/* We expect to receive GPIO interrupts for card insertion events */
# ifndef CONFIG_KINETIS_GPIOIRQ
@ -92,17 +104,16 @@
/* Automounter */
#if !defined(CONFIG_FS_AUTOMOUNTER) || !defined(HAVE_MMCSD)
# undef HAVE_AUTOMOUNTER
# undef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
# undef HAVE_SDHC_AUTOMOUNTER
#endif
#ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
# undef HAVE_AUTOMOUNTER
#if !defined(HAVE_USB_MSC) || !defined(CONFIG_USBHOST_MSC_NOTIFIER)
# undef HAVE_USB_AUTOMOUNTER
#endif
/* Automounter defaults */
#ifdef HAVE_AUTOMOUNTER
#ifdef HAVE_SDHC_AUTOMOUNTER
# ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_FSTYPE
# define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_FSTYPE "vfat"
@ -123,7 +134,30 @@
# ifndef CONFIG_FRDMK28F_SDHC_AUTOMOUNT_UDELAY
# define CONFIG_FRDMK28F_SDHC_AUTOMOUNT_UDELAY 2000
# endif
#endif /* HAVE_AUTOMOUNTER */
#endif /* HAVE_SDHC_AUTOMOUNTER */
#ifdef HAVE_USB_AUTOMOUNTER
# ifndef CONFIG_FRDMK28F_USB_AUTOMOUNT_FSTYPE
# define CONFIG_FRDMK28F_USB_AUTOMOUNT_FSTYPE "vfat"
# endif
# ifndef CONFIG_FRDMK28F_USB_AUTOMOUNT_BLKDEV
# define CONFIG_FRDMK28F_USB_AUTOMOUNT_BLKDEV "/dev/sd"
# endif
# ifndef CONFIG_FRDMK28F_USB_AUTOMOUNT_MOUNTPOINT
# define CONFIG_FRDMK28F_USB_AUTOMOUNT_MOUNTPOINT "/mnt/usb"
# endif
# ifndef CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV
# define CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV 4
# endif
# ifndef CONFIG_FRDMK28F_USB_AUTOMOUNT_UDELAY
# define CONFIG_FRDMK28F_USB_AUTOMOUNT_UDELAY 2000
# endif
#endif /* HAVE_USB_AUTOMOUNTER */
/* Freedom-K28F GPIOs *******************************************************/
@ -279,7 +313,7 @@ int k28_sdhc_initialize(void);
*
****************************************************************************/
#ifdef HAVE_AUTOMOUNTER
#ifdef HAVE_SDHC_AUTOMOUNTER
bool k28_cardinserted(void);
#else
# define k28_cardinserted() (false)
@ -293,32 +327,14 @@ bool k28_cardinserted(void);
*
****************************************************************************/
#ifdef HAVE_AUTOMOUNTER
#ifdef HAVE_SDHC_AUTOMOUNTER
bool k28_writeprotected(void);
#else
# define k28_writeprotected() (false)
#endif
/****************************************************************************
* Name: k28_automount_initialize
*
* Description:
* Configure auto-mounter for the configured SDHC slot
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef HAVE_AUTOMOUNTER
void k28_automount_initialize(void);
#endif
/****************************************************************************
* Name: k28_automount_event
* Name: k28_sdhc_automount_event
*
* Description:
* The SDHC card detection logic has detected an insertion or removal
@ -338,8 +354,26 @@ void k28_automount_initialize(void);
*
****************************************************************************/
#ifdef HAVE_AUTOMOUNTER
void k28_automount_event(bool inserted);
#ifdef HAVE_SDHC_AUTOMOUNTER
void k28_sdhc_automount_event(bool inserted);
#endif
/****************************************************************************
* Name: k28_automount_initialize
*
* Description:
* Configure auto-mounter for the configured SDHC slot
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#if defined(HAVE_SDHC_AUTOMOUNTER) || defined(HAVE_USB_AUTOMOUNTER)
void k28_automount_initialize(void);
#endif
/****************************************************************************

View File

@ -36,7 +36,7 @@
#include "freedom-k28f.h"
#ifdef HAVE_AUTOMOUNTER
#ifdef HAVE_SDHC_AUTOMOUNTER
/****************************************************************************
* Pre-processor Definitions
@ -80,11 +80,11 @@ struct k28_automount_config_s
* Private Function Prototypes
****************************************************************************/
static int k28_attach(FAR const struct automount_lower_s *lower,
static int k28_sdhc_attach(FAR const struct automount_lower_s *lower,
automount_handler_t isr, FAR void *arg);
static void k28_enable(FAR const struct automount_lower_s *lower,
static void k28_sdhc_enable(FAR const struct automount_lower_s *lower,
bool enable);
static bool k28_inserted(FAR const struct automount_lower_s *lower);
static bool k28_sdhc_inserted(FAR const struct automount_lower_s *lower);
/****************************************************************************
* Private Data
@ -100,9 +100,9 @@ static const struct k28_automount_config_s g_sdhc_config =
.mountpoint = CONFIG_FRDMK28F_SDHC_AUTOMOUNT_MOUNTPOINT,
.ddelay = MSEC2TICK(CONFIG_FRDMK28F_SDHC_AUTOMOUNT_DDELAY),
.udelay = MSEC2TICK(CONFIG_FRDMK28F_SDHC_AUTOMOUNT_UDELAY),
.attach = k28_attach,
.enable = k28_enable,
.inserted = k28_inserted
.attach = k28_sdhc_attach,
.enable = k28_sdhc_enable,
.inserted = k28_sdhc_inserted
},
.state = &g_sdhc_state
};
@ -112,7 +112,7 @@ static const struct k28_automount_config_s g_sdhc_config =
****************************************************************************/
/****************************************************************************
* Name: k28_attach
* Name: k28_sdhc_attach
*
* Description:
* Attach a new SDHC event handler
@ -127,7 +127,7 @@ static const struct k28_automount_config_s g_sdhc_config =
*
****************************************************************************/
static int k28_attach(FAR const struct automount_lower_s *lower,
static int k28_sdhc_attach(FAR const struct automount_lower_s *lower,
automount_handler_t isr, FAR void *arg)
{
FAR const struct k28_automount_config_s *config;
@ -152,7 +152,7 @@ static int k28_attach(FAR const struct automount_lower_s *lower,
}
/****************************************************************************
* Name: k28_enable
* Name: k28_sdhc_enable
*
* Description:
* Enable card insertion/removal event detection
@ -166,7 +166,7 @@ static int k28_attach(FAR const struct automount_lower_s *lower,
*
****************************************************************************/
static void k28_enable(FAR const struct automount_lower_s *lower,
static void k28_sdhc_enable(FAR const struct automount_lower_s *lower,
bool enable)
{
FAR const struct k28_automount_config_s *config;
@ -204,7 +204,7 @@ static void k28_enable(FAR const struct automount_lower_s *lower,
}
/****************************************************************************
* Name: k28_inserted
* Name: k28_sdhc_inserted
*
* Description:
* Check if a card is inserted into the slot.
@ -217,7 +217,7 @@ static void k28_enable(FAR const struct automount_lower_s *lower,
*
****************************************************************************/
static bool k28_inserted(FAR const struct automount_lower_s *lower)
static bool k28_sdhc_inserted(FAR const struct automount_lower_s *lower)
{
return k28_cardinserted();
}
@ -226,6 +226,59 @@ static bool k28_inserted(FAR const struct automount_lower_s *lower)
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: k28_sdhc_automount_event
*
* Description:
* The SDHC card detection logic has detected an insertion or removal
* event.
* It has already scheduled the MMC/SD block driver operations.
* Now we need to schedule the auto-mount event which will occur with a
* substantial delay to make sure that everything has settle down.
*
* Input Parameters:
* slotno - Identifies the SDHC0 slot: SDHC0_SLOTNO or SDHC1_SLOTNO.
* There is a terminology problem here: Each SDHC supports two slots,
* slot A and slot B. Only slot A is used.
* So this is not a really a slot, but an HSCMI peripheral number.
* inserted - True if the card is inserted in the slot. False otherwise.
*
* Returned Value:
* None
*
* Assumptions:
* Interrupts are disabled.
*
****************************************************************************/
void k28_sdhc_automount_event(bool inserted)
{
FAR const struct k28_automount_config_s *config = &g_sdhc_config;
FAR struct k28_automount_state_s *state = &g_sdhc_state;
/* Is the auto-mounter interrupt attached? */
if (state->handler)
{
/* Yes.. Have we been asked to hold off interrupts? */
if (!state->enable)
{
/* Yes.. just remember that there is a pending interrupt. We will
* deliver the interrupt when interrupts are "re-enabled."
*/
state->pending = true;
}
else
{
/* No.. forward the event to the handler */
state->handler(&config->lower, state->arg, inserted);
}
}
}
/****************************************************************************
* Name: k28_automount_initialize
*
@ -255,56 +308,4 @@ void k28_automount_initialize(void)
}
}
/****************************************************************************
* Name: k28_automount_event
*
* Description:
* The SDHC card detection logic has detected an insertion or removal event.
* It has already scheduled the MMC/SD block driver operations.
* Now we need to schedule the auto-mount event which will occur with a
* substantial delay to make sure that everything has settle down.
*
* Input Parameters:
* slotno - Identifies the SDHC0 slot: SDHC0_SLOTNO or SDHC1_SLOTNO.
* There is a terminology problem here: Each SDHC supports two slots,
* slot A and slot B. Only slot A is used.
* So this is not a really a slot, but an HSCMI peripheral number.
* inserted - True if the card is inserted in the slot. False otherwise.
*
* Returned Value:
* None
*
* Assumptions:
* Interrupts are disabled.
*
****************************************************************************/
void k28_automount_event(bool inserted)
{
FAR const struct k28_automount_config_s *config = &g_sdhc_config;
FAR struct k28_automount_state_s *state = &g_sdhc_state;
/* Is the auto-mounter interrupt attached? */
if (state->handler)
{
/* Yes.. Have we been asked to hold off interrupts? */
if (!state->enable)
{
/* Yes.. just remember that there is a pending interrupt. We will
* deliver the interrupt when interrupts are "re-enabled."
*/
state->pending = true;
}
else
{
/* No.. forward the event to the handler */
state->handler(&config->lower, state->arg, inserted);
}
}
}
#endif /* HAVE_AUTOMOUNTER */
#endif /* HAVE_SDHC_AUTOMOUNTER */

View File

@ -118,12 +118,6 @@ int k28_bringup(void)
#endif /* CONFIG_FRDMK28F_SDHC_MOUNT */
#endif /* HAVE_MMCSD */
#ifdef HAVE_AUTOMOUNTER
/* Initialize the auto-mounter */
k28_automount_initialize();
#endif
#if defined(CONFIG_USBDEV) && defined(CONFIG_KINETIS_USBOTG)
if (k28_usbdev_initialize)
{
@ -154,9 +148,17 @@ int k28_bringup(void)
#endif
#if defined(CONFIG_USBHOST) && defined(CONFIG_KINETIS_USBHS)
/* Initialize the USB highspeed host */
k28_usbhost_initialize();
#endif
#ifdef HAVE_SDHC_AUTOMOUNTER
/* Initialize the auto-mounter */
k28_automount_initialize();
#endif
UNUSED(ret);
return OK;
}

View File

@ -109,15 +109,17 @@ static void k28_mediachange(void)
{
mcinfo("Media change: %d->%d\n", g_sdhc.inserted, inserted);
/* Yes.. perform the appropriate action (this might need some debounce). */
/* Yes.. perform the appropriate action
* (this might need some debounce).
*/
g_sdhc.inserted = inserted;
sdhc_mediachange(g_sdhc.sdhc, inserted);
#ifdef CONFIG_FRDMK28F_SDHC_AUTOMOUNT
#ifdef HAVE_SDHC_AUTOMOUNTER
/* Let the automounter know about the insertion event */
k28_automount_event(k28_cardinserted());
k28_sdhc_automount_event(k28_cardinserted());
#endif
}
}
@ -180,7 +182,8 @@ int k28_sdhc_initialize(void)
ret = mmcsd_slotinitialize(MMSCD_MINOR, g_sdhc.sdhc);
if (ret != OK)
{
syslog(LOG_ERR, "ERROR: Failed to bind SDHC to the MMC/SD driver: %d\n",
syslog(LOG_ERR,
"ERROR: Failed to bind SDHC to the MMC/SD driver: %d\n",
ret);
return ret;
}
@ -205,7 +208,7 @@ int k28_sdhc_initialize(void)
*
****************************************************************************/
#ifdef HAVE_AUTOMOUNTER
#ifdef HAVE_SDHC_AUTOMOUNTER
bool k28_cardinserted(void)
{
bool inserted;
@ -228,7 +231,7 @@ bool k28_cardinserted(void)
*
****************************************************************************/
#ifdef HAVE_AUTOMOUNTER
#ifdef HAVE_SDHC_AUTOMOUNTER
bool k28_writeprotected(void)
{
/* There are no write protect pins */

View File

@ -42,6 +42,7 @@
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <sched.h>
#include <errno.h>
#include <assert.h>
@ -54,6 +55,8 @@
#include <nuttx/usb/usbdev_trace.h>
#include <nuttx/usb/ehci.h>
#include <sys/mount.h>
#include <kinetis_usbhshost.h>
#include "arm_arch.h"
@ -88,6 +91,19 @@
# endif
#endif
/*****************************************************************************
* Private Function Prototypes
*****************************************************************************/
static int ehci_waiter(int argc, char *argv[]);
static void ehci_hwinit(void);
# ifdef HAVE_USB_AUTOMOUNTER
static void usb_msc_connect(FAR void *arg);
static void unmount_retry_timeout(int argc, uint32_t arg1, ...);
static void usb_msc_disconnect(FAR void *arg);
# endif
/*****************************************************************************
* Private Data
*****************************************************************************/
@ -96,6 +112,12 @@
static struct usbhost_connection_s *g_ehciconn;
# ifdef HAVE_USB_AUTOMOUNTER
/* Unmount retry timer */
static WDOG_ID g_umount_tmr[CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV];
# endif
/*****************************************************************************
* Private Functions
*****************************************************************************/
@ -232,6 +254,152 @@ static void ehci_hwinit(void)
putreg32(regval, KINETIS_USBHSPHY_CTRL);
}
# ifdef HAVE_USB_AUTOMOUNTER
/*****************************************************************************
* Name: usb_msc_connect
*
* Description:
* Mount the USB mass storage device
*
*****************************************************************************/
static void usb_msc_connect(FAR void *arg)
{
int index = (int)arg;
char sdchar = 'a' + index;
int ret;
char blkdev[32];
char mntpnt[32];
DEBUGASSERT(index >= 0 && index < CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV);
wd_cancel(g_umount_tmr[index]);
/* Resetup the event. */
usbhost_msc_notifier_setup(usb_msc_connect, WORK_USB_MSC_CONNECT,
sdchar, arg);
snprintf(blkdev, sizeof(blkdev), "%s%c",
CONFIG_FRDMK28F_USB_AUTOMOUNT_BLKDEV, sdchar);
snprintf(mntpnt, sizeof(mntpnt), "%s%c",
CONFIG_FRDMK28F_USB_AUTOMOUNT_MOUNTPOINT, sdchar);
/* Mount */
ret = mount((FAR const char *)blkdev, (FAR const char *)mntpnt,
CONFIG_FRDMK28F_USB_AUTOMOUNT_FSTYPE, 0, NULL);
if (ret < 0)
{
int errcode = get_errno();
DEBUGASSERT(errcode > 0);
ferr("ERROR: Mount failed: %d\n", errcode);
UNUSED(errcode);
}
}
/*****************************************************************************
* Name: unmount_retry_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 unmount_retry_timeout(int argc, uint32_t arg1, ...)
{
int index = (int)arg1;
char sdchar = 'a' + index;
finfo("Timeout!\n");
DEBUGASSERT(argc == 1 && \
index >= 0 && index < CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV);
/* Resend the notification. */
usbhost_msc_notifier_signal(WORK_USB_MSC_DISCONNECT, sdchar);
}
/*****************************************************************************
* Name: usb_msc_disconnect
*
* Description:
* Unmount the USB mass storage device
*
*****************************************************************************/
static void usb_msc_disconnect(FAR void *arg)
{
int index = (int)arg;
char sdchar = 'a' + index;
int ret;
char mntpnt[32];
DEBUGASSERT(index >= 0 && index < CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV);
wd_cancel(g_umount_tmr[index]);
/* Resetup the event. */
usbhost_msc_notifier_setup(usb_msc_disconnect, WORK_USB_MSC_DISCONNECT,
sdchar, arg);
snprintf(mntpnt, sizeof(mntpnt), "%s%c",
CONFIG_FRDMK28F_USB_AUTOMOUNT_MOUNTPOINT, sdchar);
/* Unmount */
ret = umount2((FAR const char *)mntpnt, MNT_FORCE);
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)
{
finfo("WARNING: Volume is busy, try again later\n");
/* Start a timer to retry the umount2 after a delay */
ret = wd_start(g_umount_tmr[index],
MSEC2TICK(CONFIG_FRDMK28F_USB_AUTOMOUNT_UDELAY),
unmount_retry_timeout, 1, (uint32_t)index);
if (ret < 0)
{
ferr("ERROR: wd_start failed: %d\n", ret);
}
}
/* Other errors are fatal */
else
{
ferr("ERROR: Unmount failed: %d\n", errcode);
}
}
}
# endif /* HAVE_USB_AUTOMOUNTER */
/*****************************************************************************
* Public Functions
*****************************************************************************/
@ -251,6 +419,9 @@ int k28_usbhost_initialize(void)
{
pid_t pid;
int ret;
# ifdef HAVE_USB_AUTOMOUNTER
int index;
# endif
/* First, register all of the class drivers needed to support the drivers
* that we care about
@ -269,6 +440,22 @@ int k28_usbhost_initialize(void)
#ifdef CONFIG_USBHOST_MSC
/* Register the USB host Mass Storage Class */
# ifdef HAVE_USB_AUTOMOUNTER
/* Initialize the notifier listener for automount */
for (index = 0; index < CONFIG_FRDMK28F_USB_AUTOMOUNT_NUM_BLKDEV; index++)
{
char sdchar = 'a' + index;
g_umount_tmr[index] = wd_create();
usbhost_msc_notifier_setup(usb_msc_connect,
WORK_USB_MSC_CONNECT, sdchar, (FAR void *)(intptr_t)index);
usbhost_msc_notifier_setup(usb_msc_disconnect,
WORK_USB_MSC_DISCONNECT, sdchar, (FAR void *)(intptr_t)index);
}
# endif
ret = usbhost_msc_initialize();
if (ret != OK)
{

View File

@ -108,7 +108,17 @@ config USBHOST_MSC
---help---
Enable support for the mass storage class driver. This also depends on
NFILE_DESCRIPTORS > 0 && SCHED_WORKQUEUE=y
config USBHOST_MSC_NOTIFIER
bool "Support USB Mass Storage notifications"
default n
depends on USBHOST_MSC
select WQUEUE_NOTIFIER
---help---
Enable building of USB MSC notifier logic that will execute a worker
function on the low priority work queue when a mass storage device is
connected or disconnected.
config USBHOST_CDCACM
bool "CDC/ACM support"
default n

View File

@ -1400,6 +1400,14 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
ret = -ENODEV;
}
# ifdef CONFIG_USBHOST_MSC_NOTIFIER
else
{
/* Signal the connect */
usbhost_msc_notifier_signal(WORK_USB_MSC_CONNECT, priv->sdchar);
}
# endif
/* Release the semaphore... there is a race condition here.
* Decrementing the reference count and releasing the semaphore
@ -1409,6 +1417,7 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
*/
usbhost_givesem(&priv->exclsem);
return ret;
}
@ -1848,6 +1857,12 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass)
DEBUGASSERT(priv != NULL);
# ifdef CONFIG_USBHOST_MSC_NOTIFIER
/* Signal the disconnect */
usbhost_msc_notifier_signal(WORK_USB_MSC_DISCONNECT, priv->sdchar);
# endif
/* Set an indication to any users of the mass storage device that the
* device is no longer available.
*/
@ -2360,4 +2375,98 @@ int usbhost_msc_initialize(void)
return usbhost_registerclass(&g_storage);
}
# ifdef CONFIG_USBHOST_MSC_NOTIFIER
/****************************************************************************
* Name: usbhost_msc_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function when a mass storage
* device is attached.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work queue
* when the event occurs.
* event - Currently only USBHOST_MSC_DISCONNECT and USBHOST_MSC_CONNECT
* sdchar - sdchar of the connected or disconnected block device
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The notification is in place. The returned value is a key that
* may be used later in a call to
* usbmsc_attach_notifier_teardown().
* == 0 - Not used.
* < 0 - An unexpected error occurred and no notification will occur. The
* returned value is a negated errno value that indicates the
* nature of the failure.
*
****************************************************************************/
int usbhost_msc_notifier_setup(worker_t worker, uint8_t event, char sdchar,
FAR void *arg)
{
struct work_notifier_s info;
DEBUGASSERT(worker != NULL);
info.evtype = event;
info.qid = LPWORK;
info.qualifier = (FAR void *)(uintptr_t)sdchar;
info.arg = arg;
info.worker = worker;
return work_notifier_setup(&info);
}
/****************************************************************************
* Name: usbhost_msc_notifier_teardown
*
* Description:
* Eliminate an USB MSC notification previously setup by
* usbhost_msc_notifier_setup().
* This function should only be called if the notification should be
* aborted prior to the notification. The notification will automatically
* be torn down after the notification.
*
* Input Parameters:
* key - The key value returned from a previous call to
* usbhost_msc_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int usbhost_msc_notifier_teardown(int key)
{
/* This is just a simple wrapper around work_notifier_teardown(). */
return work_notifier_teardown(key);
}
/****************************************************************************
* Name: usbhost_msc_notifier_signal
*
* Description:
* An USB mass storage device has been connected or disconnected.
* Signal all threads.
*
* Input Parameters:
* event - Currently only USBHOST_MSC_DISCONNECT and USBHOST_MSC_CONNECT
* sdchar - sdchar of the connected or disconnected block device
*
* Returned Value:
* None.
*
****************************************************************************/
void usbhost_msc_notifier_signal(uint8_t event, char sdchar)
{
work_notifier_signal(event, (FAR void *)(uintptr_t)sdchar);
}
# endif /* CONFIG_USBHOST_MSC_NOTIFIER */
#endif /* CONFIG_USBHOST && !CONFIG_USBHOST_BULK_DISABLE && !CONFIG_DISABLE_MOUNTPOINT */

View File

@ -39,6 +39,10 @@
#include <stdint.h>
#include <stdbool.h>
#ifdef CONFIG_USBHOST_MSC_NOTIFIER
# include <nuttx/wqueue.h>
#endif
#include <nuttx/usb/usbhost_devaddr.h>
/************************************************************************************
@ -1014,6 +1018,78 @@ int usbhost_hub_initialize(void);
************************************************************************************/
int usbhost_msc_initialize(void);
# ifdef CONFIG_USBHOST_MSC_NOTIFIER
/************************************************************************************
* Name: usbhost_msc_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function when a mass storage
* device is attached.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work queue
* when the event occurs.
* event - Only WORK_USB_MSC_CONNECT and WORK_USB_MSC_DISCONNECT
* sdchar - sdchar of the connected or disconnected block device
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The notification is in place. The returned value is a key that
* may be used later in a call to
* usbmsc_attach_notifier_teardown().
* == 0 - Not used.
* < 0 - An unexpected error occurred and no notification will occur. The
* returned value is a negated errno value that indicates the
* nature of the failure.
*
************************************************************************************/
int usbhost_msc_notifier_setup(worker_t worker, uint8_t event, char sdchar,
FAR void *arg);
/************************************************************************************
* Name: usbhost_msc_notifier_teardown
*
* Description:
* Eliminate an USB MSC notification previously setup by
* usbhost_msc_notifier_setup().
* This function should only be called if the notification should be
* aborted prior to the notification. The notification will automatically
* be torn down after the notification.
*
* Input Parameters:
* key - The key value returned from a previous call to
* usbhost_msc_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
************************************************************************************/
int usbhost_msc_notifier_teardown(int key);
/************************************************************************************
* Name: usbhost_msc_notifier_signal
*
* Description:
* An USB mass storage device has been connected or disconnected.
* Signal all threads.
*
* Input Parameters:
* event - Currently only USBHOST_MSC_DISCONNECT and USBHOST_MSC_CONNECT
* sdchar - sdchar of the connected or disconnected block device
*
* Returned Value:
* None.
*
************************************************************************************/
void usbhost_msc_notifier_signal(uint8_t event, char sdchar);
# endif
#endif
#ifdef CONFIG_USBHOST_CDCACM

View File

@ -273,15 +273,17 @@ struct work_s
enum work_evtype_e
{
WORK_IOB_AVAIL = 1, /* Notify availability of an IOB */
WORK_NET_DOWN, /* Notify that the network is down */
WORK_TCP_READAHEAD, /* Notify that TCP read-ahead data is available */
WORK_TCP_WRITEBUFFER, /* Notify that TCP write buffer is empty */
WORK_TCP_DISCONNECT, /* Notify loss of TCP connection */
WORK_UDP_READAHEAD, /* Notify that UDP read-ahead data is available */
WORK_UDP_WRITEBUFFER, /* Notify that UDP write buffer is empty */
WORK_NETLINK_RESPONSE, /* Notify that Netlink response is available */
WORK_CAN_READAHEAD /* Notify that CAN read-ahead data is available */
WORK_IOB_AVAIL = 1, /* Notify availability of an IOB */
WORK_NET_DOWN, /* Notify that the network is down */
WORK_TCP_READAHEAD, /* Notify that TCP read-ahead data is available */
WORK_TCP_WRITEBUFFER, /* Notify that TCP write buffer is empty */
WORK_TCP_DISCONNECT, /* Notify loss of TCP connection */
WORK_UDP_READAHEAD, /* Notify that UDP read-ahead data is available */
WORK_UDP_WRITEBUFFER, /* Notify that UDP write buffer is empty */
WORK_NETLINK_RESPONSE, /* Notify that Netlink response is available */
WORK_CAN_READAHEAD, /* Notify that CAN read-ahead data is available */
WORK_USB_MSC_CONNECT, /* Notify that an USB MSC connect occured */
WORK_USB_MSC_DISCONNECT /* Notify that an USB MSC connect occured */
};
/* This structure describes one notification and is provided as input to