summaryrefslogtreecommitdiff
path: root/nuttx/drivers/usbhost/usbhost_storage.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-12-16 17:11:05 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-12-16 17:11:05 +0000
commit94d42a639e073cd05a2186c60f7c00289fd2fbf7 (patch)
tree36f0f2af0faecdb12763cf60dc31e6536ae7300e /nuttx/drivers/usbhost/usbhost_storage.c
parent321930bccd1f67683b96db46f2f35a6c289312c7 (diff)
downloadnuttx-94d42a639e073cd05a2186c60f7c00289fd2fbf7.tar.gz
nuttx-94d42a639e073cd05a2186c60f7c00289fd2fbf7.tar.bz2
nuttx-94d42a639e073cd05a2186c60f7c00289fd2fbf7.zip
Add waitsem
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3189 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/drivers/usbhost/usbhost_storage.c')
-rw-r--r--nuttx/drivers/usbhost/usbhost_storage.c137
1 files changed, 99 insertions, 38 deletions
diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c
index 94f994238..b824df3d8 100644
--- a/nuttx/drivers/usbhost/usbhost_storage.c
+++ b/nuttx/drivers/usbhost/usbhost_storage.c
@@ -111,7 +111,8 @@ enum USBSTRG_STATE_e
USBSTRG_STATE_SENSE, /* Get sense information */
USBSTRG_STATE_CAPACITY, /* Read the capacity of the volume */
USBSTRG_STATE_READY, /* Registered the block driver, idle, waiting for operation */
- USBSTRG_STATE_BUSY /* Transfer in progress */
+ USBSTRG_STATE_BUSY, /* Transfer in progress */
+ USBSTRG_STATE_FAIL /* A fatal error occurred */
};
/* This structure contains the internal, private state of the USB host mass
@@ -135,7 +136,8 @@ struct usbhost_state_s
int16_t crefs; /* Reference count on the driver instance */
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 */
+ sem_t exclsem; /* Used to maintain mutual exclusive access */
+ sem_t waitsem; /* Used to wait for transfer completion events */
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 */
@@ -147,8 +149,8 @@ struct usbhost_state_s
/* Semaphores */
-static void usbhost_takesem(FAR struct usbhost_state_s *priv);
-#define usbhost_givesem(p) sem_post(&priv->sem);
+static void usbhost_takesem(sem_t *sem);
+#define usbhost_givesem(s) sem_post(s);
/* Memory allocation services */
@@ -179,8 +181,10 @@ static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
static int usbhost_configdesc(FAR struct usbhost_class_s *class,
FAR const uint8_t *configdesc, int desclen);
-static int usbhost_complete(FAR struct usbhost_class_s *class,
- FAR const uint8_t *response, int resplen);
+static int usbhost_complete1(FAR struct usbhost_class_s *class,
+ FAR const uint8_t *response, int resplen);
+static int usbhost_complete2(FAR struct usbhost_class_s *class,
+ FAR const uint8_t *response, int resplen);
static int usbhost_disconnected(FAR struct usbhost_class_s *class);
/* struct block_operations methods */
@@ -274,11 +278,11 @@ static uint32_t g_devinuse;
*
****************************************************************************/
-static void usbhost_takesem(FAR struct usbhost_state_s *priv)
+static void usbhost_takesem(sem_t *sem)
{
/* Take the semaphore (perhaps waiting) */
- while (sem_wait(&priv->sem) != 0)
+ while (sem_wait(sem) != 0)
{
/* The only case that an error should occr here is if the wait was
* awakened by a signal.
@@ -470,9 +474,13 @@ static void usbhost_destroy(FAR void *arg)
*
* Description:
* The USB mass storage device has been successfully connected. This is
- * the state machine for normal operation. It is first called after the
- * configuration descriptor has been received; after that it is called
- * only on transfer completion events.
+ * the state machine for initialization operations. It is first called
+ * after the configuration descriptor has been received; after that it is
+ * called only on transfer completion events.
+ *
+ * When the block driver is fully initialized and registered, the
+ * completion handler will be called again and this function should no
+ * longer be executed.
*
* Input Parameters:
* arg - A reference to the class instance to be freed.
@@ -485,8 +493,11 @@ static void usbhost_destroy(FAR void *arg)
static void usbhost_statemachine(FAR void *arg)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
+ int result;
+
DEBUGASSERT(priv != NULL);
+ usbhost_takesem(&priv->exclsem);
switch (priv->state)
{
case USBSTRG_STATE_CONFIGURED: /* Received config descriptor */
@@ -527,31 +538,44 @@ static void usbhost_statemachine(FAR void *arg)
case USBSTRG_STATE_CAPACITY: /* Read the capacity of the volume */
{
+ char devname[DEV_NAMELEN];
+
/* Process capacity information */
#warning "Missing Logic"
- priv->state = USBSTRG_STATE_READY;
- }
- break;
-#warning "Missing Logic"
- break;
+ /* Register the block driver */
- case USBSTRG_STATE_BUSY: /* Transfer in progress */
- {
- /* Transfer has completed */
+ usbhost_mkdevname(priv, devname);
+ result = register_blockdriver(devname, &g_bops, 0, priv);
+ if (result != OK)
+ {
+ udbg("ERROR! Failed to register block driver: %d\n", result);
+ priv->state = USBSTRG_STATE_FAIL;
+ }
+ else
+ {
+ /* Set up for normal operation as a block device driver */
- priv->state = USBSTRG_STATE_READY;
+ uvdbg("Successfully initialized\n");
+ priv->class.complete = usbhost_complete2;
+ priv->state = USBSTRG_STATE_READY;
+ }
}
break;
+ /* This function should not be executed in the following states */
+
case USBSTRG_STATE_READY: /* Registered the block driver, idle, waiting for operation */
+ case USBSTRG_STATE_BUSY: /* Block driver I/O transfer in progress */
case USBSTRG_STATE_CREATED: /* State has been created, waiting for config descriptor */
+ case USBSTRG_STATE_FAIL: /* A fatal error occurred */
default:
{
- udbg("ERROR -- completion in unexpected stated: %d\n", priv->state);
+ udbg("ERROR! Completion in unexpected stated: %d\n", priv->state);
}
break;
}
+ usbhost_givesem(&priv->exclsem);
}
/****************************************************************************
@@ -659,11 +683,21 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
if (usbhost_allocdevno(priv) == OK)
{
+ /* Initialize class method function pointers */
+
priv->class.configdesc = usbhost_configdesc;
- priv->class.complete = usbhost_complete;
+ priv->class.complete = usbhost_complete1;
priv->class.disconnected = usbhost_disconnected;
+
+ /* The initial reference count is 1... One reference is held by the driver */
+
priv->crefs = 1;
+ /* Initialize semphores (this works okay in the interrupt context) */
+
+ sem_init(&priv->exclsem, 0, 1);
+ sem_init(&priv->waitsem, 0, 0);
+
/* Bind the driver to the storage class instance */
priv->drvr = drvr;
@@ -856,10 +890,10 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
}
/****************************************************************************
- * Name: usbhost_complete
+ * Name: usbhost_complete1 & 2
*
* Description:
- * This function implements will the complete() method of struct
+ * These functions implement the complete() method of struct
* usbhost_class_s. In the interface with the USB host drivers, the class
* will queue USB IN/OUT transactions. The enqueuing function will return
* and the transactions will be performed asynchrounously. When the
@@ -867,6 +901,14 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
* order to inform the class that the transaction has completed and to
* provide any response data.
*
+ * There are two implementations: usbhost_complete1() is used during
+ * initialization to sequence through a pre-determined set of queuries
+ * to configure for the connected USB mass storage device.
+ *
+ * usbhost_complete2() is used after the completion of the initialization
+ * sequence. After initialization, the only interactions with the mass
+ * storage device will be through block driver operations.
+ *
* Input Parameters:
* class - The USB host class entry previously obtained from a call to
* create().
@@ -882,18 +924,30 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
*
****************************************************************************/
-static int usbhost_complete(FAR struct usbhost_class_s *class,
+static int usbhost_complete1(FAR struct usbhost_class_s *class,
FAR const uint8_t *response, int resplen)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
DEBUGASSERT(priv != NULL && priv->state == USBSTRG_STATE_BUSY);
- /* Invoke the state machine on each transfer completion event */
+ /* Invoke the initialization state machine on each transfer completion event */
usbhost_work(priv, usbhost_statemachine);
return OK;
}
+static int usbhost_complete2(FAR struct usbhost_class_s *class,
+ FAR const uint8_t *response, int resplen)
+{
+ FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
+ DEBUGASSERT(priv != NULL && priv->state == USBSTRG_STATE_BUSY);
+
+ /* Wake up the application thread waiting for the transfer completion event */
+
+ usbhost_givesem(&priv->waitsem);
+ return OK;
+}
+
/****************************************************************************
* Name: usbhost_disconnected
*
@@ -978,9 +1032,10 @@ static int usbhost_open(FAR struct inode *inode)
/* Otherwise, just increment the reference count on the driver */
DEBUGASSERT(priv->crefs < MAX_CREFS);
- usbhost_takesem(priv);
+ usbhost_takesem(&priv->exclsem);
+ DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
priv->crefs++;
- usbhost_givesem(priv);
+ usbhost_givesem(&priv->exclsem);
ret = OK;
}
@@ -1005,7 +1060,8 @@ static int usbhost_close(FAR struct inode *inode)
/* Decrement the reference count on the block driver */
DEBUGASSERT(priv->crefs > 0);
- usbhost_takesem(priv);
+ usbhost_takesem(&priv->exclsem);
+ DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
priv->crefs--;
/* Release the semaphore. The following operations when crefs == 1 are
@@ -1013,7 +1069,7 @@ static int usbhost_close(FAR struct inode *inode)
* the block driver.
*/
- usbhost_givesem(priv);
+ usbhost_givesem(&priv->exclsem);
/* Check if the USB mass storage device is still connected. If the
* storage device is not connected and the reference count just
@@ -1063,9 +1119,10 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
}
else if (nsectors > 0)
{
- usbhost_takesem(priv);
+ usbhost_takesem(&priv->exclsem);
+ DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
#warning "Missing logic"
- usbhost_givesem(priv);
+ usbhost_givesem(&priv->exclsem);
}
/* On success, return the number of blocks read */
@@ -1106,9 +1163,10 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
}
else
{
- usbhost_takesem(priv);
+ usbhost_takesem(&priv->exclsem);
+ DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
#warning "Missing logic"
- usbhost_givesem(priv);
+ usbhost_givesem(&priv->exclsem);
}
/* On success, return the number of blocks written */
@@ -1148,7 +1206,8 @@ static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry)
/* Return the geometry of the USB mass storage device */
priv = (FAR struct usbhost_state_s *)inode->i_private;
- usbhost_takesem(priv);
+ usbhost_takesem(&priv->exclsem);
+ DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
geometry->geo_available = true;
geometry->geo_mediachanged = false;
@@ -1159,7 +1218,7 @@ static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry)
#endif
geometry->geo_nsectors = priv->nblocks;
geometry->geo_sectorsize = priv->blocksize;
- usbhost_givesem(priv);
+ usbhost_givesem(&priv->exclsem);
uvdbg("nsectors: %ld sectorsize: %d\n",
(long)geometry->geo_nsectors, geometry->geo_sectorsize);
@@ -1201,7 +1260,9 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
{
/* Process the IOCTL by command */
- usbhost_takesem(priv);
+ usbhost_takesem(&priv->exclsem);
+ DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
+
switch (cmd)
{
/* Add support for ioctl commands here */
@@ -1211,7 +1272,7 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
break;
}
- usbhost_givesem(priv);
+ usbhost_givesem(&priv->exclsem);
}
return ret;
}