Finishes first cut at USB host MS class
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3195 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
e3b7c6671d
commit
5824a1642c
@ -188,21 +188,45 @@ static int lpc17_usbinterrupt(int irq, FAR void *context);
|
||||
|
||||
/* USB host controller operations **********************************************/
|
||||
|
||||
static int usbhost_enumerate(FAR struct usbhost_driver_s *drvr);
|
||||
static int usbhost_alloc(FAR struct usbhost_driver_s *drvr,
|
||||
FAR uint8_t **buffer, FAR size_t *maxlen);
|
||||
static int usbhost_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
|
||||
static int usbhost_control(FAR struct usbhost_driver_s *drvr,
|
||||
const struct usb_ctrlreq_s *req, FAR uint8_t *buffer);
|
||||
static int usbhost_transfer(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_epdesc_s *ed,
|
||||
FAR uint8_t *buffer, size_t buflen);
|
||||
static void usbhost_disconnect(FAR struct usbhost_driver_s *drvr);
|
||||
|
||||
/* Initializaion ***************************************************************/
|
||||
|
||||
static void usbhost_tdinit(volatile struct usbhost_hctd_s *td);
|
||||
static void usbhost_edinit(volatile struct usbhost_hced_s *);
|
||||
static void usbhost_edinit(volatile struct usbhost_hced_s *ed);
|
||||
static void usbhost_hccainit(volatile struct usbhost_hcca_s *hcca);
|
||||
|
||||
/*******************************************************************************
|
||||
* Private Data
|
||||
*******************************************************************************/
|
||||
|
||||
/* Since there is only a single USB interface, all status information can be
|
||||
* be simply retained in a single global instance.
|
||||
/* In this driver implementation, support is provided for only a single a single
|
||||
* USB device. All status information can be simply retained in a single global
|
||||
* instance.
|
||||
*/
|
||||
|
||||
static struct lpc17_usbhost_s g_usbhost;
|
||||
static struct lpc17_usbhost_s g_usbhost =
|
||||
{
|
||||
.usbhost =
|
||||
{
|
||||
.enumerate = usbhost_enumerate,
|
||||
.alloc = usbhost_alloc,
|
||||
.free = usbhost_free,
|
||||
.control = usbhost_control,
|
||||
.transfer = usbhost_transfer,
|
||||
.disconnect = usbhost_disconnect,
|
||||
},
|
||||
.class = NULL,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Data
|
||||
@ -355,9 +379,225 @@ static int lpc17_usbinterrupt(int irq, FAR void *context)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* USB Host Device Operations
|
||||
* USB Host Controller Operations
|
||||
*******************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Name: usbhost_enumerate
|
||||
*
|
||||
* Description:
|
||||
* Enumerate the connected device. This function will enqueue the
|
||||
* enumeration process. As part of this enumeration process, the driver
|
||||
* will (1) get the device's configuration descriptor, (2) extract the class
|
||||
* ID info from the configuration descriptor, (3) call usbhost_findclass()
|
||||
* to find the class that supports this device, (4) call the create()
|
||||
* method on the struct usbhost_registry_s interface to get a class
|
||||
* instance, and finally (5) call the configdesc() method of the struct
|
||||
* usbhost_class_s interface. After that, the class is in charge of the
|
||||
* sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static int usbhost_enumerate(FAR struct usbhost_driver_s *drvr)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: usbhost_alloc
|
||||
*
|
||||
* Description:
|
||||
* Some hardware supports special memory in which transfer descriptors can
|
||||
* be accessed more efficiently. This method provides a mechanism to allocate
|
||||
* the transfer descriptor memory. If the underlying hardware does not support
|
||||
* such "special" memory, this functions may simply map to malloc.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
* buffer - The address of a memory location provided by the caller in which to
|
||||
* return the allocated buffer memory address.
|
||||
* maxlen - The address of a memory location provided by the caller in which to
|
||||
* return the maximum size of the allocated buffer memory.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static int usbhost_alloc(FAR struct usbhost_driver_s *drvr,
|
||||
FAR uint8_t **buffer, FAR size_t *maxlen)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: usbhost_free
|
||||
*
|
||||
* Description:
|
||||
* Some hardware supports special memory in which transfer descriptors can
|
||||
* be accessed more efficiently. This method provides a mechanism to free that
|
||||
* transfer descriptor memory. If the underlying hardware does not support
|
||||
* such "special" memory, this functions may simply map to free().
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
* buffer - The address of the allocated buffer memory to be freed.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static int usbhost_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: usbhost_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.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static int usbhost_control(FAR struct usbhost_driver_s *drvr,
|
||||
const struct usb_ctrlreq_s *req, FAR uint8_t *buffer)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: usbhost_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.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static int usbhost_transfer(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_epdesc_s *ed,
|
||||
FAR uint8_t *buffer, size_t buflen)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: usbhost_disconnect
|
||||
*
|
||||
* Description:
|
||||
* Called by the class when an error occurs and driver has been disconnected.
|
||||
* The USB host driver should discard the handle to the class instance (it is
|
||||
* stale) and not attempt any further interaction with the class driver instance
|
||||
* (until a new instance is received from the create() method). The driver
|
||||
* should not called the class' disconnected() method.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* This function will *not* be called from an interrupt handler.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static void usbhost_disconnect(FAR struct usbhost_driver_s *drvr)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Initialization
|
||||
*******************************************************************************/
|
||||
|
||||
static void usbhost_tdinit(volatile struct usbhost_hctd_s *td)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
}
|
||||
|
||||
static void usbhost_edinit(volatile struct usbhost_hced_s *ed)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
}
|
||||
|
||||
static void usbhost_hccainit(volatile struct usbhost_hcca_s *hcca)
|
||||
{
|
||||
# warning "Not Implemented"
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Functions
|
||||
*******************************************************************************/
|
||||
|
@ -103,21 +103,6 @@
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This enumeration provides the state of the storage class */
|
||||
|
||||
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_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
|
||||
* storage class.
|
||||
*/
|
||||
@ -134,8 +119,6 @@ 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 */
|
||||
@ -155,7 +138,7 @@ struct usbhost_state_s
|
||||
|
||||
/* Semaphores */
|
||||
|
||||
static void usbhost_takesem(sem_t *sem);
|
||||
static void usbhost_takesem(sem_t *sem);
|
||||
#define usbhost_givesem(s) sem_post(s);
|
||||
|
||||
/* Memory allocation services */
|
||||
@ -171,7 +154,7 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev
|
||||
|
||||
/* CBW helpers */
|
||||
|
||||
static inline void usbhost_modesensecbw(FAR struct usbstrg_cbw_s *cbw);
|
||||
static inline void usbhost_requestsensecbw(FAR struct usbstrg_cbw_s *cbw);
|
||||
static inline void usbhost_testunitreadycbw(FAR struct usbstrg_cbw_s *cbw);
|
||||
static inline void usbhost_readcapacitycbw(FAR struct usbstrg_cbw_s *cbw);
|
||||
static inline void usbhost_inquirycbw (FAR struct usbstrg_cbw_s *cbw);
|
||||
@ -183,7 +166,11 @@ static inline void usbhost_writecbw(size_t startsector, uint16_t blocksize,
|
||||
FAR struct usbstrg_cbw_s *cbw);
|
||||
/* Command helpers */
|
||||
|
||||
static int usbhost_testunitready(FAR struct usbhost_state_s *priv);
|
||||
static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv);
|
||||
static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv);
|
||||
static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv);
|
||||
static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv);
|
||||
static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv);
|
||||
|
||||
/* Worker thread actions */
|
||||
|
||||
@ -194,8 +181,10 @@ static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker);
|
||||
/* (Little Endian) Data helpers */
|
||||
|
||||
static inline uint16_t usbhost_getle16(const uint8_t *val);
|
||||
static inline uint16_t usbhost_getbe16(const uint8_t *val);
|
||||
static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
|
||||
static inline void usbhost_putbe16(uint8_t *dest, uint16_t val);
|
||||
static inline uint32_t usbhost_getbe32(const uint8_t *val);
|
||||
static void usbhost_putle32(uint8_t *dest, uint32_t val);
|
||||
static void usbhost_putbe32(uint8_t *dest, uint32_t val);
|
||||
|
||||
@ -214,10 +203,8 @@ 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_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_complete(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 */
|
||||
@ -477,7 +464,7 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void usbhost_modesensecbw(FAR struct usbstrg_cbw_s *cbw)
|
||||
static inline void usbhost_requestsensecbw(FAR struct usbstrg_cbw_s *cbw)
|
||||
{
|
||||
FAR struct scsicmd_requestsense_s *reqsense;
|
||||
|
||||
@ -591,7 +578,36 @@ usbhost_writecbw(size_t startsector, uint16_t blocksize,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int usbhost_testunitready(FAR struct usbhost_state_s *priv)
|
||||
static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
struct usb_ctrlreq_s req;
|
||||
int result;
|
||||
|
||||
/* Make sure that we have a buffer allocated */
|
||||
|
||||
result = usbhost_tdalloc(priv);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Request maximum logical unit number */
|
||||
|
||||
uvdbg("Request maximum logical unit number\n");
|
||||
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);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the control operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
FAR struct usbstrg_cbw_s *cbw;
|
||||
int result = -ENOMEM;
|
||||
@ -601,17 +617,176 @@ static int usbhost_testunitready(FAR struct usbhost_state_s *priv)
|
||||
cbw = usbhost_cbwalloc(priv);
|
||||
if (cbw)
|
||||
{
|
||||
/* Construc and send the CBW */
|
||||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_testunitreadycbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW OUT operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
|
||||
|
||||
/* Wait for the CSW IN operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int usbhost_requestsense(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)
|
||||
{
|
||||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_requestsensecbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW OUT operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the sense data response */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW IN response operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CSW IN operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
FAR struct usbstrg_cbw_s *cbw;
|
||||
FAR struct scsiresp_readcapacity10_s *resp;
|
||||
int result = -ENOMEM;
|
||||
|
||||
/* Initialize a CBW (allocating it if necessary) */
|
||||
|
||||
cbw = usbhost_cbwalloc(priv);
|
||||
if (cbw)
|
||||
{
|
||||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_readcapacitycbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW OUT operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the read capacity CBW IN response */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, SCSIRESP_READCAPACITY10_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW IN response operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Save the capacity information */
|
||||
|
||||
resp = (FAR struct scsiresp_readcapacity10_s *)priv->tdbuffer;
|
||||
priv->nblocks = usbhost_getbe32(resp->lba);
|
||||
priv->blocksize = usbhost_getbe32(resp->blklen);
|
||||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CSW IN operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
FAR struct usbstrg_cbw_s *cbw;
|
||||
FAR struct scsiresp_inquiry_s *resp;
|
||||
int result = -ENOMEM;
|
||||
|
||||
/* Initialize a CBW (allocating it if necessary) */
|
||||
|
||||
cbw = usbhost_cbwalloc(priv);
|
||||
if (cbw)
|
||||
{
|
||||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_inquirycbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW OUT operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the CBW IN response */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, SCSIRESP_INQUIRY_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW IN response operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* TODO: If USB debug is enabled, dump the response data here */
|
||||
|
||||
resp = (FAR struct scsiresp_inquiry_s *)priv->tdbuffer;
|
||||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
|
||||
|
||||
/* Wait for the CSW IN operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -689,141 +864,116 @@ 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;
|
||||
FAR struct usbstrg_csw_s *csw;
|
||||
unsigned int retries;
|
||||
int result = OK;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
switch (priv->state)
|
||||
/* Request the maximum logical unit number */
|
||||
|
||||
uvdbg("Get max LUN\n");
|
||||
result = usbhost_maxlunreq(priv);
|
||||
|
||||
/* Wait for the unit to be ready */
|
||||
|
||||
for (retries = 0; retries < USBHOST_MAX_RETRIES && result == OK; retries++)
|
||||
{
|
||||
case USBSTRG_STATE_CONFIGURED: /* Received config descriptor */
|
||||
{
|
||||
struct usb_ctrlreq_s req;
|
||||
uvdbg("USBSTRG_STATE_CONFIGURED\n");
|
||||
uvdbg("Test unit ready, retries=%d\n", retries);
|
||||
|
||||
/* Make sure that we have a buffer allocated */
|
||||
/* Send TESTUNITREADY to see the unit is ready */
|
||||
|
||||
result = usbhost_testunitready(priv);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Is the unit is ready */
|
||||
|
||||
result = usbhost_tdalloc(priv);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Request maximum logical unit number */
|
||||
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
|
||||
if (csw->status == 0)
|
||||
{
|
||||
/* Yes... break out of the loop */
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
result = DRVR_CONTROL(priv->drvr, &req, priv->tdbuffer);
|
||||
priv->state = USBSTRG_STATE_MAXLUN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* No.. Request mode sense information (ignoring return status) */
|
||||
|
||||
case USBSTRG_STATE_MAXLUN: /* Requested maximum logical unit number */
|
||||
{
|
||||
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_SENSE: /* MODESENSE compleed */
|
||||
{
|
||||
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_TESTUNITREADY: /* TESTUNITREADY completed */
|
||||
{
|
||||
uvdbg("USBSTRG_STATE_TESTUNITREADY\n");
|
||||
|
||||
/* 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_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"
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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);
|
||||
result = -EINVAL;
|
||||
}
|
||||
break;
|
||||
uvdbg("Request sense\n");
|
||||
result = usbhost_requestsense(priv);
|
||||
}
|
||||
}
|
||||
usbhost_givesem(&priv->exclsem);
|
||||
|
||||
/* Abort everything on an error */
|
||||
/* Did the unit become ready? Did an error occur? Or did we time out? */
|
||||
|
||||
if (result != OK)
|
||||
if (retries >= USBHOST_MAX_RETRIES)
|
||||
{
|
||||
udbg("ERROR: Timeout!\n");
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (result == OK)
|
||||
{
|
||||
/* Get the capacity of the volume */
|
||||
|
||||
uvdbg("Read capacity\n");
|
||||
result = usbhost_readcapacity(priv);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Check the CSW for errors */
|
||||
|
||||
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
|
||||
if (csw->status != 0)
|
||||
{
|
||||
udbg("CSW status error: %d\n", csw->status);
|
||||
result = -ENODEV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get information about the volume */
|
||||
|
||||
if (result == OK)
|
||||
{
|
||||
/* Inquiry */
|
||||
|
||||
uvdbg("Inquiry\n");
|
||||
result = usbhost_inquiry(priv);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Check the CSW for errors */
|
||||
|
||||
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
|
||||
if (csw->status != 0)
|
||||
{
|
||||
udbg("CSW status error: %d\n", csw->status);
|
||||
result = -ENODEV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Register the block driver */
|
||||
|
||||
if (result == OK)
|
||||
{
|
||||
char devname[DEV_NAMELEN];
|
||||
|
||||
uvdbg("Register block driver\n");
|
||||
usbhost_mkdevname(priv, devname);
|
||||
result = register_blockdriver(devname, &g_bops, 0, priv);
|
||||
}
|
||||
|
||||
/* Check if we successfully initialized */
|
||||
|
||||
if (result == OK)
|
||||
{
|
||||
/* Set up for normal operation as a block device driver */
|
||||
|
||||
uvdbg("Successfully initialized\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
udbg("ERROR! Aborting: %d\n", result);
|
||||
DRVR_DISCONNECT(priv->drvr);
|
||||
usbhost_destroy(priv);
|
||||
}
|
||||
}
|
||||
@ -884,6 +1034,25 @@ static inline uint16_t usbhost_getle16(const uint8_t *val)
|
||||
return (uint16_t)val[1] << 8 | (uint16_t)val[0];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_getbe16
|
||||
*
|
||||
* Description:
|
||||
* Get a (possibly unaligned) 16-bit big endian value.
|
||||
*
|
||||
* Input Parameters:
|
||||
* val - A pointer to the first byte of the big endian value.
|
||||
*
|
||||
* Returned Values:
|
||||
* A uin16_t representing the whole 16-bit integer value
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint16_t usbhost_getbe16(const uint8_t *val)
|
||||
{
|
||||
return (uint16_t)val[0] << 8 | (uint16_t)val[1];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_putle16
|
||||
*
|
||||
@ -926,6 +1095,29 @@ static void usbhost_putbe16(uint8_t *dest, uint16_t val)
|
||||
dest[1] = val & 0xff;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_getbe32
|
||||
*
|
||||
* Description:
|
||||
* Put a (possibly unaligned) 32-bit big endian value.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dest - A pointer to the first byte to save the big endian value.
|
||||
* val - The 32-bit value to be saved.
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t usbhost_getbe32(const uint8_t *val)
|
||||
{
|
||||
/* Big endian means MS halfword first in byte stream */
|
||||
|
||||
return (uint32_t)usbhost_getbe16(val) << 16 | (uint32_t)usbhost_getbe16(&val[2]);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_putle32
|
||||
*
|
||||
@ -943,7 +1135,7 @@ static void usbhost_putbe16(uint8_t *dest, uint16_t val)
|
||||
|
||||
static void usbhost_putle32(uint8_t *dest, uint32_t val)
|
||||
{
|
||||
/* Little endian means LS halfwrd first in byte stream */
|
||||
/* Little endian means LS halfword first in byte stream */
|
||||
|
||||
usbhost_putle16(dest, (uint16_t)(val & 0xffff));
|
||||
usbhost_putle16(dest+2, (uint16_t)(val >> 16));
|
||||
@ -966,7 +1158,7 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val)
|
||||
|
||||
static void usbhost_putbe32(uint8_t *dest, uint32_t val)
|
||||
{
|
||||
/* Big endian means MS halfwrd first in byte stream */
|
||||
/* Big endian means MS halfword first in byte stream */
|
||||
|
||||
usbhost_putbe16(dest, (uint16_t)(val >> 16));
|
||||
usbhost_putbe16(dest+2, (uint16_t)(val & 0xffff));
|
||||
@ -1116,7 +1308,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
|
||||
/* Initialize class method function pointers */
|
||||
|
||||
priv->class.configdesc = usbhost_configdesc;
|
||||
priv->class.complete = usbhost_complete1;
|
||||
priv->class.complete = usbhost_complete;
|
||||
priv->class.disconnected = usbhost_disconnected;
|
||||
|
||||
/* The initial reference count is 1... One reference is held by the driver */
|
||||
@ -1183,8 +1375,7 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
|
||||
|
||||
DEBUGASSERT(priv != NULL &&
|
||||
configdesc != NULL &&
|
||||
desclen >= sizeof(struct usb_cfgdesc_s) &&
|
||||
priv->state == USBSTRG_STATE_CREATED);
|
||||
desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
|
||||
/* Verify that we were passed a configuration descriptor */
|
||||
|
||||
@ -1314,16 +1505,15 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
|
||||
|
||||
/* Now configure the LUNs and register the block driver(s) */
|
||||
|
||||
priv->state = USBSTRG_STATE_CONFIGURED;
|
||||
usbhost_work(priv, usbhost_statemachine);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_complete1 & 2
|
||||
* Name: usbhost_complete
|
||||
*
|
||||
* Description:
|
||||
* These functions implement the complete() method of struct
|
||||
* This function implements 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
|
||||
@ -1331,14 +1521,6 @@ 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().
|
||||
@ -1354,23 +1536,11 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int usbhost_complete1(FAR struct usbhost_class_s *class,
|
||||
static int usbhost_complete(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 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);
|
||||
DEBUGASSERT(priv != NULL && priv->waitsem.semcount <= 0);
|
||||
|
||||
/* Wake up the application thread waiting for the transfer completion event */
|
||||
|
||||
@ -1463,7 +1633,6 @@ static int usbhost_open(FAR struct inode *inode)
|
||||
|
||||
DEBUGASSERT(priv->crefs < MAX_CREFS);
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||
priv->crefs++;
|
||||
usbhost_givesem(&priv->exclsem);
|
||||
ret = OK;
|
||||
@ -1491,7 +1660,6 @@ static int usbhost_close(FAR struct inode *inode)
|
||||
|
||||
DEBUGASSERT(priv->crefs > 0);
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||
priv->crefs--;
|
||||
|
||||
/* Release the semaphore. The following operations when crefs == 1 are
|
||||
@ -1511,6 +1679,7 @@ static int usbhost_close(FAR struct inode *inode)
|
||||
{
|
||||
/* Destroy the class instance */
|
||||
|
||||
DEBUGASSERT(priv->crefs == 1);
|
||||
usbhost_destroy(priv);
|
||||
}
|
||||
return OK;
|
||||
@ -1530,6 +1699,7 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
|
||||
{
|
||||
FAR struct usbhost_state_s *priv;
|
||||
ssize_t ret = 0;
|
||||
int result;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
priv = (FAR struct usbhost_state_s *)inode->i_private;
|
||||
@ -1549,9 +1719,64 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
|
||||
}
|
||||
else if (nsectors > 0)
|
||||
{
|
||||
FAR struct usbstrg_cbw_s *cbw;
|
||||
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||
#warning "Missing logic"
|
||||
|
||||
/* Assume allocation failure */
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
/* Initialize a CBW (allocating it if necessary) */
|
||||
|
||||
cbw = usbhost_cbwalloc(priv);
|
||||
if (cbw)
|
||||
{
|
||||
/* Assume some device failure */
|
||||
|
||||
ret = -ENODEV;
|
||||
|
||||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW OUT operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the user data */
|
||||
#warning "For lpc17xx, I think this buffer needs to lie in BANK1"
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
buffer, priv->blocksize * nsectors);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the data in operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
FAR struct usbstrg_csw_s *csw;
|
||||
|
||||
/* Check the CSW status */
|
||||
|
||||
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
|
||||
if (csw->status == 0)
|
||||
{
|
||||
ret = nsectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usbhost_givesem(&priv->exclsem);
|
||||
}
|
||||
|
||||
@ -1574,7 +1799,8 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
|
||||
size_t startsector, unsigned int nsectors)
|
||||
{
|
||||
FAR struct usbhost_state_s *priv;
|
||||
int ret;
|
||||
ssize_t ret;
|
||||
int result;
|
||||
|
||||
uvdbg("sector: %d nsectors: %d sectorsize: %d\n");
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
@ -1593,9 +1819,64 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
|
||||
}
|
||||
else
|
||||
{
|
||||
FAR struct usbstrg_cbw_s *cbw;
|
||||
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||
#warning "Missing logic"
|
||||
|
||||
/* Assume allocation failure */
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
/* Initialize a CBW (allocating it if necessary) */
|
||||
|
||||
cbw = usbhost_cbwalloc(priv);
|
||||
if (cbw)
|
||||
{
|
||||
/* Assume some device failure */
|
||||
|
||||
ret = -ENODEV;
|
||||
|
||||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the CBW OUT operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Send the user data */
|
||||
#warning "For lpc17xx, I think this buffer needs to lie in BANK1"
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
|
||||
buffer, priv->blocksize * nsectors);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Wait for the data in operation to complete */
|
||||
|
||||
usbhost_takesem(&priv->waitsem);
|
||||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
|
||||
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
FAR struct usbstrg_csw_s *csw;
|
||||
|
||||
/* Check the CSW status */
|
||||
|
||||
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
|
||||
if (csw->status == 0)
|
||||
{
|
||||
ret = nsectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usbhost_givesem(&priv->exclsem);
|
||||
}
|
||||
|
||||
@ -1637,7 +1918,6 @@ static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry)
|
||||
/* Return the geometry of the USB mass storage device */
|
||||
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||
|
||||
geometry->geo_available = true;
|
||||
geometry->geo_mediachanged = false;
|
||||
@ -1691,8 +1971,6 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
|
||||
/* Process the IOCTL by command */
|
||||
|
||||
usbhost_takesem(&priv->exclsem);
|
||||
DEBUGASSERT(priv->state == USBSTRG_STATE_READY);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* Add support for ioctl commands here */
|
||||
@ -1701,7 +1979,6 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
usbhost_givesem(&priv->exclsem);
|
||||
}
|
||||
return ret;
|
||||
|
@ -313,6 +313,30 @@
|
||||
|
||||
#define DRVR_TRANSFER(drvr,ed,buffer,buflen) ((drvr)->transfer(drvr,ed,buffer,buflen))
|
||||
|
||||
/************************************************************************************
|
||||
* Name: DRVR_DISCONNECT
|
||||
*
|
||||
* Description:
|
||||
* Called by the class when an error occurs and driver has been disconnected.
|
||||
* The USB host driver should discard the handle to the class instance (it is
|
||||
* stale) and not attempt any further interaction with the class driver instance
|
||||
* (until a new instance is received from the create() method). The driver
|
||||
* should not called the class' disconnected() method.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* This function will *not* be called from an interrupt handler.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr))
|
||||
|
||||
/************************************************************************************
|
||||
* Public Types
|
||||
************************************************************************************/
|
||||
@ -444,6 +468,14 @@ struct usbhost_driver_s
|
||||
int (*transfer)(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_epdesc_s *ed,
|
||||
FAR uint8_t *buffer, size_t buflen);
|
||||
|
||||
/* Called by the class when an error occurs and driver has been disconnected.
|
||||
* The USB host driver should discard the handle to the class instance (it is
|
||||
* stale) and not attempt any further interaction with the class driver instance
|
||||
* (until a new instance is received from the create() method).
|
||||
*/
|
||||
|
||||
void (*disconnect)(FAR struct usbhost_driver_s *drvr);
|
||||
};
|
||||
|
||||
/* This structure describes one endpoint */
|
||||
|
Loading…
Reference in New Issue
Block a user