9
0
Fork 0

Working through initialization state machine

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@3194 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2010-12-18 03:24:13 +00:00
parent 6ef24a191f
commit e55a84fe68
2 changed files with 224 additions and 73 deletions

View File

@ -87,15 +87,17 @@
* defined here so that it will be used consistently in all places.
*/
#define DEV_FORMAT "/dev/sd%c"
#define DEV_NAMELEN 10
#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
#define USBHOST_IFFOUND 0x01
#define USBHOST_BINFOUND 0x02
#define USBHOST_BOUTFOUND 0x04
#define USBHOST_ALLFOUND 0x07
#define USBHOST_MAX_RETRIES 100
/****************************************************************************
* Private Types
@ -105,15 +107,15 @@
enum USBSTRG_STATE_e
{
USBSTRG_STATE_CREATED = 0, /* State has been created, waiting for config descriptor */
USBSTRG_STATE_CONFIGURED, /* Received config descriptor */
USBSTRG_STATE_MAXLUN, /* Requested maximum logical unit number */
USBSTRG_STATE_UNITREADY, /* Check if the unit is ready */
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_FAIL /* A fatal error occurred */
USBSTRG_STATE_CREATED = 0, /* State has been created, waiting for config descriptor */
USBSTRG_STATE_CONFIGURED, /* Received config descriptor */
USBSTRG_STATE_MAXLUN, /* Requested maximum logical unit number */
USBSTRG_STATE_TESTUNITREADY, /* Waiting for test unit ready to complete */
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_FAIL /* A fatal error occurred */
};
/* This structure contains the internal, private state of the USB host mass
@ -133,6 +135,7 @@ struct usbhost_state_s
/* The remainder of the fields are provide o the mass storage class */
uint8_t state; /* See enum USBSTRG_STATE_e */
uint8_t retries; /* Retry counter */
char sdchar; /* Character identifying the /dev/sd[n] device */
int16_t crefs; /* Reference count on the driver instance */
uint16_t blocksize; /* Block size of USB mass storage device */
@ -178,6 +181,9 @@ static inline void usbhost_readcbw (size_t startsector, uint16_t blocksize,
static inline void usbhost_writecbw(size_t startsector, uint16_t blocksize,
unsigned int nsectors,
FAR struct usbstrg_cbw_s *cbw);
/* Command helpers */
static int usbhost_testunitready(FAR struct usbhost_state_s *priv);
/* Worker thread actions */
@ -571,6 +577,46 @@ usbhost_writecbw(size_t startsector, uint16_t blocksize,
usbhost_putbe16(wr10->xfrlen, nsectors);
}
/****************************************************************************
* Name: Command helpers
*
* Description:
* The following functions are helper functions used to send commands.
*
* Input Parameters:
* priv - A reference to the class instance.
*
* Returned Values:
* None
*
****************************************************************************/
static int usbhost_testunitready(FAR struct usbhost_state_s *priv)
{
FAR struct usbstrg_cbw_s *cbw;
int result = -ENOMEM;
/* Initialize a CBW (allocating it if necessary) */
cbw = usbhost_cbwalloc(priv);
if (cbw)
{
/* Construc and send the CBW */
usbhost_testunitreadycbw(cbw);
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
}
}
return result;
}
/****************************************************************************
* Name: usbhost_destroy
*
@ -603,6 +649,15 @@ static void usbhost_destroy(FAR void *arg)
usbhost_freedevno(priv);
/* Free any transfer buffers */
usbhost_tdfree(priv);
/* Destroy the semaphores */
sem_destroy(&priv->exclsem);
sem_destroy(&priv->waitsem);
/* And free the class instance. Hmmm.. this may execute on the worker
* thread and the work structure is part of what is getting freed.
*/
@ -634,7 +689,7 @@ 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;
int result = OK;
DEBUGASSERT(priv != NULL);
@ -643,43 +698,88 @@ static void usbhost_statemachine(FAR void *arg)
{
case USBSTRG_STATE_CONFIGURED: /* Received config descriptor */
{
/* Request maximum logical unit number */
#warning "Missing Logic"
priv->state = USBSTRG_STATE_MAXLUN;
struct usb_ctrlreq_s req;
uvdbg("USBSTRG_STATE_CONFIGURED\n");
/* Make sure that we have a buffer allocated */
result = usbhost_tdalloc(priv);
if (result == OK)
{
/* Request maximum logical unit number */
memset(&req, 0, sizeof(struct usb_ctrlreq_s));
req.type = USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE;
req.req = USBSTRG_REQ_GETMAXLUN;
usbhost_putle16(req.len, 1);
result = DRVR_CONTROL(priv->drvr, &req, priv->tdbuffer);
priv->state = USBSTRG_STATE_MAXLUN;
}
}
break;
case USBSTRG_STATE_MAXLUN: /* Requested maximum logical unit number */
{
/* Handle maximum LUN info */
uvdbg("USBSTRG_STATE_MAXLUN\n");
/* Check if the unit is ready */
result = usbhost_testunitready(priv);
priv->retries = 0;
#warning "Missing Logic"
priv->state = USBSTRG_STATE_MAXLUN;
}
break;
case USBSTRG_STATE_UNITREADY: /* Check if the unit is ready */
case USBSTRG_STATE_SENSE: /* MODESENSE compleed */
{
/* Request sense information */
#warning "Missing Logic"
priv->state = USBSTRG_STATE_SENSE;
uvdbg("USBSTRG_STATE_SENSE\n");
/* Check if the unit is ready again */
result = usbhost_testunitready(priv);
priv->state = USBSTRG_STATE_TESTUNITREADY;
priv->retries++;
}
break;
case USBSTRG_STATE_SENSE: /* Get sense information */
case USBSTRG_STATE_TESTUNITREADY: /* TESTUNITREADY completed */
{
/* Process sense information */
uvdbg("USBSTRG_STATE_TESTUNITREADY\n");
/* Request the capaciy of the volume */
/* Check the result */
if (priv->tdbuffer[12] != 0)
{
/* Not ready... retry? */
if (priv->retries < USBHOST_MAX_RETRIES)
{
/* Request mode sense information */
#warning "Missing Logic"
priv->state = USBSTRG_STATE_CAPACITY;
priv->state = USBSTRG_STATE_SENSE;
}
else
{
result = -ETIMEDOUT;
}
}
else
{
/* Request the capaciy of the volume */
#warning "Missing Logic"
priv->state = USBSTRG_STATE_CAPACITY;
}
}
break;
case USBSTRG_STATE_CAPACITY: /* Read the capacity of the volume */
{
char devname[DEV_NAMELEN];
uvdbg("USBSTRG_STATE_CAPACITY\n");
/* Process capacity information */
#warning "Missing Logic"
@ -713,10 +813,19 @@ static void usbhost_statemachine(FAR void *arg)
default:
{
udbg("ERROR! Completion in unexpected stated: %d\n", priv->state);
result = -EINVAL;
}
break;
}
usbhost_givesem(&priv->exclsem);
/* Abort everything on an error */
if (result != OK)
{
udbg("ERROR! Aborting: %d\n", result);
usbhost_destroy(priv);
}
}
/****************************************************************************

View File

@ -196,37 +196,6 @@
#define DRVR_ENUMERATE(drvr) ((drvr)->enumerate(drvr))
/************************************************************************************
* Name: DRVR_TRANSFER
*
* Description:
* Enqueue a request to handle a transfer descriptor. This method will
* enqueue the transfer request and return immediately. The transfer will
* be performed asynchronously. When the transfer completes, the USB host
* driver will call he complete() method of the struct usbhost_class_s
* interface. Only one transfer may be queued; this function cannot be
* again until the class complete() method has been called.
*
* Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method.
* ed - The IN or OUT endpoint descriptor for the device endpoint on which to
* perform the transfer.
* buffer - A buffer containing the data to be sent (OUT endpoint) or received
* (IN endpoint).
* buflen - The length of the data to be sent or received.
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
* returned indicating the nature of the failure
*
* Assumptions:
* This function will *not* be called from an interrupt handler.
*
************************************************************************************/
#define DRVR_TRANSFER(drvr,ed,buffer,buflen) ((drvr)->transfer(drvr,ed,buffer,buflen))
/************************************************************************************
* Name: DRVR_ALLOC
*
@ -280,6 +249,70 @@
#define DRVR_FREE(drvr,buffer) ((drvr)->free(drvr,buffer))
/************************************************************************************
* Name: DRVR_CONTROL
*
* Description:
* Enqueue a request on the control endpoint. This method will enqueue
* the request and return immediately. The transfer will be performed
* asynchronously. When the transfer completes, the USB host driver will
* call the complete() method of the struct usbhost_class_s interface.
* Only one transfer may be queued; Neither this method nor the transfer()
* method can be called again until the class complete() method has been called.
*
* Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method.
* req - Describes the request to be sent. This data will be copied from the
* user provided memory. Therefore, the req buffer may be declared on the
* stack.
* buffer - A buffer used for sending the request and for returning any
* responses. This buffer must be large enough to hold the length value
* in the request description. buffer must have been allocated using DRVR_ALLOC
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
* returned indicating the nature of the failure
*
* Assumptions:
* This function will *not* be called from an interrupt handler.
*
************************************************************************************/
#define DRVR_CONTROL(drvr,req,buffer) ((drvr)->control(drvr,req,buffer))
/************************************************************************************
* Name: DRVR_TRANSFER
*
* Description:
* Enqueue a request to handle a transfer descriptor. This method will
* enqueue the transfer request and return immediately. The transfer will
* be performed asynchronously. When the transfer completes, the USB host
* driver will call the complete() method of the struct usbhost_class_s
* interface. Only one transfer may be queued; Neither this method nor the
* control method can be called again until the class complete() method has
* been called.
*
* Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method.
* ed - The IN or OUT endpoint descriptor for the device endpoint on which to
* perform the transfer.
* buffer - A buffer containing the data to be sent (OUT endpoint) or received
* (IN endpoint). buffer must have been allocated using DRVR_ALLOC
* buflen - The length of the data to be sent or received.
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
* returned indicating the nature of the failure
*
* Assumptions:
* This function will *not* be called from an interrupt handler.
*
************************************************************************************/
#define DRVR_TRANSFER(drvr,ed,buffer,buflen) ((drvr)->transfer(drvr,ed,buffer,buflen))
/************************************************************************************
* Public Types
************************************************************************************/
@ -376,18 +409,6 @@ struct usbhost_driver_s
int (*enumerate)(FAR struct usbhost_driver_s *drvr);
/* Enqueue a request to handle a transfer descriptor. This method will
* enqueue the transfer request and return immediately. The transfer will
* be performed asynchronously. When the transfer completes, the USB host
* driver will call he complete() method of the struct usbhost_class_s
* interface. Only one transfer may be queued; this function cannot be
* again until the class complete() method has been called.
*/
int (*transfer)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_epdesc_s *ed,
FAR uint8_t *buffer, size_t buflen);
/* Some hardware supports special memory in which transfer descriptors can
* be accessed more efficiently. The following methods provide a mechanism
* to allocate and free the transfer descriptor memory. If the underlying
@ -399,9 +420,30 @@ struct usbhost_driver_s
FAR uint8_t **buffer, FAR size_t *maxlen);
int (*free)(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
/* Receive control information */
/* Enqueue a request on the control endpoint. This method will enqueue
* the request and return immediately. The transfer will be performed
* asynchronously. When the transfer completes, the USB host driver will
* call the complete() method of the struct usbhost_class_s interface.
* Only one transfer may be queued; Neither this method nor the transfer()
* method can be called again until the class complete() method has been called.
*/
int (*rcvctrl)(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_epdesc_s *ed);
int (*control)(FAR struct usbhost_driver_s *drvr,
const struct usb_ctrlreq_s *req,
FAR uint8_t *buffer);
/* Enqueue a request to handle a transfer descriptor. This method will
* enqueue the transfer request and return immediately. The transfer will
* be performed asynchronously. When the transfer completes, the USB host
* driver will call the complete() method of the struct usbhost_class_s
* interface. Only one transfer may be queued; Neither this method nor the
* control method can be called again until the class complete() method has
* been called.
*/
int (*transfer)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_epdesc_s *ed,
FAR uint8_t *buffer, size_t buflen);
};
/* This structure describes one endpoint */