USB host MS class compiles

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3186 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2010-12-16 01:29:51 +00:00
parent e9c523ac51
commit 3f103dacc9
4 changed files with 158 additions and 53 deletions
+1 -1
View File
@@ -202,7 +202,7 @@ static const struct usb_ifdesc_s g_ifdesc =
USBSTRG_ALTINTERFACEID, /* alt */ USBSTRG_ALTINTERFACEID, /* alt */
USBSTRG_NENDPOINTS, /* neps */ USBSTRG_NENDPOINTS, /* neps */
USB_CLASS_MASS_STORAGE, /* class */ USB_CLASS_MASS_STORAGE, /* class */
SUBSTRG_SUBCLASS_SCSI, /* subclass */ USBSTRG_SUBCLASS_SCSI, /* subclass */
USBSTRG_PROTO_BULKONLY, /* protocol */ USBSTRG_PROTO_BULKONLY, /* protocol */
USBSTRG_CONFIGSTRID /* iif */ USBSTRG_CONFIGSTRID /* iif */
}; };
+1
View File
@@ -38,4 +38,5 @@ USBHOST_CSRCS =
ifeq ($(CONFIG_USBHOST),y) ifeq ($(CONFIG_USBHOST),y)
USBHOST_CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c USBHOST_CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c
USBHOST_CSRCS += usbhost_storage.c
endif endif
+151 -47
View File
@@ -39,15 +39,21 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <debug.h> #include <debug.h>
#include <nuttx/fs.h> #include <nuttx/fs.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/wqueue.h> #include <nuttx/wqueue.h>
#include <nuttx/usb/usb.h> #include <nuttx/usb/usb.h>
#include <nuttx/usb/usbhost.h> #include <nuttx/usb/usbhost.h>
#include <nuttx/usb/usb_storage.h>
#if defined(CONFIG_USBHOST) && !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 #if defined(CONFIG_USBHOST) && !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0
@@ -75,6 +81,7 @@
# error "Currently limited to 26 devices /dev/sda-z" # error "Currently limited to 26 devices /dev/sda-z"
#endif #endif
/* Driver support ***********************************************************/
/* This format is used to construct the /dev/sd[n] device driver path. It /* This format is used to construct the /dev/sd[n] device driver path. It
* defined here so that it will be used consistently in all places. * defined here so that it will be used consistently in all places.
*/ */
@@ -82,6 +89,13 @@
#define DEV_FORMAT "/dev/sd%c" #define DEV_FORMAT "/dev/sd%c"
#define DEV_NAMELEN 10 #define DEV_NAMELEN 10
/* Used in usbhost_configdesc() */
#define USBHOST_IFFOUND 0x01
#define USBHOST_BINFOUND 0x02
#define USBHOST_BOUTFOUND 0x04
#define USBHOST_ALLFOUND 0x07
/**************************************************************************** /****************************************************************************
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
@@ -106,6 +120,7 @@ struct usbhost_state_s
char sdchar; /* Character identifying the /dev/sd[n] device */ char sdchar; /* Character identifying the /dev/sd[n] device */
uint16_t blocksize; /* Block size of USB mass storage device */ uint16_t blocksize; /* Block size of USB mass storage device */
uint32_t nblocks; /* Number of blocks on the USB mass storage device */ uint32_t nblocks; /* Number of blocks on the USB mass storage device */
sem_t sem; /* Used to maintain mutual exclusive access */
struct work_s work; /* For interacting with the worker thread */ struct work_s work; /* For interacting with the worker thread */
struct usbhost_epdesc_s bulkin; /* Bulk IN endpoint */ struct usbhost_epdesc_s bulkin; /* Bulk IN endpoint */
struct usbhost_epdesc_s bulkout; /* Bulk OUT endpoint */ struct usbhost_epdesc_s bulkout; /* Bulk OUT endpoint */
@@ -115,10 +130,15 @@ struct usbhost_state_s
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
/* Semaphores */
static void usbhost_takesem(FAR struct usbhost_state_s *priv);
#define usbhost_givesem(p) sem_post(&priv->sem);
/* Memory allocation services */ /* Memory allocation services */
static inline struct usbhost_state_s *usbhost_allocclass(void); static inline struct usbhost_state_s *usbhost_allocclass(void);
static inline usbhost_freeclass(struct usbhost_state_s *class); static inline void usbhost_freeclass(struct usbhost_state_s *class);
/* Device name management */ /* Device name management */
@@ -129,6 +149,7 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev
/* Worker thread actions */ /* Worker thread actions */
static void usbhost_destroy(FAR void *arg); static void usbhost_destroy(FAR void *arg);
static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker);
/* Data helpers */ /* Data helpers */
@@ -173,7 +194,7 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd,
static const const struct usbhost_id_s g_id = static const const struct usbhost_id_s g_id =
{ {
USB_CLASS_MASS_STORAGE, /* base */ USB_CLASS_MASS_STORAGE, /* base */
SUBSTRG_SUBCLASS_SCSI, /* subclass */ USBSTRG_SUBCLASS_SCSI, /* subclass */
USBSTRG_PROTO_BULKONLY, /* proto */ USBSTRG_PROTO_BULKONLY, /* proto */
0, /* vid */ 0, /* vid */
0 /* pid */ 0 /* pid */
@@ -227,6 +248,29 @@ static uint32_t g_devinuse;
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Name: usbhost_takesem
*
* Description:
* This is just a wrapper to handle the annoying behavior of semaphore
* waits that return due to the receipt of a signal.
*
****************************************************************************/
static void usbhost_takesem(FAR struct usbhost_state_s *priv)
{
/* Take the semaphore (perhaps waiting) */
while (sem_wait(&priv->sem) != 0)
{
/* The only case that an error should occr here is if the wait was
* awakened by a signal.
*/
ASSERT(errno == EINTR);
}
}
/**************************************************************************** /****************************************************************************
* Name: usbhost_allocclass * Name: usbhost_allocclass
* *
@@ -293,7 +337,7 @@ static inline struct usbhost_state_s *usbhost_allocclass(void)
****************************************************************************/ ****************************************************************************/
#if CONFIG_USBHOST_NPREALLOC > 0 #if CONFIG_USBHOST_NPREALLOC > 0
static inline usbhost_freeclass(struct usbhost_state_s *class) static inline void usbhost_freeclass(struct usbhost_state_s *class)
{ {
irqstate_t flags; irqstate_t flags;
DEBUGASSERT(class != NULL); DEBUGASSERT(class != NULL);
@@ -306,7 +350,7 @@ static inline usbhost_freeclass(struct usbhost_state_s *class)
irqrestore(flags); irqrestore(flags);
} }
#else #else
static inline usbhost_freeclass(struct usbhost_state_s *class) static inline void usbhost_freeclass(struct usbhost_state_s *class)
{ {
DEBUGASSERT(class != NULL); DEBUGASSERT(class != NULL);
@@ -360,7 +404,7 @@ static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
} }
} }
static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname); static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname)
{ {
(void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar); (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar);
} }
@@ -404,6 +448,74 @@ static void usbhost_destroy(FAR void *arg)
usbhost_freeclass(priv); usbhost_freeclass(priv);
} }
/****************************************************************************
* Name: usbhost_configluns
*
* Description:
* The USB mass storage device has been successfully connected. Now get
* information about the connect LUNs.
*
* Input Parameters:
* arg - A reference to the class instance to be freed.
*
* Returned Values:
* None
*
****************************************************************************/
static void usbhost_configluns(FAR void *arg)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
/* Get the maximum logical unit number */
/* Check if the unit is ready */
/* Get sense information */
/* Read the capacity of the volume */
/* Register the block driver */
#warning "Missing Logic"
}
/****************************************************************************
* Name: usbhost_work
*
* Description:
* Perform work, depending on context: If we are executing from an
* interrupt handler, then defer the work to the worker thread. Otherwise,
* just execute the work now.
*
* Input Parameters:
* priv - A reference to the class instance to be freed.
* worker - A reference to the worker function to be executed
*
* Returned Values:
* A uin16_t representing the whole 16-bit integer value
*
****************************************************************************/
static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker)
{
/* Are we in an interrupt handler? */
if (up_interrupt_context())
{
/* Yes.. do the work on the worker thread. Higher level logic should
* prevent us from over-running the work structure.
*/
(void)work_queue(&priv->work, worker, priv, 0);
}
else
{
/* No.. do the work now */
worker(priv);
}
}
/**************************************************************************** /****************************************************************************
* Name: usbhost_getint16 * Name: usbhost_getint16
* *
@@ -420,7 +532,7 @@ static void usbhost_destroy(FAR void *arg)
static inline uint16_t usbhost_getint16(const uint8_t *val) static inline uint16_t usbhost_getint16(const uint8_t *val)
{ {
return (uint16_t)val[1] << 8 + (uint16_t)val[0]; return (uint16_t)val[1] << 8 | (uint16_t)val[0];
} }
/**************************************************************************** /****************************************************************************
@@ -461,12 +573,12 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
/* Allocate a USB host mass storage class instance */ /* Allocate a USB host mass storage class instance */
priv = usbhost_allocclass(void); priv = usbhost_allocclass();
if (priv) if (priv)
{ {
/* Initialize the allocated storage class instance */ /* Initialize the allocated storage class instance */
memset(priv, 0, sizeof(struct usbhost_state_s); memset(priv, 0, sizeof(struct usbhost_state_s));
/* Assign a device number to this class instance */ /* Assign a device number to this class instance */
@@ -492,7 +604,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
if (priv) if (priv)
{ {
usbhost_free(priv); usbhost_freeclass(priv);
} }
return NULL; return NULL;
} }
@@ -523,17 +635,16 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
static int usbhost_configdesc(FAR struct usbhost_class_s *class, static int usbhost_configdesc(FAR struct usbhost_class_s *class,
FAR const uint8_t *configdesc, int desclen) FAR const uint8_t *configdesc, int desclen)
{ {
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
FAR struct usb_cfgdesc_s *cfgdesc; FAR struct usb_cfgdesc_s *cfgdesc;
FAR struct usb_desc_s *desc; FAR struct usb_desc_s *desc;
int remaining; int remaining;
bool iffound = false; uint8_t found = 0;
bool boutfound = false;
bool binfound = false;
/* Verify that we were passed a configuration descriptor */ /* Verify that we were passed a configuration descriptor */
cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc; cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
if (desc->type != USB_DESC_TYPE_CONFIG) if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
{ {
return -EINVAL; return -EINVAL;
} }
@@ -546,8 +657,8 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
/* Skip to the next entry descriptor */ /* Skip to the next entry descriptor */
configdesc += desc->len; configdesc += cfgdesc->len;
remaining -= desc->len; remaining -= cfgdesc->len;
/* Loop where there are more dscriptors to examine */ /* Loop where there are more dscriptors to examine */
@@ -565,13 +676,13 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
case USB_DESC_TYPE_INTERFACE: case USB_DESC_TYPE_INTERFACE:
{ {
DEBUGASSERT(remaining >= sizeof(struct usb_ifdesc_s)); DEBUGASSERT(remaining >= sizeof(struct usb_ifdesc_s));
if (iffound) if ((found & USBHOST_IFFOUND) != 0)
{ {
/* Oops.. more than one interface. We don't know what to do with this. */ /* Oops.. more than one interface. We don't know what to do with this. */
return -ENOSYS; return -ENOSYS;
} }
iffound = true; found |= USBHOST_IFFOUND;
} }
break; break;
@@ -593,37 +704,37 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
{ {
/* It is an OUT bulk endpoint. There should be only one bulk OUT endpoint. */ /* It is an OUT bulk endpoint. There should be only one bulk OUT endpoint. */
if (boutfound) if ((found & USBHOST_BOUTFOUND) != 0)
{ {
/* Oops.. more than one interface. We don't know what to do with this. */ /* Oops.. more than one interface. We don't know what to do with this. */
return -EINVAL; return -EINVAL;
} }
boutfound = true; found |= USBHOST_BOUTFOUND;
/* Save the bulk OUT endpoint information */ /* Save the bulk OUT endpoint information */
priv->bulkout.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; priv->bulkout.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
priv->bulkout.in = false; priv->bulkout.in = false;
priv->bulkout.mxpacketsize = usbhost_getint16(pdesc->mxpacketsize); priv->bulkout.mxpacketsize = usbhost_getint16(epdesc->mxpacketsize);
} }
else else
{ {
/* It is an IN bulk endpoint. There should be only one bulk IN endpoint. */ /* It is an IN bulk endpoint. There should be only one bulk IN endpoint. */
if (binfound) if ((found & USBHOST_BINFOUND) != 0)
{ {
/* Oops.. more than one interface. We don't know what to do with this. */ /* Oops.. more than one interface. We don't know what to do with this. */
return -EINVAL; return -EINVAL;
} }
binfound = true; found |= USBHOST_BINFOUND;
/* Save the bulk IN endpoint information */ /* Save the bulk IN endpoint information */
priv->bulkin.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; priv->bulkin.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
priv->bulkin.in = true; priv->bulkin.in = true;
priv->bulkin.mxpacketsize = usbhost_getint16(pdesc->mxpacketsize); priv->bulkin.mxpacketsize = usbhost_getint16(epdesc->mxpacketsize);
} }
} }
} }
@@ -645,16 +756,20 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
* can we work read-only or write-only if only one bulk endpoint found? * can we work read-only or write-only if only one bulk endpoint found?
*/ */
if (!iffound || !binfound || !boutfound) if (found != USBHOST_ALLFOUND)
{ {
ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n", ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
iffound ? "YES" : "NO", (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
binfound ? "YES" : "NO", (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
outfound ? "YES" : "NO"); (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
return -EINVAL; return -EINVAL;
} }
ullvdbg("Mass Storage device connected\n"); ullvdbg("Mass Storage device connected\n");
/* Now configure the LUNs and register the block driver(s) */
usbhost_work(priv, usbhost_configluns);
return OK; return OK;
} }
@@ -700,19 +815,8 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
if (priv->crefs == 1) if (priv->crefs == 1)
{ {
/* Destroy the class instance */ /* Destroy the class instance */
/* Are we in an interrupt handler? */
if (up_interrupt_context()) usbhost_work(priv, usbhost_destroy);
{
/* Yes.. do the destruction on the worker thread */
(void)work_queue(&priv->work, usbhost_destroy, priv, 0);
}
else
{
/* No.. destroy the class now */
usbhost_destroy(priv);
} }
irqrestore(flags); irqrestore(flags);
return OK; return OK;
+5 -5
View File
@@ -65,11 +65,11 @@
/* Mass storage subclass codes */ /* Mass storage subclass codes */
#define USBSTRG_SUBCLASS_RBC (0x01) /* Reduced block commands (e.g., flash devices) */ #define USBSTRG_SUBCLASS_RBC (0x01) /* Reduced block commands (e.g., flash devices) */
#define SUBSTRG_SUBCLASS_SFF1 (0x02) /* SFF-8020i/MMC-2 (ATAPI) (e.g., C/DVD) */ #define USBSTRG_SUBCLASS_SFF1 (0x02) /* SFF-8020i/MMC-2 (ATAPI) (e.g., C/DVD) */
#define SUBSTRG_SUBCLASS_QIC (0x03) /* QIC-157 (e.g., tape device) */ #define USBSTRG_SUBCLASS_QIC (0x03) /* QIC-157 (e.g., tape device) */
#define SUBSTRG_SUBCLASS_UFI (0x04) /* e.g. floppy device */ #define USBSTRG_SUBCLASS_UFI (0x04) /* e.g. floppy device */
#define SUBSTRG_SUBCLASS_SFF2 (0x05) /* SFF-8070i (e.g. floppy disk) */ #define USBSTRG_SUBCLASS_SFF2 (0x05) /* SFF-8070i (e.g. floppy disk) */
#define SUBSTRG_SUBCLASS_SCSI (0x06) /* SCSI transparent */ #define USBSTRG_SUBCLASS_SCSI (0x06) /* SCSI transparent */
/* Mass storage transport protocols */ /* Mass storage transport protocols */