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:
parent
8807a52de6
commit
02a9228c1f
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue