summaryrefslogtreecommitdiff
path: root/nuttx/drivers/usbdev/usbdev_storage.h
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/usbdev/usbdev_storage.h')
-rw-r--r--nuttx/drivers/usbdev/usbdev_storage.h538
1 files changed, 538 insertions, 0 deletions
diff --git a/nuttx/drivers/usbdev/usbdev_storage.h b/nuttx/drivers/usbdev/usbdev_storage.h
new file mode 100644
index 000000000..9f42d1567
--- /dev/null
+++ b/nuttx/drivers/usbdev/usbdev_storage.h
@@ -0,0 +1,538 @@
+/****************************************************************************
+ * drivers/usbdev/usbdev_storage.h
+ *
+ * Copyright (C) 2008 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Mass storage class device. Bulk-only with SCSI subclass.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_USBDEV_USBDEV_STORAGE_H
+#define __DRIVERS_USBDEV_USBDEV_STORAGE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include <pthread.h>
+#include <queue.h>
+
+#include <nuttx/fs.h>
+#include <nuttx/usb_bulk.h>
+#include <nuttx/usbdev.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* Number of requests in the write queue */
+
+#ifndef CONFIG_USBSTRG_NWRREQS
+# define CONFIG_USBSTRG_NWRREQS 4
+#endif
+
+/* Number of requests in the read queue */
+
+#ifndef CONFIG_USBSTRG_NRDREQS
+# define CONFIG_USBSTRG_NRDREQS 4
+#endif
+
+/* Logical endpoint numbers / max packet sizes */
+
+#ifndef CONFIG_USBSTRG_EPBULKOUT
+# warning "EPBULKOUT not defined in the configuration"
+# define CONFIG_USBSTRG_EPBULKOUT 2
+#endif
+
+#ifndef CONFIG_USBSTRG_EPBULKIN
+# warning "EPBULKIN not defined in the configuration"
+# define CONFIG_USBSTRG_EPBULKIN 3
+#endif
+
+/* Packet and request buffer sizes */
+
+#ifndef CONFIG_USBSTRG_EP0MAXPACKET
+# define CONFIG_USBSTRG_EP0MAXPACKET 64
+#endif
+
+#ifndef CONFIG_USBSTRG_BULKINREQLEN
+# ifdef CONFIG_USBDEV_DUALSPEED
+# define CONFIG_USBSTRG_BULKINREQLEN 512
+# else
+# define CONFIG_USBSTRG_BULKINREQLEN 64
+# endif
+#else
+# ifdef CONFIG_USBDEV_DUALSPEED
+# if CONFIG_USBSTRG_BULKINREQLEN < 512
+# warning "Bulk in buffer size smaller than max packet"
+# undef CONFIG_USBSTRG_BULKINREQLEN
+# define CONFIG_USBSTRG_BULKINREQLEN 512
+# endif
+# else
+# if CONFIG_USBSTRG_BULKINREQLEN < 64
+# warning "Bulk in buffer size smaller than max packet"
+# undef CONFIG_USBSTRG_BULKINREQLEN
+# define CONFIG_USBSTRG_BULKINREQLEN 64
+# endif
+# endif
+#endif
+
+#ifndef CONFIG_USBSTRG_BULKOUTREQLEN
+# ifdef CONFIG_USBDEV_DUALSPEED
+# define CONFIG_USBSTRG_BULKOUTREQLEN 512
+# else
+# define CONFIG_USBSTRG_BULKOUTREQLEN 64
+# endif
+#else
+# ifdef CONFIG_USBDEV_DUALSPEED
+# if CONFIG_USBSTRG_BULKOUTREQLEN < 512
+# warning "Bulk in buffer size smaller than max packet"
+# undef CONFIG_USBSTRG_BULKOUTREQLEN
+# define CONFIG_USBSTRG_BULKOUTREQLEN 512
+# endif
+# else
+# if CONFIG_USBSTRG_BULKOUTREQLEN < 64
+# warning "Bulk in buffer size smaller than max packet"
+# undef CONFIG_USBSTRG_BULKOUTREQLEN
+# define CONFIG_USBSTRG_BULKOUTREQLEN 64
+# endif
+# endif
+#endif
+
+/* Vendor and product IDs and strings */
+
+#ifndef CONFIG_USBSTRG_VENDORID
+# warning "CONFIG_USBSTRG_VENDORID not defined"
+# define CONFIG_USBSTRG_VENDORID 0x584e
+#endif
+
+#ifndef CONFIG_USBSTRG_PRODUCTID
+# warning "CONFIG_USBSTRG_PRODUCTID not defined"
+# define CONFIG_USBSTRG_PRODUCTID 0x5342
+#endif
+
+#ifndef CONFIG_USBSTRG_VERSIONNO
+# define CONFIG_USBSTRG_VERSIONNO (0x0399)
+#endif
+
+#ifndef CONFIG_USBSTRG_VENDORSTR
+# warning "No Vendor string specified"
+# define CONFIG_USBSTRG_VENDORSTR "NuttX"
+#endif
+
+#ifndef CONFIG_USBSTRG_PRODUCTSTR
+# warning "No Product string specified"
+# define CONFIG_USBSTRG_PRODUCTSTR "USBdev Storage"
+#endif
+
+#undef CONFIG_USBSTRG_SERIALSTR
+#define CONFIG_USBSTRG_SERIALSTR "0101"
+
+#undef CONFIG_USBSTRG_CONFIGSTR
+#define CONFIG_USBSTRG_CONFIGSTR "Bulk"
+
+/* Debug -- must be consistent with include/debug.h */
+
+#ifdef CONFIG_CPP_HAVE_VARARGS
+# ifdef CONFIG_DEBUG
+# ifdef CONFIG_ARCH_LOWPUTC
+# define dbgprintf(format, arg...) lib_lowprintf(format, ##arg)
+# else
+# define dbgprintf(format, arg...) lib_rawprintf(format, ##arg)
+# endif
+# else
+# define dbgprintf(x...)
+# endif
+#else
+# ifdef CONFIG_DEBUG
+# ifdef CONFIG_ARCH_LOWPUTC
+# define dbgprintf lib_lowprintf
+# else
+# define dbgprintf lib_rawprintf
+# endif
+# else
+# define dbgprintf (void)
+# endif
+#endif
+
+/* Packet and request buffer sizes */
+
+#ifndef CONFIG_USBSTRG_EP0MAXPACKET
+# define CONFIG_USBSTRG_EP0MAXPACKET 64
+#endif
+
+/* USB Controller */
+
+#ifndef CONFIG_USBDEV_SELFPOWERED
+# define SELFPOWERED USB_CONFIG_ATT_SELFPOWER
+#else
+# define SELFPOWERED (0)
+#endif
+
+#ifndef CONFIG_USBDEV_REMOTEWAKEUP
+# define REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP
+#else
+# define REMOTEWAKEUP (0)
+#endif
+
+#ifndef CONFIG_USBDEV_MAXPOWER
+# define CONFIG_USBDEV_MAXPOWER 100
+#endif
+
+/* Current state of the worker thread */
+
+#define USBSTRG_STATE_NOTSTARTED (0) /* Thread has not yet been started */
+#define USBSTRG_STATE_STARTED (1) /* Started, but is not yet initialized */
+#define USBSTRG_STATE_IDLE (2) /* Started and waiting for commands */
+#define USBSTRG_STATE_CMDPARSE (3) /* Processing a received command */
+#define USBSTRG_STATE_CMDREAD (4) /* Processing a SCSI read command */
+#define USBSTRG_STATE_CMDWRITE (5) /* Processing a SCSI write command */
+#define USBSTRG_STATE_CMDFINISH (6) /* Finish command processing */
+#define USBSTRG_STATE_CMDSTATUS (7) /* Processing the final status of the command */
+#define USBSTRG_STATE_TERMINATED (8) /* Thread has exitted */
+
+/* Event communicated to worker thread */
+
+#define USBSTRG_EVENT_NOEVENTS (0) /* There are no outstanding events */
+#define USBSTRG_EVENT_READY (1 << 0) /* Initialization is complete */
+#define USBSTRG_EVENT_RDCOMPLETE (1 << 1) /* A read has completed there is data to be processed */
+#define USBSTRG_EVENT_WRCOMPLETE (1 << 2) /* A write has completed and a request is available */
+#define USBSTRG_EVENT_TERMINATEREQUEST (1 << 3) /* Shutdown requested */
+#define USBSTRG_EVENT_DISCONNECT (1 << 4) /* USB disconnect received */
+#define USBSTRG_EVENT_RESET (1 << 5) /* USB storage setup reset received */
+#define USBSTRG_EVENT_CFGCHANGE (1 << 6) /* USB setup configuration change received */
+#define USBSTRG_EVENT_IFCHANGE (1 << 7) /* USB setup interface change received */
+#define USBSTRG_EVENT_ABORTBULKOUT (1 << 8) /* SCSI receive failure */
+
+/* SCSI command flags (passed to usbstrg_setupcmd()) */
+
+#define USBSTRG_FLAGS_DIRMASK (0x03) /* Bits 0-1: Data direction */
+#define USBSTRG_FLAGS_DIRNONE (0x00) /* No data to send */
+#define USBSTRG_FLAGS_DIRHOST2DEVICE (0x01) /* Host-to-device */
+#define USBSTRG_FLAGS_DIRDEVICE2HOST (0x02) /* Device-to-host */
+#define USBSTRG_FLAGS_BLOCKXFR (0x04) /* Bit 2: Command is a block transfer request */
+#define USBSTRG_FLAGS_LUNNOTNEEDED (0x08) /* Bit 3: Command does not require a valid LUN */
+#define USBSTRG_FLAGS_UACOKAY (0x10) /* Bit 4: Command OK if unit attention condition */
+#define USBSTRG_FLAGS_RETAINSENSEDATA (0x20) /* Bit 5: Do not clear sense data */
+
+/* Descriptors **************************************************************/
+
+/* Big enough to hold our biggest descriptor */
+
+#define USBSTRG_MXDESCLEN (64)
+
+/* String language */
+
+#define USBSTRG_STR_LANGUAGE (0x0409) /* en-us */
+
+/* Descriptor strings */
+
+#define USBSTRG_MANUFACTURERSTRID (1)
+#define USBSTRG_PRODUCTSTRID (2)
+#define USBSTRG_SERIALSTRID (3)
+#define USBSTRG_CONFIGSTRID (4)
+#define USBSTRG_NCONFIGS (1) /* Number of configurations supported */
+
+/* Configuration Descriptor */
+
+#define USBSTRG_NINTERFACES (1) /* Number of interfaces in the configuration */
+#define USBSTRG_INTERFACEID (0)
+#define USBSTRG_ALTINTERFACEID (0)
+#define USBSTRG_CONFIGIDNONE (0) /* Config ID means to return to address mode */
+#define USBSTRG_CONFIGID (1) /* The only supported configuration ID */
+
+#define STRING_MANUFACTURER (1)
+#define STRING_PRODUCT (2)
+#define STRING_SERIAL (3)
+
+#define USBSTRG_CONFIGID (1) /* There is only one configuration. */
+
+/* Interface description */
+
+#define USBSTRG_NENDPOINTS (2) /* Number of endpoints in the interface */
+
+/* Endpoint configuration */
+
+#define USBSTRG_EPOUTBULK_ADDR (CONFIG_USBSTRG_EPBULKOUT)
+#define USBSTRG_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK)
+
+#define USBSTRG_EPINBULK_ADDR (USB_DIR_IN|CONFIG_USBSTRG_EPBULKIN)
+#define USBSTRG_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK)
+
+#define USBSTRG_HSBULKMAXPACKET (512)
+#define USBSTRG_HSBULKMXPKTSHIFT (9)
+#define USBSTRG_HSBULKMXPKTMASK (0x000001ff)
+#define USBSTRG_FSBULKMAXPACKET (64)
+#define USBSTRG_FSBULKMXPKTSHIFT (6)
+#define USBSTRG_FSBULKMXPKTMASK (0x0000003f)
+
+/* Macros for dual speed vs. full speed only operation */
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+# define USBSTRG_EPBULKINDESC(hs) ((hs) ? (g_hsepbulkindesc) : (g_fsepbulkindesc))
+# define USBSTRG_EPBULKOUTDESC(hs) ((hs) ? (g_hsepbulkoutdesc) : (g_fsepbulkoutdesc))
+# define USBSTRG_BULKMAXPACKET(hs) \
+ ((hs) ? USBSTRG_HSBULKMAXPACKET : USBSTRG_FSBULKMAXPACKET)
+# define USBSTRG_BULKMXPKTSHIFT(d) \
+ (((d)->speed==USB_SPEED_HIGH) ? USBSTRG_HSBULKMXPKTSHIFT : USBSTRG_FSBULKMXPKTSHIFT)
+# define USBSTRG_BULKMXPKTMASK(d) \
+ (((d)->speed==USB_SPEED_HIGH) ? USBSTRG_HSBULKMXPKTMASK : USBSTRG_FSBULKMXPKTMASK)
+#else
+# define USBSTRG_EPBULKINDESC(d) (g_fsepbulkindesc))
+# define USBSTRG_EPBULKOUTDESC(d) (g_fsepbulkoutdesc))
+# define USBSTRG_BULKMAXPACKET(hs) USBSTRG_FSBULKMAXPACKET
+# define USBSTRG_BULKMXPKTSHIFT(d) USBSTRG_FSBULKMXPKTSHIFT
+# define USBSTRG_BULKMXPKTMASK(d) USBSTRG_FSBULKMXPKTMASK
+#endif
+
+/* Block driver helpers *****************************************************/
+
+#define USBSTRG_DRVR_READ(l,b,s,n) ((l)->inode->u.i_bops->read((l)->inode,b,s,n))
+#define USBSTRG_DRVR_WRITE(l,b,s,n) ((l)->inode->u.i_bops->write((l)->inode,b,s,n))
+#define USBSTRG_DRVR_GEOMETRY(l,g) ((l)->inode->u.i_bops->geometry((l)->inode,g))
+
+/* Everpresent min/max macros ***********************************************/
+
+#ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef max
+# define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Container to support a list of requests */
+
+struct usbstrg_req_s
+{
+ FAR struct usbstrg_req_s *flink; /* Implements a singly linked list */
+ FAR struct usbdev_req_s *req; /* The contained request */
+};
+
+/* This structure describes one LUN: */
+
+struct usbstrg_lun_s
+{
+ struct inode *inode; /* Inode structure of open'ed block driver */
+ ubyte readonly:1; /* Media is read-only */
+ ubyte locked:1; /* Media removal is prevented */
+ uint16 sectorsize; /* The size of one sector */
+ uint32 sd; /* Sense data */
+ uint32 sdinfo; /* Sense data information */
+ uint32 uad; /* Unit needs attention data */
+ off_t startsector; /* Sector offset to start of partition */
+ size_t nsectors; /* Number of sectors in the partition */
+};
+
+/* Describes the overall state of the driver */
+
+struct usbstrg_dev_s
+{
+ FAR struct usbdev_s *usbdev; /* usbdev driver pointer (Non-null if registered) */
+
+ /* Worker thread interface */
+
+ pthread_t thread; /* The worker thread */
+ pthread_mutex_t mutex; /* Mutually exclusive access to resources*/
+ pthread_cond_t cond; /* Used to signal worker thread */
+ volatile ubyte thstate; /* State of the worker thread */
+ volatile uint16 theventset; /* Set of pending events signaled to worker thread */
+ volatile ubyte thvalue; /* Value passed with the event (must persist) */
+
+ /* Storage class configuration and state */
+
+ ubyte nluns:4; /* Number of LUNs */
+ ubyte config; /* Configuration number */
+ ubyte nwrq; /* Number of queue write requests (in wrreqlist)*/
+ ubyte nrdq; /* Number of queue read requests (in epbulkout) */
+
+ /* Endpoints */
+
+ FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */
+ FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */
+ FAR struct usbdev_req_s *ctrlreq; /* Control request (for ep0 setup responses) */
+
+ /* SCSI commands */
+
+ struct usbstrg_lun_s *lun; /* Currently selected LUN */
+ struct usbstrg_lun_s *luntab; /* Allocated table of all LUNs */
+ ubyte cdb[USBSTRG_MAXCDBLEN]; /* Command data (cdb[]) from CBW */
+ ubyte phaseerror:1; /* Need to send phase sensing status */
+ ubyte shortpacket:1; /* Host transmission stopped unexpectedly */
+ ubyte cbwdir:2; /* Direction from CBW. See USBSTRG_FLAGS_DIR* definitions */
+ ubyte cdblen; /* Length of cdb[] from CBW */
+ ubyte cbwlun; /* LUN from the CBW */
+ uint16 nsectbytes; /* Bytes buffered in iobuffer[] */
+ uint16 nreqbytes; /* Bytes buffered in head write requests */
+ uint16 iosize; /* Size of iobuffer[] */
+ uint32 cbwlen; /* Length of data from CBW */
+ uint32 cbwtag; /* Tag from the CBW */
+ union
+ {
+ uint32 xfrlen; /* Read/Write: Sectors remaining to be transferred */
+ uint32 alloclen; /* Other device-to-host: Host allocation length */
+ } u;
+ uint32 sector; /* Current sector (relative to lun->startsector) */
+ uint32 residue; /* Untransferred amount reported in the CSW */
+ ubyte *iobuffer; /* Buffer for data transfers */
+
+ /* Write request list */
+
+ struct sq_queue_s wrreqlist; /* List of empty write request containers */
+ struct sq_queue_s rdreqlist; /* List of filled read request containers */
+
+ /* Pre-allocated write request containers. The write requests will
+ * be linked in a free list (wrreqlist), and used to send requests to
+ * EPBULKIN; Read requests will be queued in the EBULKOUT.
+ */
+
+ struct usbstrg_req_s wrreqs[CONFIG_USBSTRG_NWRREQS];
+ struct usbstrg_req_s rdreqs[CONFIG_USBSTRG_NRDREQS];
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+# define EXTERN extern "C"
+extern "C"
+{
+#else
+# define EXTERN extern
+#endif
+
+/* String *******************************************************************/
+
+EXTERN const char g_vendorstr[];
+EXTERN const char g_productstr[];
+EXTERN const char g_serialstr[];
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+/****************************************************************************
+ * Name: usbstrg_workerthread
+ *
+ * Description:
+ * This is the main function of the USB storage worker thread. It loops
+ * until USB-related events occur, then processes those events accordingly
+ *
+ ****************************************************************************/
+
+EXTERN void *usbstrg_workerthread(void *arg);
+
+/****************************************************************************
+ * Name: usbstrg_setconfig
+ *
+ * Description:
+ * Set the device configuration by allocating and configuring endpoints and
+ * by allocating and queue read and write requests.
+ *
+ ****************************************************************************/
+
+EXTERN int usbstrg_setconfig(FAR struct usbstrg_dev_s *priv, ubyte config);
+
+/****************************************************************************
+ * Name: usbstrg_resetconfig
+ *
+ * Description:
+ * Mark the device as not configured and disable all endpoints.
+ *
+ ****************************************************************************/
+
+EXTERN void usbstrg_resetconfig(FAR struct usbstrg_dev_s *priv);
+
+/****************************************************************************
+ * Name: usbstrg_wrcomplete
+ *
+ * Description:
+ * Handle completion of write request. This function probably executes
+ * in the context of an interrupt handler.
+ *
+ ****************************************************************************/
+
+EXTERN void usbstrg_wrcomplete(FAR struct usbdev_ep_s *ep,
+ FAR struct usbdev_req_s *req);
+
+/****************************************************************************
+ * Name: usbstrg_rdcomplete
+ *
+ * Description:
+ * Handle completion of read request on the bulk OUT endpoint. This
+ * is handled like the receipt of serial data on the "UART"
+ *
+ ****************************************************************************/
+
+EXTERN void usbstrg_rdcomplete(FAR struct usbdev_ep_s *ep,
+ FAR struct usbdev_req_s *req);
+
+/****************************************************************************
+ * Name: usbstrg_deferredresponse
+ *
+ * Description:
+ * Some EP0 setup request cannot be responded to immediately becuase they
+ * require some asynchronous action from the SCSI worker thread. This
+ * function is provided for the SCSI thread to make that deferred response.
+ * The specific requests that require this deferred response are:
+ *
+ * 1. USB_REQ_SETCONFIGURATION,
+ * 2. USB_REQ_SETINTERFACE, or
+ * 3. USBSTRG_REQ_MSRESET
+ *
+ * In all cases, the success reponse is a zero-length packet; the failure
+ * response is an EP0 stall.
+ *
+ * Input parameters:
+ * priv - Private state structure for this USB storage instance
+ * stall - TRUE is the action failed and a stall is required
+ *
+ ****************************************************************************/
+
+EXTERN void usbstrg_deferredresponse(FAR struct usbstrg_dev_s *priv, boolean failed);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* #define __DRIVERS_USBDEV_USBDEV_STORAGE_H */