diff options
Diffstat (limited to 'nuttx/drivers/usbdev/usbdev_storage.h')
-rw-r--r-- | nuttx/drivers/usbdev/usbdev_storage.h | 538 |
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 */ |