From 3f103dacc969fa65b6e69c5fa805bf6041ec4892 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 16 Dec 2010 01:29:51 +0000 Subject: [PATCH] USB host MS class compiles git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3186 42af7a65-404d-4744-a932-0658087f49c3 --- drivers/usbdev/usbdev_storage.c | 2 +- drivers/usbhost/Make.defs | 1 + drivers/usbhost/usbhost_storage.c | 198 +++++++++++++++++++++++------- include/nuttx/usb/usb_storage.h | 10 +- 4 files changed, 158 insertions(+), 53 deletions(-) diff --git a/drivers/usbdev/usbdev_storage.c b/drivers/usbdev/usbdev_storage.c index 02a2ad467c..17509c13e0 100644 --- a/drivers/usbdev/usbdev_storage.c +++ b/drivers/usbdev/usbdev_storage.c @@ -202,7 +202,7 @@ static const struct usb_ifdesc_s g_ifdesc = USBSTRG_ALTINTERFACEID, /* alt */ USBSTRG_NENDPOINTS, /* neps */ USB_CLASS_MASS_STORAGE, /* class */ - SUBSTRG_SUBCLASS_SCSI, /* subclass */ + USBSTRG_SUBCLASS_SCSI, /* subclass */ USBSTRG_PROTO_BULKONLY, /* protocol */ USBSTRG_CONFIGSTRID /* iif */ }; diff --git a/drivers/usbhost/Make.defs b/drivers/usbhost/Make.defs index 97aba26cc6..539d42551a 100644 --- a/drivers/usbhost/Make.defs +++ b/drivers/usbhost/Make.defs @@ -38,4 +38,5 @@ USBHOST_CSRCS = ifeq ($(CONFIG_USBHOST),y) USBHOST_CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c +USBHOST_CSRCS += usbhost_storage.c endif diff --git a/drivers/usbhost/usbhost_storage.c b/drivers/usbhost/usbhost_storage.c index 5142871eb4..064cc7de0d 100644 --- a/drivers/usbhost/usbhost_storage.c +++ b/drivers/usbhost/usbhost_storage.c @@ -39,15 +39,21 @@ #include +#include #include +#include +#include #include +#include #include #include #include #include + #include #include +#include #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" #endif +/* Driver support ***********************************************************/ /* 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. */ @@ -82,6 +89,13 @@ #define DEV_FORMAT "/dev/sd%c" #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 ****************************************************************************/ @@ -106,6 +120,7 @@ struct usbhost_state_s char sdchar; /* Character identifying the /dev/sd[n] device */ uint16_t blocksize; /* Block size of 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 usbhost_epdesc_s bulkin; /* Bulk IN endpoint */ struct usbhost_epdesc_s bulkout; /* Bulk OUT endpoint */ @@ -115,10 +130,15 @@ struct usbhost_state_s * 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 */ 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 */ @@ -129,6 +149,7 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev /* Worker thread actions */ static void usbhost_destroy(FAR void *arg); +static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker); /* 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 = { USB_CLASS_MASS_STORAGE, /* base */ - SUBSTRG_SUBCLASS_SCSI, /* subclass */ + USBSTRG_SUBCLASS_SCSI, /* subclass */ USBSTRG_PROTO_BULKONLY, /* proto */ 0, /* vid */ 0 /* pid */ @@ -227,6 +248,29 @@ static uint32_t g_devinuse; * 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 * @@ -293,7 +337,7 @@ static inline struct usbhost_state_s *usbhost_allocclass(void) ****************************************************************************/ #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; DEBUGASSERT(class != NULL); @@ -306,7 +350,7 @@ static inline usbhost_freeclass(struct usbhost_state_s *class) irqrestore(flags); } #else -static inline usbhost_freeclass(struct usbhost_state_s *class) +static inline void usbhost_freeclass(struct usbhost_state_s *class) { 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); } @@ -404,6 +448,74 @@ static void usbhost_destroy(FAR void *arg) 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 * @@ -420,7 +532,7 @@ static void usbhost_destroy(FAR void *arg) 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 */ - priv = usbhost_allocclass(void); + priv = usbhost_allocclass(); if (priv) { /* 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 */ @@ -492,7 +604,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d if (priv) { - usbhost_free(priv); + usbhost_freeclass(priv); } 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, 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_desc_s *desc; int remaining; - bool iffound = false; - bool boutfound = false; - bool binfound = false; + uint8_t found = 0; /* Verify that we were passed a configuration descriptor */ cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc; - if (desc->type != USB_DESC_TYPE_CONFIG) + if (cfgdesc->type != USB_DESC_TYPE_CONFIG) { return -EINVAL; } @@ -546,8 +657,8 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class, /* Skip to the next entry descriptor */ - configdesc += desc->len; - remaining -= desc->len; + configdesc += cfgdesc->len; + remaining -= cfgdesc->len; /* 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: { 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. */ return -ENOSYS; } - iffound = true; + found |= USBHOST_IFFOUND; } 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. */ - if (boutfound) - { - /* Oops.. more than one interface. We don't know what to do with this. */ + if ((found & USBHOST_BOUTFOUND) != 0) + { + /* Oops.. more than one interface. We don't know what to do with this. */ - return -EINVAL; - } - boutfound = true; + return -EINVAL; + } + found |= USBHOST_BOUTFOUND; /* Save the bulk OUT endpoint information */ priv->bulkout.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; priv->bulkout.in = false; - priv->bulkout.mxpacketsize = usbhost_getint16(pdesc->mxpacketsize); + priv->bulkout.mxpacketsize = usbhost_getint16(epdesc->mxpacketsize); } else { /* It is an IN bulk endpoint. There should be only one bulk IN endpoint. */ - if (binfound) - { - /* Oops.. more than one interface. We don't know what to do with this. */ + if ((found & USBHOST_BINFOUND) != 0) + { + /* Oops.. more than one interface. We don't know what to do with this. */ - return -EINVAL; - } - binfound = true; + return -EINVAL; + } + found |= USBHOST_BINFOUND; /* Save the bulk IN endpoint information */ priv->bulkin.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; 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? */ - if (!iffound || !binfound || !boutfound) + if (found != USBHOST_ALLFOUND) { ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n", - iffound ? "YES" : "NO", - binfound ? "YES" : "NO", - outfound ? "YES" : "NO"); + (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO", + (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO", + (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO"); return -EINVAL; } ullvdbg("Mass Storage device connected\n"); + + /* Now configure the LUNs and register the block driver(s) */ + + usbhost_work(priv, usbhost_configluns); return OK; } @@ -700,19 +815,8 @@ static int usbhost_disconnected(struct usbhost_class_s *class) if (priv->crefs == 1) { /* Destroy the class instance */ - /* Are we in an interrupt handler? */ - if (up_interrupt_context()) - { - /* 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); + usbhost_work(priv, usbhost_destroy); } irqrestore(flags); return OK; diff --git a/include/nuttx/usb/usb_storage.h b/include/nuttx/usb/usb_storage.h index 0ff1d9a38d..030b10bc21 100644 --- a/include/nuttx/usb/usb_storage.h +++ b/include/nuttx/usb/usb_storage.h @@ -65,11 +65,11 @@ /* Mass storage subclass codes */ #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 SUBSTRG_SUBCLASS_QIC (0x03) /* QIC-157 (e.g., tape device) */ -#define SUBSTRG_SUBCLASS_UFI (0x04) /* e.g. floppy device */ -#define SUBSTRG_SUBCLASS_SFF2 (0x05) /* SFF-8070i (e.g. floppy disk) */ -#define SUBSTRG_SUBCLASS_SCSI (0x06) /* SCSI transparent */ +#define USBSTRG_SUBCLASS_SFF1 (0x02) /* SFF-8020i/MMC-2 (ATAPI) (e.g., C/DVD) */ +#define USBSTRG_SUBCLASS_QIC (0x03) /* QIC-157 (e.g., tape device) */ +#define USBSTRG_SUBCLASS_UFI (0x04) /* e.g. floppy device */ +#define USBSTRG_SUBCLASS_SFF2 (0x05) /* SFF-8070i (e.g. floppy disk) */ +#define USBSTRG_SUBCLASS_SCSI (0x06) /* SCSI transparent */ /* Mass storage transport protocols */