Add waitsem
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3189 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
c796ba1e29
commit
46dc066efe
@ -111,7 +111,8 @@ enum USBSTRG_STATE_e
|
|||||||
USBSTRG_STATE_SENSE, /* Get sense information */
|
USBSTRG_STATE_SENSE, /* Get sense information */
|
||||||
USBSTRG_STATE_CAPACITY, /* Read the capacity of the volume */
|
USBSTRG_STATE_CAPACITY, /* Read the capacity of the volume */
|
||||||
USBSTRG_STATE_READY, /* Registered the block driver, idle, waiting for operation */
|
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
|
/* 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 */
|
int16_t crefs; /* Reference count on the driver instance */
|
||||||
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 */
|
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 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 */
|
||||||
@ -147,8 +149,8 @@ struct usbhost_state_s
|
|||||||
|
|
||||||
/* Semaphores */
|
/* Semaphores */
|
||||||
|
|
||||||
static void usbhost_takesem(FAR struct usbhost_state_s *priv);
|
static void usbhost_takesem(sem_t *sem);
|
||||||
#define usbhost_givesem(p) sem_post(&priv->sem);
|
#define usbhost_givesem(s) sem_post(s);
|
||||||
|
|
||||||
/* Memory allocation services */
|
/* 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,
|
static int usbhost_configdesc(FAR struct usbhost_class_s *class,
|
||||||
FAR const uint8_t *configdesc, int desclen);
|
FAR const uint8_t *configdesc, int desclen);
|
||||||
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 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);
|
static int usbhost_disconnected(FAR struct usbhost_class_s *class);
|
||||||
|
|
||||||
/* struct block_operations methods */
|
/* 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) */
|
/* 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
|
/* The only case that an error should occr here is if the wait was
|
||||||
* awakened by a signal.
|
* awakened by a signal.
|
||||||
@ -470,9 +474,13 @@ static void usbhost_destroy(FAR void *arg)
|
|||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* The USB mass storage device has been successfully connected. This is
|
* The USB mass storage device has been successfully connected. This is
|
||||||
* the state machine for normal operation. It is first called after the
|
* the state machine for initialization operations. It is first called
|
||||||
* configuration descriptor has been received; after that it is called
|
* after the configuration descriptor has been received; after that it is
|
||||||
* only on transfer completion events.
|
* 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:
|
* Input Parameters:
|
||||||
* arg - A reference to the class instance to be freed.
|
* 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)
|
static void usbhost_statemachine(FAR void *arg)
|
||||||
{
|
{
|
||||||
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
|
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
|
||||||
|
int result;
|
||||||
|
|
||||||
DEBUGASSERT(priv != NULL);
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
|
usbhost_takesem(&priv->exclsem);
|
||||||
switch (priv->state)
|
switch (priv->state)
|
||||||
{
|
{
|
||||||
case USBSTRG_STATE_CONFIGURED: /* Received config descriptor */
|
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 */
|
case USBSTRG_STATE_CAPACITY: /* Read the capacity of the volume */
|
||||||
{
|
{
|
||||||
|
char devname[DEV_NAMELEN];
|
||||||
|
|
||||||
/* Process capacity information */
|
/* Process capacity information */
|
||||||
#warning "Missing Logic"
|
#warning "Missing Logic"
|
||||||
priv->state = USBSTRG_STATE_READY;
|
|
||||||
|
/* Register the block driver */
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
uvdbg("Successfully initialized\n");
|
||||||
|
priv->class.complete = usbhost_complete2;
|
||||||
|
priv->state = USBSTRG_STATE_READY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#warning "Missing Logic"
|
/* This function should not be executed in the following states */
|
||||||
break;
|
|
||||||
|
|
||||||
case USBSTRG_STATE_BUSY: /* Transfer in progress */
|
|
||||||
{
|
|
||||||
/* Transfer has completed */
|
|
||||||
|
|
||||||
priv->state = USBSTRG_STATE_READY;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBSTRG_STATE_READY: /* Registered the block driver, idle, waiting for operation */
|
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_CREATED: /* State has been created, waiting for config descriptor */
|
||||||
|
case USBSTRG_STATE_FAIL: /* A fatal error occurred */
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
udbg("ERROR -- completion in unexpected stated: %d\n", priv->state);
|
udbg("ERROR! Completion in unexpected stated: %d\n", priv->state);
|
||||||
}
|
}
|
||||||
break;
|
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)
|
if (usbhost_allocdevno(priv) == OK)
|
||||||
{
|
{
|
||||||
|
/* Initialize class method function pointers */
|
||||||
|
|
||||||
priv->class.configdesc = usbhost_configdesc;
|
priv->class.configdesc = usbhost_configdesc;
|
||||||
priv->class.complete = usbhost_complete;
|
priv->class.complete = usbhost_complete1;
|
||||||
priv->class.disconnected = usbhost_disconnected;
|
priv->class.disconnected = usbhost_disconnected;
|
||||||
|
|
||||||
|
/* The initial reference count is 1... One reference is held by the driver */
|
||||||
|
|
||||||
priv->crefs = 1;
|
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 */
|
/* Bind the driver to the storage class instance */
|
||||||
|
|
||||||
priv->drvr = drvr;
|
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:
|
* 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
|
* usbhost_class_s. In the interface with the USB host drivers, the class
|
||||||
* will queue USB IN/OUT transactions. The enqueuing function will return
|
* will queue USB IN/OUT transactions. The enqueuing function will return
|
||||||
* and the transactions will be performed asynchrounously. When the
|
* 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
|
* order to inform the class that the transaction has completed and to
|
||||||
* provide any response data.
|
* 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:
|
* Input Parameters:
|
||||||
* class - The USB host class entry previously obtained from a call to
|
* class - The USB host class entry previously obtained from a call to
|
||||||
* create().
|
* 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 const uint8_t *response, int resplen)
|
||||||
{
|
{
|
||||||
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
|
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
|
||||||
DEBUGASSERT(priv != NULL && priv->state == USBSTRG_STATE_BUSY);
|
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);
|
usbhost_work(priv, usbhost_statemachine);
|
||||||
return OK;
|
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
|
* Name: usbhost_disconnected
|
||||||
*
|
*
|
||||||
@ -978,9 +1032,10 @@ static int usbhost_open(FAR struct inode *inode)
|
|||||||
/* Otherwise, just increment the reference count on the driver */
|
/* Otherwise, just increment the reference count on the driver */
|
||||||
|
|
||||||
DEBUGASSERT(priv->crefs < MAX_CREFS);
|
DEBUGASSERT(priv->crefs < MAX_CREFS);
|
||||||
usbhost_takesem(priv);
|
usbhost_takesem(&priv->exclsem);
|
||||||
|
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||||
priv->crefs++;
|
priv->crefs++;
|
||||||
usbhost_givesem(priv);
|
usbhost_givesem(&priv->exclsem);
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1005,7 +1060,8 @@ static int usbhost_close(FAR struct inode *inode)
|
|||||||
/* Decrement the reference count on the block driver */
|
/* Decrement the reference count on the block driver */
|
||||||
|
|
||||||
DEBUGASSERT(priv->crefs > 0);
|
DEBUGASSERT(priv->crefs > 0);
|
||||||
usbhost_takesem(priv);
|
usbhost_takesem(&priv->exclsem);
|
||||||
|
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||||
priv->crefs--;
|
priv->crefs--;
|
||||||
|
|
||||||
/* Release the semaphore. The following operations when crefs == 1 are
|
/* 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.
|
* the block driver.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
usbhost_givesem(priv);
|
usbhost_givesem(&priv->exclsem);
|
||||||
|
|
||||||
/* Check if the USB mass storage device is still connected. If the
|
/* Check if the USB mass storage device is still connected. If the
|
||||||
* storage device is not connected and the reference count just
|
* 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)
|
else if (nsectors > 0)
|
||||||
{
|
{
|
||||||
usbhost_takesem(priv);
|
usbhost_takesem(&priv->exclsem);
|
||||||
|
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||||
#warning "Missing logic"
|
#warning "Missing logic"
|
||||||
usbhost_givesem(priv);
|
usbhost_givesem(&priv->exclsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On success, return the number of blocks read */
|
/* 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
|
else
|
||||||
{
|
{
|
||||||
usbhost_takesem(priv);
|
usbhost_takesem(&priv->exclsem);
|
||||||
|
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||||
#warning "Missing logic"
|
#warning "Missing logic"
|
||||||
usbhost_givesem(priv);
|
usbhost_givesem(&priv->exclsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On success, return the number of blocks written */
|
/* 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 */
|
/* Return the geometry of the USB mass storage device */
|
||||||
|
|
||||||
priv = (FAR struct usbhost_state_s *)inode->i_private;
|
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_available = true;
|
||||||
geometry->geo_mediachanged = false;
|
geometry->geo_mediachanged = false;
|
||||||
@ -1159,7 +1218,7 @@ static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry)
|
|||||||
#endif
|
#endif
|
||||||
geometry->geo_nsectors = priv->nblocks;
|
geometry->geo_nsectors = priv->nblocks;
|
||||||
geometry->geo_sectorsize = priv->blocksize;
|
geometry->geo_sectorsize = priv->blocksize;
|
||||||
usbhost_givesem(priv);
|
usbhost_givesem(&priv->exclsem);
|
||||||
|
|
||||||
uvdbg("nsectors: %ld sectorsize: %d\n",
|
uvdbg("nsectors: %ld sectorsize: %d\n",
|
||||||
(long)geometry->geo_nsectors, geometry->geo_sectorsize);
|
(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 */
|
/* Process the IOCTL by command */
|
||||||
|
|
||||||
usbhost_takesem(priv);
|
usbhost_takesem(&priv->exclsem);
|
||||||
|
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
/* Add support for ioctl commands here */
|
/* Add support for ioctl commands here */
|
||||||
@ -1211,7 +1272,7 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
usbhost_givesem(priv);
|
usbhost_givesem(&priv->exclsem);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user