You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
694 lines
24 KiB
694 lines
24 KiB
/**************************************************************************** |
|
* drivers/usbdev/usbmsc.h |
|
* |
|
* Copyright (C) 2008-2012 Gregory Nutt. All rights reserved. |
|
* Author: Gregory Nutt <gnutt@nuttx.org> |
|
* |
|
* 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_USBMSC_H |
|
#define __DRIVERS_USBDEV_USBMSC_H |
|
|
|
/**************************************************************************** |
|
* Included Files |
|
****************************************************************************/ |
|
|
|
#include <nuttx/config.h> |
|
|
|
#include <sys/types.h> |
|
#include <stdint.h> |
|
#include <stdbool.h> |
|
#include <pthread.h> |
|
#include <queue.h> |
|
|
|
#include <nuttx/fs/fs.h> |
|
#include <nuttx/usb/storage.h> |
|
#include <nuttx/usb/usbdev.h> |
|
|
|
/**************************************************************************** |
|
* Pre-processor Definitions |
|
****************************************************************************/ |
|
/* Configuration ************************************************************/ |
|
/* If the USB mass storage device is configured as part of a composite device |
|
* then both CONFIG_USBDEV_COMPOSITE and CONFIG_USBMSC_COMPOSITE must be |
|
* defined. |
|
*/ |
|
|
|
#ifndef CONFIG_USBDEV_COMPOSITE |
|
# undef CONFIG_USBMSC_COMPOSITE |
|
#endif |
|
|
|
#if defined(CONFIG_USBMSC_COMPOSITE) && !defined(CONFIG_USBMSC_STRBASE) |
|
# define CONFIG_USBMSC_STRBASE (4) |
|
#endif |
|
|
|
/* Interface IDs. If the mass storage driver is built as a component of a |
|
* composite device, then the interface IDs may need to be offset. |
|
*/ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
# undef CONFIG_USBMSC_IFNOBASE |
|
# define CONFIG_USBMSC_IFNOBASE 0 |
|
#endif |
|
|
|
#ifndef CONFIG_USBMSC_IFNOBASE |
|
# define CONFIG_USBMSC_IFNOBASE 0 |
|
#endif |
|
|
|
/* Number of requests in the write queue */ |
|
|
|
#ifndef CONFIG_USBMSC_NWRREQS |
|
# define CONFIG_USBMSC_NWRREQS 4 |
|
#endif |
|
|
|
/* Number of requests in the read queue */ |
|
|
|
#ifndef CONFIG_USBMSC_NRDREQS |
|
# define CONFIG_USBMSC_NRDREQS 4 |
|
#endif |
|
|
|
/* Logical endpoint numbers / max packet sizes */ |
|
|
|
#ifndef CONFIG_USBMSC_EPBULKOUT |
|
# warning "EPBULKOUT not defined in the configuration" |
|
# define CONFIG_USBMSC_EPBULKOUT 2 |
|
#endif |
|
|
|
#ifndef CONFIG_USBMSC_EPBULKIN |
|
# warning "EPBULKIN not defined in the configuration" |
|
# define CONFIG_USBMSC_EPBULKIN 3 |
|
#endif |
|
|
|
/* Packet and request buffer sizes */ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
# ifndef CONFIG_USBMSC_EP0MAXPACKET |
|
# define CONFIG_USBMSC_EP0MAXPACKET 64 |
|
# endif |
|
#endif |
|
|
|
#ifndef CONFIG_USBMSC_BULKINREQLEN |
|
# ifdef CONFIG_USBDEV_DUALSPEED |
|
# define CONFIG_USBMSC_BULKINREQLEN 512 |
|
# else |
|
# define CONFIG_USBMSC_BULKINREQLEN 64 |
|
# endif |
|
#else |
|
# ifdef CONFIG_USBDEV_DUALSPEED |
|
# if CONFIG_USBMSC_BULKINREQLEN < 512 |
|
# warning "Bulk in buffer size smaller than max packet" |
|
# undef CONFIG_USBMSC_BULKINREQLEN |
|
# define CONFIG_USBMSC_BULKINREQLEN 512 |
|
# endif |
|
# else |
|
# if CONFIG_USBMSC_BULKINREQLEN < 64 |
|
# warning "Bulk in buffer size smaller than max packet" |
|
# undef CONFIG_USBMSC_BULKINREQLEN |
|
# define CONFIG_USBMSC_BULKINREQLEN 64 |
|
# endif |
|
# endif |
|
#endif |
|
|
|
#ifndef CONFIG_USBMSC_BULKOUTREQLEN |
|
# ifdef CONFIG_USBDEV_DUALSPEED |
|
# define CONFIG_USBMSC_BULKOUTREQLEN 512 |
|
# else |
|
# define CONFIG_USBMSC_BULKOUTREQLEN 64 |
|
# endif |
|
#else |
|
# ifdef CONFIG_USBDEV_DUALSPEED |
|
# if CONFIG_USBMSC_BULKOUTREQLEN < 512 |
|
# warning "Bulk in buffer size smaller than max packet" |
|
# undef CONFIG_USBMSC_BULKOUTREQLEN |
|
# define CONFIG_USBMSC_BULKOUTREQLEN 512 |
|
# endif |
|
# else |
|
# if CONFIG_USBMSC_BULKOUTREQLEN < 64 |
|
# warning "Bulk in buffer size smaller than max packet" |
|
# undef CONFIG_USBMSC_BULKOUTREQLEN |
|
# define CONFIG_USBMSC_BULKOUTREQLEN 64 |
|
# endif |
|
# endif |
|
#endif |
|
|
|
/* Vendor and product IDs and strings */ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
# ifndef CONFIG_USBMSC_VENDORID |
|
# warning "CONFIG_USBMSC_VENDORID not defined" |
|
# define CONFIG_USBMSC_VENDORID 0x584e |
|
# endif |
|
|
|
# ifndef CONFIG_USBMSC_PRODUCTID |
|
# warning "CONFIG_USBMSC_PRODUCTID not defined" |
|
# define CONFIG_USBMSC_PRODUCTID 0x5342 |
|
# endif |
|
|
|
# ifndef CONFIG_USBMSC_VERSIONNO |
|
# define CONFIG_USBMSC_VERSIONNO (0x0399) |
|
# endif |
|
|
|
# ifndef CONFIG_USBMSC_VENDORSTR |
|
# warning "No Vendor string specified" |
|
# define CONFIG_USBMSC_VENDORSTR "NuttX" |
|
# endif |
|
|
|
# ifndef CONFIG_USBMSC_PRODUCTSTR |
|
# warning "No Product string specified" |
|
# define CONFIG_USBMSC_PRODUCTSTR "USBdev Storage" |
|
# endif |
|
|
|
# undef CONFIG_USBMSC_SERIALSTR |
|
# define CONFIG_USBMSC_SERIALSTR "0101" |
|
#endif |
|
|
|
#undef CONFIG_USBMSC_CONFIGSTR |
|
#define CONFIG_USBMSC_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_USBMSC_EP0MAXPACKET |
|
# define CONFIG_USBMSC_EP0MAXPACKET 64 |
|
#endif |
|
|
|
/* USB Controller */ |
|
|
|
#ifndef CONFIG_USBDEV_SELFPOWERED |
|
# define SELFPOWERED USB_CONFIG_ATTR_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 USBMSC_STATE_NOTSTARTED (0) /* Thread has not yet been started */ |
|
#define USBMSC_STATE_STARTED (1) /* Started, but is not yet initialized */ |
|
#define USBMSC_STATE_IDLE (2) /* Started and waiting for commands */ |
|
#define USBMSC_STATE_CMDPARSE (3) /* Processing a received command */ |
|
#define USBMSC_STATE_CMDREAD (4) /* Processing a SCSI read command */ |
|
#define USBMSC_STATE_CMDWRITE (5) /* Processing a SCSI write command */ |
|
#define USBMSC_STATE_CMDFINISH (6) /* Finish command processing */ |
|
#define USBMSC_STATE_CMDSTATUS (7) /* Processing the final status of the command */ |
|
#define USBMSC_STATE_TERMINATED (8) /* Thread has exitted */ |
|
|
|
/* Event communicated to worker thread */ |
|
|
|
#define USBMSC_EVENT_NOEVENTS (0) /* There are no outstanding events */ |
|
#define USBMSC_EVENT_READY (1 << 0) /* Initialization is complete */ |
|
#define USBMSC_EVENT_RDCOMPLETE (1 << 1) /* A read has completed there is data to be processed */ |
|
#define USBMSC_EVENT_WRCOMPLETE (1 << 2) /* A write has completed and a request is available */ |
|
#define USBMSC_EVENT_TERMINATEREQUEST (1 << 3) /* Shutdown requested */ |
|
#define USBMSC_EVENT_DISCONNECT (1 << 4) /* USB disconnect received */ |
|
#define USBMSC_EVENT_RESET (1 << 5) /* USB storage setup reset received */ |
|
#define USBMSC_EVENT_CFGCHANGE (1 << 6) /* USB setup configuration change received */ |
|
#define USBMSC_EVENT_IFCHANGE (1 << 7) /* USB setup interface change received */ |
|
#define USBMSC_EVENT_ABORTBULKOUT (1 << 8) /* SCSI receive failure */ |
|
|
|
/* SCSI command flags (passed to usbmsc_setupcmd()) */ |
|
|
|
#define USBMSC_FLAGS_DIRMASK (0x03) /* Bits 0-1: Data direction */ |
|
#define USBMSC_FLAGS_DIRNONE (0x00) /* No data to send */ |
|
#define USBMSC_FLAGS_DIRHOST2DEVICE (0x01) /* Host-to-device */ |
|
#define USBMSC_FLAGS_DIRDEVICE2HOST (0x02) /* Device-to-host */ |
|
#define USBMSC_FLAGS_BLOCKXFR (0x04) /* Bit 2: Command is a block transfer request */ |
|
#define USBMSC_FLAGS_LUNNOTNEEDED (0x08) /* Bit 3: Command does not require a valid LUN */ |
|
#define USBMSC_FLAGS_UACOKAY (0x10) /* Bit 4: Command OK if unit attention condition */ |
|
#define USBMSC_FLAGS_RETAINSENSEDATA (0x20) /* Bit 5: Do not clear sense data */ |
|
|
|
/* Descriptors **************************************************************/ |
|
|
|
/* Big enough to hold our biggest descriptor */ |
|
|
|
#define USBMSC_MXDESCLEN (64) |
|
|
|
/* String language */ |
|
|
|
#define USBMSC_STR_LANGUAGE (0x0409) /* en-us */ |
|
|
|
/* Descriptor strings */ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
# define USBMSC_MANUFACTURERSTRID (1) |
|
# define USBMSC_PRODUCTSTRID (2) |
|
# define USBMSC_SERIALSTRID (3) |
|
# define USBMSC_CONFIGSTRID (4) |
|
# define USBMSC_INTERFACESTRID USBMSC_CONFIGSTRID |
|
|
|
# undef CONFIG_USBMSC_STRBASE |
|
# define CONFIG_USBMSC_STRBASE (0) |
|
#else |
|
# define USBMSC_INTERFACESTRID (CONFIG_USBMSC_STRBASE+1) |
|
#endif |
|
|
|
#define USBMSC_LASTSTRID USBMSC_INTERFACESTRID |
|
#define USBMSC_NSTRIDS (USBMSC_LASTSTRID - CONFIG_USBMSC_STRBASE) |
|
|
|
#define USBMSC_NCONFIGS (1) /* Number of configurations supported */ |
|
|
|
/* Configuration Descriptor */ |
|
|
|
#define USBMSC_NINTERFACES (1) /* Number of interfaces in the configuration */ |
|
#define USBMSC_INTERFACEID (CONFIG_USBMSC_IFNOBASE+0) |
|
#define USBMSC_ALTINTERFACEID (0) |
|
|
|
#define USBMSC_CONFIGIDNONE (0) /* Config ID means to return to address mode */ |
|
#define USBMSC_CONFIGID (1) /* The only supported configuration ID */ |
|
|
|
/* Interface description */ |
|
|
|
#define USBMSC_NENDPOINTS (2) /* Number of endpoints in the interface */ |
|
|
|
/* Endpoint configuration */ |
|
|
|
#define USBMSC_EPOUTBULK_ADDR (CONFIG_USBMSC_EPBULKOUT) |
|
#define USBMSC_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK) |
|
|
|
#define USBMSC_EPINBULK_ADDR (USB_DIR_IN|CONFIG_USBMSC_EPBULKIN) |
|
#define USBMSC_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) |
|
|
|
#define USBMSC_HSBULKMAXPACKET (512) |
|
#define USBMSC_HSBULKMXPKTSHIFT (9) |
|
#define USBMSC_HSBULKMXPKTMASK (0x000001ff) |
|
#define USBMSC_FSBULKMAXPACKET (64) |
|
#define USBMSC_FSBULKMXPKTSHIFT (6) |
|
#define USBMSC_FSBULKMXPKTMASK (0x0000003f) |
|
|
|
/* Macros for dual speed vs. full speed only operation */ |
|
|
|
#ifdef CONFIG_USBDEV_DUALSPEED |
|
# define USBMSC_EPBULKINDESC(hs) \ |
|
usbmsc_getepdesc((hs) ? USBMSC_EPHSBULKIN : USBMSC_EPFSBULKIN) |
|
# define USBMSC_EPBULKOUTDESC(hs) \ |
|
usbmsc_getepdesc((hs) ? USBMSC_EPHSBULKOUT : USBMSC_EPFSBULKOUT) |
|
# define USBMSC_BULKMAXPACKET(hs) \ |
|
((hs) ? USBMSC_HSBULKMAXPACKET : USBMSC_FSBULKMAXPACKET) |
|
# define USBMSC_BULKMXPKTSHIFT(d) \ |
|
(((d)->speed==USB_SPEED_HIGH) ? USBMSC_HSBULKMXPKTSHIFT : USBMSC_FSBULKMXPKTSHIFT) |
|
# define USBMSC_BULKMXPKTMASK(d) \ |
|
(((d)->speed==USB_SPEED_HIGH) ? USBMSC_HSBULKMXPKTMASK : USBMSC_FSBULKMXPKTMASK) |
|
#else |
|
# define USBMSC_EPBULKINDESC(d) usbmsc_getepdesc(USBMSC_EPFSBULKIN) |
|
# define USBMSC_EPBULKOUTDESC(d) usbmsc_getepdesc(USBMSC_EPFSBULKOUT) |
|
# define USBMSC_BULKMAXPACKET(hs) USBMSC_FSBULKMAXPACKET |
|
# define USBMSC_BULKMXPKTSHIFT(d) USBMSC_FSBULKMXPKTSHIFT |
|
# define USBMSC_BULKMXPKTMASK(d) USBMSC_FSBULKMXPKTMASK |
|
#endif |
|
|
|
/* Configuration descriptor size */ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
|
|
/* Number of individual descriptors in the configuration descriptor: |
|
* (1) Configuration descriptor + (1) interface descriptor + (2) interface |
|
* descriptors. |
|
*/ |
|
|
|
# define USBMSC_CFGGROUP_SIZE (4) |
|
|
|
/* The size of the config descriptor: (9 + 9 + 2*7) = 32 */ |
|
|
|
# define SIZEOF_USBMSC_CFGDESC \ |
|
(USB_SIZEOF_CFGDESC + USB_SIZEOF_IFDESC + USBMSC_NENDPOINTS * USB_SIZEOF_EPDESC) |
|
|
|
#else |
|
|
|
/* Number of individual descriptors in the configuration descriptor: |
|
* (1) interface descriptor + (2) interface descriptors. |
|
*/ |
|
|
|
# define USBMSC_CFGGROUP_SIZE (3) |
|
|
|
/* The size of the config descriptor: (9 + 2*7) = 23 */ |
|
|
|
# define SIZEOF_USBMSC_CFGDESC \ |
|
(USB_SIZEOF_IFDESC + USBMSC_NENDPOINTS * USB_SIZEOF_EPDESC) |
|
|
|
#endif |
|
|
|
/* Block driver helpers *****************************************************/ |
|
|
|
#define USBMSC_DRVR_READ(l,b,s,n) ((l)->inode->u.i_bops->read((l)->inode,b,s,n)) |
|
#define USBMSC_DRVR_WRITE(l,b,s,n) ((l)->inode->u.i_bops->write((l)->inode,b,s,n)) |
|
#define USBMSC_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 |
|
****************************************************************************/ |
|
/* Endpoint descriptors */ |
|
|
|
enum usbmsc_epdesc_e |
|
{ |
|
USBMSC_EPFSBULKOUT = 0, /* Full speed bulk OUT endpoint descriptor */ |
|
USBMSC_EPFSBULKIN /* Full speed bulk IN endpoint descriptor */ |
|
#ifdef CONFIG_USBDEV_DUALSPEED |
|
, |
|
USBMSC_EPHSBULKOUT, /* High speed bulk OUT endpoint descriptor */ |
|
USBMSC_EPHSBULKIN /* High speed bulk IN endpoint descriptor */ |
|
#endif |
|
}; |
|
|
|
/* Container to support a list of requests */ |
|
|
|
struct usbmsc_req_s |
|
{ |
|
FAR struct usbmsc_req_s *flink; /* Implements a singly linked list */ |
|
FAR struct usbdev_req_s *req; /* The contained request */ |
|
}; |
|
|
|
/* This structure describes one LUN: */ |
|
|
|
struct usbmsc_lun_s |
|
{ |
|
struct inode *inode; /* Inode structure of open'ed block driver */ |
|
uint8_t readonly:1; /* Media is read-only */ |
|
uint8_t locked:1; /* Media removal is prevented */ |
|
uint16_t sectorsize; /* The size of one sector */ |
|
uint32_t sd; /* Sense data */ |
|
uint32_t sdinfo; /* Sense data information */ |
|
uint32_t 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 usbmsc_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 uint8_t thstate; /* State of the worker thread */ |
|
volatile uint16_t theventset; /* Set of pending events signaled to worker thread */ |
|
volatile uint8_t thvalue; /* Value passed with the event (must persist) */ |
|
|
|
/* Storage class configuration and state */ |
|
|
|
uint8_t nluns:4; /* Number of LUNs */ |
|
uint8_t config; /* Configuration number */ |
|
|
|
/* 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 command processing */ |
|
|
|
struct usbmsc_lun_s *lun; /* Currently selected LUN */ |
|
struct usbmsc_lun_s *luntab; /* Allocated table of all LUNs */ |
|
uint8_t cdb[USBMSC_MAXCDBLEN]; /* Command data (cdb[]) from CBW */ |
|
uint8_t phaseerror:1; /* Need to send phase sensing status */ |
|
uint8_t shortpacket:1; /* Host transmission stopped unexpectedly */ |
|
uint8_t cbwdir:2; /* Direction from CBW. See USBMSC_FLAGS_DIR* definitions */ |
|
uint8_t cdblen; /* Length of cdb[] from CBW */ |
|
uint8_t cbwlun; /* LUN from the CBW */ |
|
uint16_t nsectbytes; /* Bytes buffered in iobuffer[] */ |
|
uint16_t nreqbytes; /* Bytes buffered in head write requests */ |
|
uint16_t iosize; /* Size of iobuffer[] */ |
|
uint32_t cbwlen; /* Length of data from CBW */ |
|
uint32_t cbwtag; /* Tag from the CBW */ |
|
union |
|
{ |
|
uint32_t xfrlen; /* Read/Write: Sectors remaining to be transferred */ |
|
uint32_t alloclen; /* Other device-to-host: Host allocation length */ |
|
} u; |
|
uint32_t sector; /* Current sector (relative to lun->startsector) */ |
|
uint32_t residue; /* Untransferred amount reported in the CSW */ |
|
uint8_t *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 usbmsc_req_s wrreqs[CONFIG_USBMSC_NWRREQS]; |
|
struct usbmsc_req_s rdreqs[CONFIG_USBMSC_NRDREQS]; |
|
}; |
|
|
|
/**************************************************************************** |
|
* Public Data |
|
****************************************************************************/ |
|
|
|
#undef EXTERN |
|
#if defined(__cplusplus) |
|
# define EXTERN extern "C" |
|
extern "C" |
|
{ |
|
#else |
|
# define EXTERN extern |
|
#endif |
|
|
|
/* String *******************************************************************/ |
|
|
|
/* Mass storage class vendor/product/serial number strings */ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
EXTERN const char g_mscvendorstr[]; |
|
EXTERN const char g_mscproductstr[]; |
|
EXTERN const char g_mscserialstr[]; |
|
|
|
/* If we are using a composite device, then vendor/product/serial number strings |
|
* are provided by the composite device logic. |
|
*/ |
|
|
|
#else |
|
EXTERN const char g_compvendorstr[]; |
|
EXTERN const char g_compproductstr[]; |
|
EXTERN const char g_compserialstr[]; |
|
|
|
#define g_mscvendorstr g_compvendorstr |
|
#define g_mscproductstr g_compproductstr |
|
#define g_mscserialstr g_compserialstr |
|
#endif |
|
/************************************************************************************ |
|
* Public Function Prototypes |
|
************************************************************************************/ |
|
|
|
/************************************************************************************ |
|
* Name: usbmsc_mkstrdesc |
|
* |
|
* Description: |
|
* Construct a string descriptor |
|
* |
|
************************************************************************************/ |
|
|
|
struct usb_strdesc_s; |
|
int usbmsc_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); |
|
|
|
/************************************************************************************ |
|
* Name: usbmsc_getepdesc |
|
* |
|
* Description: |
|
* Return a pointer to the raw device descriptor |
|
* |
|
************************************************************************************/ |
|
|
|
#ifndef CONFIG_USBMSC_COMPOSITE |
|
FAR const struct usb_devdesc_s *usbmsc_getdevdesc(void); |
|
#endif |
|
|
|
/************************************************************************************ |
|
* Name: usbmsc_getepdesc |
|
* |
|
* Description: |
|
* Return a pointer to the raw endpoint descriptor (used for configuring endpoints) |
|
* |
|
************************************************************************************/ |
|
|
|
struct usb_epdesc_s; |
|
FAR const struct usb_epdesc_s *usbmsc_getepdesc(enum usbmsc_epdesc_e epid); |
|
|
|
/************************************************************************************ |
|
* Name: usbmsc_mkcfgdesc |
|
* |
|
* Description: |
|
* Construct the configuration descriptor |
|
* |
|
************************************************************************************/ |
|
|
|
#ifdef CONFIG_USBDEV_DUALSPEED |
|
int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type); |
|
#else |
|
int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf); |
|
#endif |
|
|
|
/************************************************************************************ |
|
* Name: usbmsc_getqualdesc |
|
* |
|
* Description: |
|
* Return a pointer to the raw qual descriptor |
|
* |
|
************************************************************************************/ |
|
|
|
#if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) |
|
FAR const struct usb_qualdesc_s *usbmsc_getqualdesc(void); |
|
#endif |
|
|
|
/**************************************************************************** |
|
* Name: usbmsc_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 *usbmsc_workerthread(void *arg); |
|
|
|
/**************************************************************************** |
|
* Name: usbmsc_setconfig |
|
* |
|
* Description: |
|
* Set the device configuration by allocating and configuring endpoints and |
|
* by allocating and queue read and write requests. |
|
* |
|
****************************************************************************/ |
|
|
|
EXTERN int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config); |
|
|
|
/**************************************************************************** |
|
* Name: usbmsc_resetconfig |
|
* |
|
* Description: |
|
* Mark the device as not configured and disable all endpoints. |
|
* |
|
****************************************************************************/ |
|
|
|
EXTERN void usbmsc_resetconfig(FAR struct usbmsc_dev_s *priv); |
|
|
|
/**************************************************************************** |
|
* Name: usbmsc_wrcomplete |
|
* |
|
* Description: |
|
* Handle completion of write request. This function probably executes |
|
* in the context of an interrupt handler. |
|
* |
|
****************************************************************************/ |
|
|
|
EXTERN void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, |
|
FAR struct usbdev_req_s *req); |
|
|
|
/**************************************************************************** |
|
* Name: usbmsc_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 usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, |
|
FAR struct usbdev_req_s *req); |
|
|
|
/**************************************************************************** |
|
* Name: usbmsc_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. USBMSC_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 usbmsc_deferredresponse(FAR struct usbmsc_dev_s *priv, bool failed); |
|
|
|
#undef EXTERN |
|
#if defined(__cplusplus) |
|
} |
|
#endif |
|
|
|
#endif /* #define __DRIVERS_USBDEV_USBMSC_H */
|
|
|