* drivers/usbdev/usbmsc.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __DRIVERS_USBDEV_USBMSC_H
#define __DRIVERS_USBDEV_USBMSC_H
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/param.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/fs/fs.h>
#include <nuttx/queue.h>
#include <nuttx/mutex.h>
#include <nuttx/spinlock.h>
#include <nuttx/semaphore.h>
#include <nuttx/usb/storage.h>
#include <nuttx/usb/usbdev.h>
* Pre-processor Definitions
****************************************************************************/
* 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 (0)
#endif
* 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
#ifndef CONFIG_USBMSC_NWRREQS
# define CONFIG_USBMSC_NWRREQS 4
#endif
#ifndef CONFIG_USBMSC_NRDREQS
# define CONFIG_USBMSC_NRDREQS 4
#endif
#ifndef CONFIG_USBMSC_COMPOSITE
# ifndef CONFIG_USBMSC_EPBULKOUT
# warning "EPBULKOUT not defined in the configuration"
# define CONFIG_USBMSC_EPBULKOUT 2
# endif
#endif
#ifndef CONFIG_USBMSC_COMPOSITE
# ifndef CONFIG_USBMSC_EPBULKIN
# warning "EPBULKIN not defined in the configuration"
# define CONFIG_USBMSC_EPBULKIN 3
# endif
#endif
#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
#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"
#ifndef CONFIG_USBMSC_SCSI_PRIO
# define CONFIG_USBMSC_SCSI_PRIO 128
#endif
#ifndef CONFIG_USBMSC_SCSI_STACKSIZE
# define CONFIG_USBMSC_SCSI_STACKSIZE 2048
#endif
#ifdef CONFIG_USBDEV_SELFPOWERED
# define USBMSC_SELFPOWERED USB_CONFIG_ATTR_SELFPOWER
#else
# define USBMSC_SELFPOWERED (0)
#endif
#ifdef CONFIG_USBDEV_REMOTEWAKEUP
# define USBMSC_REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP
#else
# define USBMSC_REMOTEWAKEUP (0)
#endif
#ifndef CONFIG_USBDEV_MAXPOWER
# define CONFIG_USBDEV_MAXPOWER 100
#endif
#define USBMSC_STATE_NOTSTARTED (0)
#define USBMSC_STATE_STARTED (1)
#define USBMSC_STATE_IDLE (2)
#define USBMSC_STATE_CMDPARSE (3)
#define USBMSC_STATE_CMDREAD (4)
#define USBMSC_STATE_CMDWRITE (5)
#define USBMSC_STATE_CMDFINISH (6)
#define USBMSC_STATE_CMDSTATUS (7)
#define USBMSC_STATE_TERMINATED (8)
#define USBMSC_EVENT_NOEVENTS (0)
#define USBMSC_EVENT_READY (1 << 0)
#define USBMSC_EVENT_RDCOMPLETE (1 << 1)
#define USBMSC_EVENT_WRCOMPLETE (1 << 2)
#define USBMSC_EVENT_TERMINATEREQUEST (1 << 3)
#define USBMSC_EVENT_DISCONNECT (1 << 4)
#define USBMSC_EVENT_RESET (1 << 5)
#define USBMSC_EVENT_CFGCHANGE (1 << 6)
#define USBMSC_EVENT_IFCHANGE (1 << 7)
#define USBMSC_EVENT_ABORTBULKOUT (1 << 8)
#define USBMSC_FLAGS_DIRMASK (0x03)
#define USBMSC_FLAGS_DIRNONE (0x00)
#define USBMSC_FLAGS_DIRHOST2DEVICE (0x01)
#define USBMSC_FLAGS_DIRDEVICE2HOST (0x02)
#define USBMSC_FLAGS_BLOCKXFR (0x04)
#define USBMSC_FLAGS_LUNNOTNEEDED (0x08)
#define USBMSC_FLAGS_UACOKAY (0x10)
#define USBMSC_FLAGS_RETAINSENSEDATA (0x20)
#define USBMSC_MXDESCLEN (64)
#define USBMSC_MAXSTRLEN (USBMSC_MXDESCLEN-2)
#define USBMSC_STR_LANGUAGE (0x0409)
#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_INTERFACEID (CONFIG_USBMSC_IFNOBASE + 0)
#define USBMSC_ALTINTERFACEID (0)
#define USBMSC_CONFIGIDNONE (0)
#define USBMSC_MKEPBULKOUT(devDesc) ((devDesc)->epno[USBMSC_EP_BULKOUT_IDX])
#define USBMSC_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK)
#define USBMSC_MKEPBULKIN(devDesc) (USB_DIR_IN | (devDesc)->epno[USBMSC_EP_BULKIN_IDX])
#define USBMSC_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK)
#define USBMSC_SSBULKMAXSTREAM (0)
#define USBMSC_SSBULKMAXBURST (0)
#define USBMSC_SSBULKMAXPACKET (1024)
#define USBMSC_SSBULKMXPKTSHIFT (10)
#define USBMSC_SSBULKMXPKTMASK (0x000003ff)
#define USBMSC_HSBULKMAXPACKET (512)
#define USBMSC_HSBULKMXPKTSHIFT (9)
#define USBMSC_HSBULKMXPKTMASK (0x000001ff)
#define USBMSC_FSBULKMAXPACKET (64)
#define USBMSC_FSBULKMXPKTSHIFT (6)
#define USBMSC_FSBULKMXPKTMASK (0x0000003f)
#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE)
# define SIZEOF_USBMSC_CFGDESC \
(USB_SIZEOF_IFDESC + USBMSC_NENDPOINTS * USB_SIZEOF_EPDESC + \
USBMSC_NENDPOINTS * USB_SIZEOF_SS_EPCOMPDESC)
#else
# define SIZEOF_USBMSC_CFGDESC \
(USB_SIZEOF_IFDESC + USBMSC_NENDPOINTS * USB_SIZEOF_EPDESC)
#endif
#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))
* Public Types
****************************************************************************/
enum usbmsc_epdesc_e
{
USBMSC_EPBULKOUT = 0,
USBMSC_EPBULKIN
};
struct usbmsc_req_s
{
FAR struct usbmsc_req_s *flink;
FAR struct usbdev_req_s *req;
};
struct usbmsc_lun_s
{
FAR struct inode *inode;
uint8_t readonly:1;
uint8_t locked:1;
uint16_t sectorsize;
uint32_t sd;
uint32_t sdinfo;
uint32_t uad;
off_t startsector;
size_t nsectors;
};
struct usbmsc_dev_s
{
FAR struct usbdev_s *usbdev;
pid_t thpid;
sem_t thsynch;
spinlock_t spinlock;
mutex_t thlock;
sem_t thwaitsem;
volatile bool thwaiting;
volatile uint8_t thstate;
volatile uint16_t theventset;
volatile uint8_t thvalue;
uint8_t nluns:4;
uint8_t config;
FAR struct usbdev_ep_s *epbulkin;
FAR struct usbdev_ep_s *epbulkout;
FAR struct usbdev_req_s *ctrlreq;
struct usbmsc_lun_s *lun;
struct usbmsc_lun_s *luntab;
uint8_t cdb[USBMSC_MAXCDBLEN];
uint8_t phaseerror:1;
uint8_t shortpacket:1;
uint8_t cbwdir:2;
uint8_t cdblen;
uint8_t cbwlun;
uint16_t nsectbytes;
uint16_t nreqbytes;
uint16_t iosize;
uint32_t cbwlen;
uint32_t cbwtag;
union
{
uint32_t xfrlen;
uint32_t alloclen;
} u;
uint32_t sector;
uint32_t residue;
uint8_t *iobuffer;
struct sq_queue_s wrreqlist;
struct sq_queue_s rdreqlist;
struct usbdev_devinfo_s devinfo;
* 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
#ifndef CONFIG_USBMSC_COMPOSITE
EXTERN const char g_mscvendorstr[];
EXTERN const char g_mscproductstr[];
#ifndef CONFIG_BOARD_USBDEV_SERIALSTR
EXTERN const char g_mscserialstr[];
#endif
* strings are provided by the composite device logic.
*/
#else
EXTERN const char g_compvendorstr[];
EXTERN const char g_compproductstr[];
#ifndef CONFIG_BOARD_USBDEV_SERIALSTR
EXTERN const char g_compserialstr[];
#endif
#define g_mscvendorstr g_compvendorstr
#define g_mscproductstr g_compproductstr
#ifndef CONFIG_BOARD_USBDEV_SERIALSTR
#define g_mscserialstr g_compserialstr
#endif
#endif
* started
*/
EXTERN FAR struct usbmsc_dev_s *g_usbmsc_handoff;
* Public Function Prototypes
****************************************************************************/
* Name: usbmsc_scsi_signal
*
* Description:
* Signal the SCSI worker thread that SCSI events need service.
*
****************************************************************************/
void usbmsc_scsi_signal(FAR struct usbmsc_dev_s *priv);
* Name: usbmsc_synch_signal
*
* Description:
* ACK controlling tasks request for synchronization.
*
****************************************************************************/
#define usbmsc_synch_signal(priv) nxsem_post(&priv->thsynch)
* 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_getdevdesc
*
* 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_copy_epdesc
*
* Description:
* Copies the requested Endpoint Description into the buffer given.
* Returns the number of Bytes filled in ( sizeof(struct usb_epdesc_s) ).
*
****************************************************************************/
int usbmsc_copy_epdesc(enum usbmsc_epdesc_e epid,
FAR struct usb_epdesc_s *epdesc,
FAR struct usbdev_devinfo_s *devinfo,
uint8_t speed);
* Name: usbmsc_mkcfgdesc
*
* Description:
* Construct the configuration descriptor
*
****************************************************************************/
int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf,
FAR struct usbdev_devinfo_s *devinfo,
uint8_t speed, uint8_t type);
* 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_scsi_main
*
* Description:
* This is the main function of the USB storage worker thread. It loops
* until USB-related events occur, then processes those events accordingly
*
****************************************************************************/
int usbmsc_scsi_main(int argc, FAR char *argv[]);
* Name: usbmsc_setconfig
*
* Description:
* Set the device configuration by allocating and configuring endpoints and
* by allocating and queue read and write requests.
*
****************************************************************************/
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.
*
****************************************************************************/
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.
*
****************************************************************************/
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"
*
****************************************************************************/
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 because 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 response 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
*
****************************************************************************/
void usbmsc_deferredresponse(FAR struct usbmsc_dev_s *priv, bool failed);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif