| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412 |
- //*****************************************************************************
- //
- // usbdmsc.c - USB mass storage device class driver.
- //
- // Copyright (c) 2009-2010 Texas Instruments Incorporated. All rights reserved.
- // Software License Agreement
- //
- // Texas Instruments (TI) is supplying this software for use solely and
- // exclusively on TI's microcontroller products. The software is owned by
- // TI and/or its suppliers, and is protected under applicable copyright
- // laws. You may not combine this software with "viral" open-source
- // software in order to form a larger program.
- //
- // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
- // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
- // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
- // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
- // DAMAGES, FOR ANY REASON WHATSOEVER.
- //
- // This is part of revision 6288 of the Stellaris USB Library.
- //
- //*****************************************************************************
- //#include "inc/hw_memmap.h"
- #include "hw_usb.h"
- #include "hw_types.h"
- #include "debug.h"
- #include "interrupt.h"
- #include "usb.h"
- #include "cppi41dma.h"
- #include "usblib.h"
- #include "usbmsc.h"
- #include "usbdevice.h"
- #include "usbdmsc.h"
- #include "usblibpriv.h"
- #include <string.h>
- #include <delay.h>
- #include <perf.h>
- //*****************************************************************************
- //
- //! \addtogroup msc_device_class_api
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // These defines control the sizes of USB transfers for data and commands.
- //
- //*****************************************************************************
- #define MAX_TRANSFER_SIZE USB_PACKET_LENGTH
- #define COMMAND_BUFFER_SIZE 64
- //*****************************************************************************
- //
- // DMA configuration Parameters
- //
- //*****************************************************************************
- #define DMA_TX_MAX_CHUNK_SIZE (MAX_TRANSFER_SIZE*8) // 512 blocks size, 8 blocks
- #define DMA_RX_MAX_CHUNK_SIZE MAX_TRANSFER_SIZE // 1 block
- //*****************************************************************************
- //
- // The subset of endpoint status flags that we consider to be reception
- // errors. These are passed to the client via USB_EVENT_ERROR if seen.
- //
- //*****************************************************************************
- #define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
- USBERR_DEV_RX_OVERRUN | \
- USBERR_DEV_RX_FIFO_FULL)
- //*****************************************************************************
- //
- // These are fields that are used by the USB descriptors for the Mass Storage
- // Class.
- //
- //*****************************************************************************
- #define USB_MSC_SUBCLASS_SCSI 0x6
- #define USB_MSC_PROTO_BULKONLY 0x50
- //*****************************************************************************
- //
- // Endpoints to use for each of the required endpoints in the driver.
- //
- //*****************************************************************************
- #define DATA_IN_ENDPOINT USB_EP_1
- #define DATA_IN_DMA_CHANNEL USB_EP_1// UDMA_CHANNEL_USBEP1TX
- #define DATA_OUT_ENDPOINT USB_EP_1
- #define DATA_OUT_DMA_CHANNEL USB_EP_1//UDMA_CHANNEL_USBEP1RX
- //*****************************************************************************
- //
- // Maximum packet size for the bulk endpoints is 64 bytes.
- //
- //*****************************************************************************
- #define DATA_IN_EP_MAX_SIZE MAX_TRANSFER_SIZE
- #define DATA_OUT_EP_MAX_SIZE MAX_TRANSFER_SIZE
- //*****************************************************************************
- //
- // The local buffer used to read in commands and process them.
- //
- //*****************************************************************************
- unsigned char g_pucCommand[COMMAND_BUFFER_SIZE];
- unsigned char intStatus = 0;
- unsigned int g_bytesRead = 0;
- unsigned int g_bytesWritten = 0;
- //*****************************************************************************
- //
- // The current transfer state is held in these variables.
- //
- //*****************************************************************************
- static tMSCCSW g_sSCSICSW={0,0,0,0};
- unsigned short gDMAflag =0;
- //*****************************************************************************
- //
- // The current state for the SCSI commands that are being handled and are
- // stored in the tMSCInstance.ucSCSIState structure member.
- //
- //*****************************************************************************
- //
- // No command in process.
- //
- #define STATE_SCSI_IDLE 0x00
- //
- // Sending and reading logical blocks.
- //
- #define STATE_SCSI_SEND_BLOCKS 0x01
- //
- // Receiving and writing logical blocks.
- //
- #define STATE_SCSI_RECEIVE_BLOCKS 0x02
- //
- // Send the status once the previous transfer is complete.
- //
- #define STATE_SCSI_SEND_STATUS 0x03
- //
- // Status was prepared to be sent and now waiting for it to have gone out.
- //
- #define STATE_SCSI_SENT_STATUS 0x04
- #define STATE_SCSI_COMMAND_RCVD 0x05
- //*****************************************************************************
- //
- // USB instance Object
- //
- //*****************************************************************************
- extern tUSBInstanceObject g_USBInstance[];
- //*****************************************************************************
- //
- // Device Descriptor. This is stored in RAM to allow several fields to be
- // changed at runtime based on the client's requirements.
- //
- //*****************************************************************************
- static const unsigned char g_pMSCDeviceDescriptor[] =
- {
- 18, // Size of this structure.
- USB_DTYPE_DEVICE, // Type of this structure.
- USBShort(0x200), // USB version 1.1 (if we say 2.0, hosts assume
- // high-speed - see USB 2.0 spec 9.2.6.6)
- 0, // USB Device Class (spec 5.1.1)
- 0, // USB Device Sub-class (spec 5.1.1)
- 0, // USB Device protocol (spec 5.1.1)
- 64, // Maximum packet size for default pipe.
- USBShort(0), // Vendor ID (filled in during USBDCDCInit).
- USBShort(0), // Product ID (filled in during USBDCDCInit).
- USBShort(0x100), // Device Version BCD.
- 1, // Manufacturer string identifier.
- 2, // Product string identifier.
- 3, // Product serial number.
- 1 // Number of configurations.
- };
- //*****************************************************************************
- //
- // Mass storage device configuration descriptor.
- //
- // It is vital that the configuration descriptor bConfigurationValue field
- // (byte 6) is 1 for the first configuration and increments by 1 for each
- // additional configuration defined here. This relationship is assumed in the
- // device stack for simplicity even though the USB 2.0 specification imposes
- // no such restriction on the bConfigurationValue values.
- //
- // Note that this structure is deliberately located in RAM since we need to
- // be able to patch some values in it based on client requirements.
- //
- //*****************************************************************************
- static unsigned char g_pMSCDescriptor[] =
- {
- //
- // Configuration descriptor header.
- //
- 9, // Size of the configuration descriptor.
- USB_DTYPE_CONFIGURATION, // Type of this descriptor.
- USBShort(32), // The total size of this full structure.
- 1, // The number of interfaces in this
- // configuration.
- 1, // The unique value for this configuration.
- 0, // The string identifier that describes this
- // configuration.
- USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
- 250, // The maximum power in 2mA increments.
- };
- //*****************************************************************************
- //
- // The remainder of the configuration descriptor is stored in flash since we
- // don't need to modify anything in it at runtime.
- //
- //*****************************************************************************
- const unsigned char g_pMSCInterface[] =
- {
- //
- // Vendor-specific Interface Descriptor.
- //
- 9, // Size of the interface descriptor.
- USB_DTYPE_INTERFACE, // Type of this descriptor.
- 0, // The index for this interface.
- 0, // The alternate setting for this interface.
- 2, // The number of endpoints used by this
- // interface.
- USB_CLASS_MASS_STORAGE, // The interface class
- USB_MSC_SUBCLASS_SCSI, // The interface sub-class.
- USB_MSC_PROTO_BULKONLY, // The interface protocol for the sub-class
- // specified above.
- 0, // The string index for this interface.
- //
- // Endpoint Descriptor
- //
- 7, // The size of the endpoint descriptor.
- USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
- USB_EP_DESC_IN | USB_EP_TO_INDEX(DATA_IN_ENDPOINT),
- USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
- USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
- 0, // The polling interval for this endpoint.
- //
- // Endpoint Descriptor
- //
- 7, // The size of the endpoint descriptor.
- USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
- USB_EP_DESC_OUT | USB_EP_TO_INDEX(DATA_OUT_ENDPOINT),
- USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
- USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
- 0, // The polling interval for this endpoint.
- };
- //*****************************************************************************
- //
- // The mass storage configuration descriptor is defined as two sections,
- // one containing just the 9 byte USB configuration descriptor and the other
- // containing everything else that is sent to the host along with it.
- //
- //*****************************************************************************
- const tConfigSection g_sMSCConfigSection =
- {
- sizeof(g_pMSCDescriptor),
- g_pMSCDescriptor
- };
- const tConfigSection g_sMSCInterfaceSection =
- {
- sizeof(g_pMSCInterface),
- g_pMSCInterface
- };
- //*****************************************************************************
- //
- // This array lists all the sections that must be concatenated to make a
- // single, complete bulk device configuration descriptor.
- //
- //*****************************************************************************
- const tConfigSection *g_psMSCSections[] =
- {
- &g_sMSCConfigSection,
- &g_sMSCInterfaceSection
- };
- #define NUM_MSC_SECTIONS (sizeof(g_psMSCSections) / sizeof(tConfigSection *))
- //*****************************************************************************
- //
- // The header for the single configuration we support. This is the root of
- // the data structure that defines all the bits and pieces that are pulled
- // together to generate the configuration descriptor.
- //
- //*****************************************************************************
- const tConfigHeader g_sMSCConfigHeader =
- {
- NUM_MSC_SECTIONS,
- g_psMSCSections
- };
- //*****************************************************************************
- //
- // Configuration Descriptor.
- //
- //*****************************************************************************
- const tConfigHeader * const g_pMSCConfigDescriptors[] =
- {
- &g_sMSCConfigHeader
- };
- //*****************************************************************************
- //
- // Various internal handlers needed by this class.
- //
- //*****************************************************************************
- static void HandleDisconnect(void *pvInstance);
- static void ConfigChangeHandler(void *pvInstance, unsigned int ulValue,
- unsigned int ulIndex);
- static void HandleEndpoints(void *pvInstance, unsigned int ulStatus,
- unsigned int ulIndex);
- static void HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex);
- static void USBDSCSISendStatus(const tUSBDMSCDevice *psDevice,
- unsigned int ulIndex);
- unsigned int USBDSCSICommand(const tUSBDMSCDevice *psDevice,
- tMSCCBW *pSCSICBW, unsigned int ulIndex);
- static void HandleDevice(void *pvInstance, unsigned int ulRequest,
- void *pvRequestData);
- //*****************************************************************************
- //
- // The FIFO configuration for USB mass storage class device.
- //
- //*****************************************************************************
- const tFIFOConfig g_sUSBMSCFIFOConfig =
- {
- //
- // IN endpoints.
- //
- {
- { 1, false, USB_EP_DEV_IN | USB_EP_DMA_MODE_1 | USB_EP_AUTO_SET },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN },
- { 1, false, USB_EP_DEV_IN }
- },
- //
- // OUT endpoints.
- //
- {
- { 1, false, USB_EP_DEV_OUT | USB_EP_DMA_MODE_1 | USB_EP_AUTO_CLEAR },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT },
- { 1, false, USB_EP_DEV_OUT }
- },
- };
- //*****************************************************************************
- //
- // The device information structure for the USB MSC device.
- //
- //*****************************************************************************
- tDeviceInfo g_sMSCDeviceInfo =
- {
- //
- // Device event handler callbacks.
- //
- {
- //
- // GetDescriptor
- //
- 0,
- //
- // RequestHandler
- //
- HandleRequests,
- //
- // InterfaceChange
- //
- 0,
- //
- // ConfigChange
- //
- ConfigChangeHandler,
- //
- // DataReceived
- //
- 0,
- //
- // DataSentCallback
- //
- 0,
- //
- // ResetHandler
- //
- 0,
- //
- // SuspendHandler
- //
- 0,
- //
- // ResumeHandler
- //
- 0,
- //
- // DisconnectHandler
- //
- HandleDisconnect,
- //
- // EndpointHandler
- //
- HandleEndpoints,
- //
- // Device handler
- //
- HandleDevice
- },
- g_pMSCDeviceDescriptor,
- g_pMSCConfigDescriptors,
- 0,
- 0,
- &g_sUSBDefaultFIFOConfig
- //&g_sUSBMSCFIFOConfig
- };
- //*****************************************************************************
- //
- //! This function is used by an application if it can detect insertion or
- //! removal of the media.
- //!
- //! \param pvInstance is the mass storage device instance that had a media
- //! change.
- //! \param eMediaStatus is the updated status for the media.
- //!
- //! This function should be called by an application when it detects a change
- //! in the status of the media in use by the USB mass storage class. The
- //! \e eMediaStatus parameter will indicate the new status of the media and
- //! can also indicate that the application has no knowledge of the media state.
- //!
- //! There are currently the three following values for the \e eMediaStatus
- //! parameter:
- //! - USBDMSC_MEDIA_PRESENT indicates that the media is present or has been
- //! added.
- //! - USBDMSC_MEDIA_NOTPRESENT indicates that the media is not present or was
- //! removed.
- //! - USBDMSC_MEDIA_UNKNOWN indicates that the application has no knowledge of
- //! the media state and the USB mass storage class.
- //!
- //! It will be left up to the application to call this function whenever it
- //! detects a change or simply call it once with USBDMSC_MEDIA_UNKNOWN and
- //! allow the mass storage class to infer the state from the remaining device
- //! APIs.
- //!
- //! \note It is recommended that the application use this function to inform
- //! the mass storage class of media state changes as it will lead to a more
- //! responsive system.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBDMSCMediaChange(void *pvInstance, tUSBDMSCMediaStatus eMediaStatus)
- {
- const tUSBDMSCDevice *psDevice;
- //
- // Create a device instance pointer.
- //
- psDevice = pvInstance;
- //
- // Save the current media status.
- //
- psDevice->psPrivateData->eMediaStatus = eMediaStatus;
- }
- //*****************************************************************************
- //
- // This function is called to handle the interrupts on the Bulk endpoints for
- // the mass storage class.
- //
- //*****************************************************************************
- static void
- HandleEndpoints(void *pvInstance, unsigned int ulStatus, unsigned int ulIndex)
- {
- tUSBDMSCDevice *psDevice;
- tMSCInstance *psInst;
- tMSCCBW *pSCSICBW;
- unsigned int pendReg = 0;
-
- #ifdef DMA_MODE
- unsigned int rxBuffer;
- unsigned int txBuffer;
- unsigned int dmaStatus = 0;
- unsigned int nBlocks;
- #else
- unsigned int ulMaxsize = MAX_TRANSFER_SIZE;
- unsigned int ulSize;
- #endif
- ASSERT(pvInstance != 0);
- //
- // Determine if the serial device is in single or composite mode because
- // the meaning of ulIndex is different in both cases.
- //
- psDevice = pvInstance;
- //
- // Initialize the workspace in the passed instance structure.
- //
- psInst = psDevice->psPrivateData;
- #ifdef DMA_MODE
- // Get the Starvation interrupt status
- CppiDmaGetINTD0Status(g_USBInstance[ulIndex].uiUSBInstance);
-
- // Get the DMA Interrupt status
- pendReg = CppiDmaGetPendStatus(g_USBInstance[ulIndex].uiUSBInstance);
- #endif
-
- //
- // Handler for the bulk IN data endpoint.
- //
- if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucINEndpoint))
- || (pendReg & CPDMA_TX_PENDING))
- {
- #ifdef DMA_MODE
- if(pendReg & CPDMA_TX_PENDING)
- {
- dmaStatus = dmaTxCompletion(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- }
- #endif
-
- switch(psInst->ucSCSIState)
- {
- //
- // Handle the case where we are sending out data due to a read
- // command.
- //
- case STATE_SCSI_SEND_BLOCKS:
- {
-
- #ifndef DMA_MODE
- //
- // Decrement the number of bytes left to send.
- //
- psInst->ulBytesToTransfer -= MAX_TRANSFER_SIZE;
- //
- //Add the bytes transfered
- //
- g_bytesRead = g_bytesRead + MAX_TRANSFER_SIZE;
-
- #else //
- // Check if DMA is completed, Check the remaining bytes
- //
- if(dmaStatus == DMA_TX_COMPLETED)
- {
- if(psInst->ulBytesToTransfer > DMA_TX_MAX_CHUNK_SIZE)
- {
- psInst->ulBytesToTransfer -= DMA_TX_MAX_CHUNK_SIZE;
- g_bytesRead = g_bytesRead + DMA_TX_MAX_CHUNK_SIZE;
- }
- else
- {
- g_bytesRead = g_bytesRead +psInst->ulBytesToTransfer;
- psInst->ulBytesToTransfer = 0;
- }
- }
- #endif
- //
- // If we are done then move on to the status phase.
- //
- if(psInst->ulBytesToTransfer == 0)
- {
-
- //
- // Set the status so that it can be sent when this
- // response has has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = 0;
- g_bytesRead = 0;
-
- //
- // Send back the status once this transfer is complete.
- //
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
-
- #ifdef DMA_MODE
- //
- //Disable the RX and TX DMA before sending the CSW
- //DMA is not used to send the CSW.
- //
- disableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- disableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- #endif
-
- USBDSCSISendStatus(psDevice, ulIndex);
- if(psDevice->pfnEventCallback)
- {
- psDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE, 0,
- 0);
- }
- //
- // The transfer is complete so don't read anymore data.
- //
- break;
- }
-
- #ifndef DMA_MODE
- if(g_bytesRead == DEVICE_BLOCK_SIZE)
- {
- //
- // Move on to the next Logical Block.
- //
- psInst->ulCurrentLBA++;
- g_bytesRead = 0;
- }
- #endif
- //
- // Read the new data and send it out.
- //
- #ifdef DMA_MODE
- if(dmaStatus == DMA_TX_COMPLETED)
- {
- //
- //If current DMA is operation is completed, check how may byets remaining
- //to send
- //
- g_bytesRead = 0;
- psInst->ulCurrentLBA += (DMA_TX_MAX_CHUNK_SIZE / MAX_TRANSFER_SIZE);
- nBlocks = psInst->ulBytesToTransfer / MAX_TRANSFER_SIZE;
- if(nBlocks > (DMA_TX_MAX_CHUNK_SIZE / MAX_TRANSFER_SIZE))
- nBlocks = (DMA_TX_MAX_CHUNK_SIZE / MAX_TRANSFER_SIZE);
-
- //Allocate buffer for the remaining data
- txBuffer = (unsigned int)cppiDmaAllocnBuffer(nBlocks);
- if(NULL!=(void *)txBuffer)
- {
- //
- //Read the blocks and send it out
- //
- psDevice->sMediaFunctions.BlockRead(psInst->pvMedia,
- (unsigned char *)txBuffer, psInst->ulCurrentLBA, nBlocks);
-
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, (unsigned char *)txBuffer,
- (nBlocks * DEVICE_BLOCK_SIZE), psInst->ucINEndpoint);
- }
- }
- #else
- //
- // Read the new data and send it out.
- //
- psDevice->sMediaFunctions.BlockRead(psInst->pvMedia,
- (unsigned char *)psInst->pulBuffer,
- psInst->ulCurrentLBA, 1);
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint,
- (unsigned char *)psInst->pulBuffer, MAX_TRANSFER_SIZE);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- #endif
-
- break;
- }
- //
- // Handle sending status.
- //
- case STATE_SCSI_SEND_STATUS:
- {
- #ifdef DMA_MODE
- //
- //Disable the RX and TX DMA before sending the CSW
- //DMA is not used to send the CSW.
- //
- disableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- disableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- #endif
-
- //
- // Indicate success and no extra data coming.
- //
- USBDSCSISendStatus(psDevice, ulIndex);
- break;
- }
- //
- // Handle completing sending status.
- //
- case STATE_SCSI_SENT_STATUS:
- {
- #ifdef DMA_MODE
- disableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- disableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- #endif
-
- psInst->ucSCSIState = STATE_SCSI_IDLE;
- #ifdef PROFILE_USB_MSC_READ
- if(fReadEnabled)
- {
- g_USBPerfInfo[ulPerfInfoCounter++].ulTimeInTicks = PerfTimerStop();
- fReadEnabled = 0;
- if (ulPerfInfoCounter==5000)
- ulPerfInfoCounter=4999;
- }
- #endif//PROFILE_USB_MSC_READ
- #ifdef PROFILE_USB_MSC_WRITE
- if(fWriteEnabled)
- {
- g_USBPerfInfo[ulPerfInfoCounter++].ulTimeInTicks = PerfTimerStop();
- fWriteEnabled = 0;
- if (ulPerfInfoCounter==5000)
- ulPerfInfoCounter=4999;
- }
- #endif//PROFILE_USB_MSC_WRITE
- break;
- }
- //
- // These cases should not occur as the being in the IDLE state due
- // to an IN interrupt is invalid.
- //
- case STATE_SCSI_IDLE:
- default:
- {
- break;
- }
- }
- }
- //
- // Handler for the bulk OUT data endpoint.
- //
- if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucOUTEndpoint))
- || (pendReg & CPDMA_RX_PENDING))
- {
-
- switch(psInst->ucSCSIState)
- {
- //
- // Receiving and writing bytes to the storage device.
- //
- case STATE_SCSI_RECEIVE_BLOCKS:
- {
- #ifndef DMA_MODE
- //
- //Get the data from the FIFO and send Ack
- //
- USBEndpointDataGet(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- (unsigned char *)psInst->pulBuffer, &ulMaxsize);
- USBDevEndpointDataAck(psInst->ulUSBBase, psInst->ucOUTEndpoint, false);
- //
- //Write the data to the block media
- //
- psDevice->sMediaFunctions.BlockWrite(psInst->pvMedia,
- (unsigned char *)psInst->pulBuffer,
- psInst->ulCurrentLBA, 1);
-
- #endif
-
- #ifdef DMA_MODE
- //
- //During receive operation, we need to wait in loop till we recive all data
- //
- while(CppiDmaGetPendStatus(g_USBInstance[ulIndex].uiUSBInstance) & CPDMA_RX_PENDING)
- {
- //Decrement the bytes recived
- psInst->ulBytesToTransfer -= DMA_RX_MAX_CHUNK_SIZE;
- g_bytesWritten = g_bytesWritten + DMA_RX_MAX_CHUNK_SIZE;
-
- #else
- psInst->ulBytesToTransfer -= MAX_TRANSFER_SIZE;
- g_bytesWritten = g_bytesWritten + MAX_TRANSFER_SIZE;
- #endif
- #ifdef DMA_MODE
- //
- //Get the data from the RX completeion queue
- //
- rxBuffer = dmaRxCompletion(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- //
- //Write the data to the block media
- //
- psDevice->sMediaFunctions.BlockWrite(psInst->pvMedia,
- (unsigned char *)rxBuffer, psInst->ulCurrentLBA, 1);
- //
- //Load another BD to the receive queue
- //
- doDmaRxTransfer(g_USBInstance[ulIndex].uiUSBInstance, MAX_TRANSFER_SIZE,
- (unsigned char *)rxBuffer, psInst->ucOUTEndpoint);
-
- #endif
- if(g_bytesWritten == DEVICE_BLOCK_SIZE)
- {
- g_bytesWritten = 0;
- psInst->ulCurrentLBA++;
- }
-
- #ifdef DMA_MODE
- }
-
- cppiDmaHandleError(g_USBInstance[ulIndex].uiUSBInstance);
- #endif
- //
- // Check if all bytes have been received.
- //
- if(psInst->ulBytesToTransfer == 0)
- {
- //
- // Set the status so that it can be sent when this response
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = 0;
- g_bytesWritten = 0;
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
-
- #ifdef DMA_MODE
- //
- //Disable the RX and TX DMA before sending the CSW
- //DMA is not used to send the CSW.
- //
- disableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- disableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #endif
- //
- // Indicate success and no extra data coming.
- //
- USBDSCSISendStatus(psDevice, ulIndex);
- }
- break;
- }
- //
- // If there is an OUT transfer in idle state then it was a new
- // command.
- //
- case STATE_SCSI_IDLE:
- {
- //
- // Attempt to handle the new command.
- //
- #ifdef DMA_MODE
-
- //
- //Enable the RX DMA as it is disabled during last CSW
- //
- enableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- while(!(CppiDmaGetPendStatus(g_USBInstance[ulIndex].uiUSBInstance) & CPDMA_RX_PENDING));
- rxBuffer = dmaRxCompletion(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- pSCSICBW = (tMSCCBW *)rxBuffer;
-
- //
- //Recceive the command
- //
- doDmaRxTransfer(g_USBInstance[ulIndex].uiUSBInstance, MAX_TRANSFER_SIZE,
- (unsigned char *)rxBuffer, psInst->ucOUTEndpoint);
-
- #else
- ulSize = COMMAND_BUFFER_SIZE;
- //
- // Receive the command.
- //
- USBEndpointDataGet(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- g_pucCommand, &ulSize);
- pSCSICBW = (tMSCCBW *)g_pucCommand;
- //
- // Acknowledge the OUT data packet.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- false);
- #endif
-
- //
- // If this is a valid CBW then handle it.
- //
- if(pSCSICBW->dCBWSignature == CBW_SIGNATURE)
- {
- g_sSCSICSW.dCSWSignature = CSW_SIGNATURE;
- g_sSCSICSW.dCSWTag = pSCSICBW->dCBWTag;
- g_sSCSICSW.dCSWDataResidue = 0;
- g_sSCSICSW.bCSWStatus = 0;
- USBDSCSICommand(psDevice, pSCSICBW, ulIndex);
-
- }
- else
- {
- //
- // Just return to the idle state since we are now out of
- // sync with the host. This should not happen, but this
- // should allow the device to synchronize with the host
- // controller.
- //
- psInst->ucSCSIState = STATE_SCSI_IDLE;
-
- }
- break;
- }
- default:
- {
- break;
- }
- }
-
- }
-
- }
- //*****************************************************************************
- //
- // Device instance specific handler.
- //
- //*****************************************************************************
- static void
- HandleDevice(void *pvInstance, unsigned int ulRequest, void *pvRequestData)
- {
- tMSCInstance *psInst;
- unsigned char *pucData;
- //
- // Create the serial instance data.
- //
- psInst = ((tUSBDMSCDevice *)pvInstance)->psPrivateData;
- //
- // Create the char array used by the events supported by the USB CDC
- // serial class.
- //
- pucData = (unsigned char *)pvRequestData;
- switch(ulRequest)
- {
- //
- // This was an interface change event.
- //
- case USB_EVENT_COMP_IFACE_CHANGE:
- {
- psInst->ucInterface = pucData[1];
- break;
- }
- //
- // This was an endpoint change event.
- //
- case USB_EVENT_COMP_EP_CHANGE:
- {
- //
- // Determine if this is an IN or OUT endpoint that has changed.
- //
- if(pucData[0] & USB_EP_DESC_IN)
- {
- psInst->ucINEndpoint = INDEX_TO_USB_EP((pucData[1] & 0x7f));
- }
- else
- {
- //
- // Extract the new endpoint number.
- //
- psInst->ucOUTEndpoint = INDEX_TO_USB_EP(pucData[1] & 0x7f);
- }
- break;
- }
- default:
- {
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the device is
- // disconnected from the host.
- //
- //*****************************************************************************
- static void
- HandleDisconnect(void *pvInstance)
- {
- const tUSBDMSCDevice *psDevice;
- ASSERT(pvInstance != 0);
- memset(&g_sSCSICSW, 0, sizeof(g_sSCSICSW));
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDMSCDevice *)pvInstance;
- psDevice->psPrivateData->ucSCSIState = STATE_SCSI_IDLE;
- psDevice->psPrivateData->ulBytesToTransfer = 0;
- psDevice->psPrivateData->ulCurrentLBA = 0;
- //
- // Close the drive requested.
- //
- if(psDevice->psPrivateData->pvMedia != 0)
- {
- psDevice->psPrivateData->pvMedia = 0;
- psDevice->sMediaFunctions.Close(0);
- }
- //
- // If we have a control callback, let the client know we are open for
- // business.
- //
- if(psDevice->pfnEventCallback)
- {
- //
- // Pass the connected event to the client.
- //
- psDevice->pfnEventCallback(pvInstance, USB_EVENT_DISCONNECTED, 0, 0);
- }
- //UARTprintf("------------------------------------------------------------\n");
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the device
- // configuration changes.
- //
- //*****************************************************************************
- static void
- ConfigChangeHandler(void *pvInstance, unsigned int ulValue,
- unsigned int ulIndex)
- {
- tMSCInstance *psInst;
- const tUSBDMSCDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDMSCDevice *)pvInstance;
- //
- // Create the serial instance data.
- //
- psInst = psDevice->psPrivateData;
- //
- // Insure that DMA is disable whenever the configuration is set.
- //
- USBEndpointDMADisable(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_EP_DEV_IN);
- USBEndpointDMADisable(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint, USB_EP_DEV_OUT);
- //
- // If we have a control callback, let the client know we are open for
- // business.
- //
- if(psDevice->pfnEventCallback)
- {
- //
- // Pass the connected event to the client.
- //
- psDevice->pfnEventCallback(pvInstance, USB_EVENT_CONNECTED, 0, 0);
- }
- }
- //*****************************************************************************
- //
- //! This function should be called once for the mass storage class device to
- //! initialized basic operation and prepare for enumeration.
- //!
- //! \param ulIndex is the index of the USB controller to initialize for
- //! mass storage class device operation.
- //! \param psDevice points to a structure containing parameters customizing
- //! the operation of the mass storage device.
- //!
- //! In order for an application to initialize the USB device mass storage
- //! class, it must first call this function with the a valid mass storage
- //! device class structure in the \e psDevice parameter. This allows this
- //! function to initialize the USB controller and device code to be prepared to
- //! enumerate and function as a USB mass storage device.
- //!
- //! This function returns a void pointer that must be passed in to all other
- //! APIs used by the mass storage class.
- //!
- //! See the documentation on the tUSBDMSCDevice structure for more information
- //! on how to properly fill the structure members.
- //!
- //! \return Returns 0 on failure or a non-zero void pointer on success.
- //
- //*****************************************************************************
- void *
- USBDMSCInit(unsigned int ulIndex, const tUSBDMSCDevice *psDevice)
- {
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psDevice);
- ASSERT(psDevice->ppStringDescriptors);
- ASSERT(psDevice->psPrivateData);
- USBDMSCCompositeInit(ulIndex, psDevice);
-
- //
- // All is well so now pass the descriptors to the lower layer and put
- // the bulk device on the bus.
- //
- USBDCDInit(ulIndex, psDevice->psPrivateData->psDevInfo);
-
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return ((void *)psDevice);
- }
- //*****************************************************************************
- //
- //! This function should be called once for the mass storage class device to
- //! initialized basic operation and prepare for enumeration.
- //!
- //! \param ulIndex is the index of the USB controller to initialize for
- //! mass storage class device operation.
- //! \param psDevice points to a structure containing parameters customizing
- //! the operation of the mass storage device.
- //!
- //! An application wishing to make use of a composite
- //! USB bulk communication channel for MSC class needs to call this function.
- //! This function is used for initializing an instance related information of the
- //! MSC device.
- //!
- //! This function returns a void pointer that must be passed in to all other
- //! APIs used by the mass storage class.
- //!
- //! See the documentation on the tUSBDMSCDevice structure for more information
- //! on how to properly fill the structure members.
- //!
- //! \return Returns 0 on failure or a non-zero void pointer on success.
- //
- //*****************************************************************************
- void *
- USBDMSCCompositeInit(unsigned int ulIndex, const tUSBDMSCDevice *psDevice)
- {
- tMSCInstance *psInst;
- tDeviceDescriptor *psDevDesc;
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psDevice);
- ASSERT(psDevice->ppStringDescriptors);
- ASSERT(psDevice->psPrivateData);
- if(ulIndex == 0)
- {
- g_USBInstance[ulIndex].uiUSBInstance = ulIndex;
- g_USBInstance[ulIndex].uiBaseAddr = USB0_BASE;
- g_USBInstance[ulIndex].uiSubBaseAddr = USB_0_OTGBASE;
- g_USBInstance[ulIndex].uiInterruptNum = SYS_INT_USB0;
- g_USBInstance[ulIndex].uiSubInterruptNum = SYS_INT_USBSSINT;
- g_USBInstance[ulIndex].uiPHYConfigRegAddr = CFGCHIP2_USBPHYCTRL;
- }
- #if (USB_NUM_INSTANCE == 2)
- else if(ulIndex == 1)
- {
- g_USBInstance[ulIndex].uiUSBInstance = ulIndex;
- g_USBInstance[ulIndex].uiBaseAddr = USB1_BASE;
- g_USBInstance[ulIndex].uiSubBaseAddr = USB_1_OTGBASE;
- g_USBInstance[ulIndex].uiInterruptNum = SYS_INT_USB1;
- g_USBInstance[ulIndex].uiSubInterruptNum = SYS_INT_USBSSINT;
- g_USBInstance[ulIndex].uiPHYConfigRegAddr = CFGCHIP2_USB1PHYCTRL;
- }
- #endif
- //
- // Initialize the workspace in the passed instance structure.
- //
- psInst = psDevice->psPrivateData;
- psInst->psConfDescriptor = (tConfigDescriptor *)g_pMSCDescriptor;
- psInst->psDevInfo = &g_sMSCDeviceInfo;
- psInst->ulUSBBase = g_USBInstance[ulIndex].uiBaseAddr;
- psInst->bConnected = false;
- psInst->eMediaStatus = USBDMSC_MEDIA_UNKNOWN;
- //
- // Set the initial interface and endpoints.
- //
- psInst->ucInterface = 0;
- psInst->ucOUTEndpoint = DATA_OUT_ENDPOINT;
- psInst->ucOUTDMA = DATA_OUT_DMA_CHANNEL;
- psInst->ucINEndpoint = DATA_IN_ENDPOINT;
- psInst->ucINDMA = DATA_IN_DMA_CHANNEL;
- //
- // Set the initial SCSI state to idle.
- //
- psInst->ucSCSIState = STATE_SCSI_IDLE;
- //
- // Fix up the device descriptor with the client-supplied values.
- //
- psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
- psDevDesc->idVendor = psDevice->usVID;
- psDevDesc->idProduct = psDevice->usPID;
- //
- // Fix up the configuration descriptor with client-supplied values.
- //
- psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
- psInst->psConfDescriptor->bMaxPower =
- (unsigned char)(psDevice->usMaxPowermA / 2);
- //
- // Plug in the client's string stable to the device information
- // structure.
- //
- psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
- psInst->psDevInfo->ulNumStringDescriptors
- = psDevice->ulNumStringDescriptors;
- psInst->psDevInfo->pvInstance = (void *)psDevice;
- //
- // Open the drive requested.
- //
- psInst->pvMedia = psDevice->sMediaFunctions.Open(0);
- if(psInst->pvMedia == 0)
- {
- //
- // There is no media currently present.
- //
- psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
- psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
- }
- else
- {
- //
- // Media is now ready for use.
- //
- psInst->ucSenseKey = SCSI_RS_KEY_UNIT_ATTN;
- psInst->usAddSenseCode = SCSI_RS_MED_NOTRDY2RDY;
- }
- //
- // Enable Clocking to the USB controller.
- //
- USBModuleClkEnable(ulIndex, g_USBInstance[ulIndex].uiBaseAddr);
-
- //
- // Turn on USB Phy clock.
- //
- UsbPhyOn(ulIndex);
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return((void *)psDevice);
- }
- //*****************************************************************************
- //
- //! Shuts down the mass storage device.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDMSCInit() or USBDMSCInitComposite().
- //!
- //! This function terminates mass storage operation for the instance supplied
- //! and removes the device from the USB bus. Following this call, the
- //! \e psDevice instance may not me used in any other call to the mass storage
- //! device other than USBDMSCInit() or USBDMSCInitComposite().
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBDMSCTerm(void *pvInstance)
- {
- const tUSBDMSCDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create a device instance pointer.
- //
- psDevice = pvInstance;
- //
- // If the media was opened the close it out.
- //
- if(psDevice->psPrivateData->pvMedia == 0)
- {
- psDevice->psPrivateData->pvMedia = 0;
- psDevice->sMediaFunctions.Close(0);
- }
- //
- // Cleanly exit device mode.
- //
- USBDCDTerm(0);
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever a non-standard
- // request is received.
- //
- // \param pvInstance is instance data for this request.
- // \param pUSBRequest points to the request received.
- //
- // This call parses the provided request structure to determine the command.
- // The only mass storage command supported over endpoint 0 is the Get Max LUN
- // command.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex)
- {
- //
- // This class only support a single LUN.
- //
- static const unsigned char ucMaxLun = 0;
- ASSERT(pvInstance != 0);
- //
- // Determine the type of request.
- //
- switch(pUSBRequest->bRequest)
- {
- //
- // A Set Report request is received from the host when it sends an
- // Output report via endpoint 0.
- //
- case USBREQ_GET_MAX_LUN:
- {
- //
- // Send our response to the host.
- //
- USBDCDSendDataEP0(0, (unsigned char *)&ucMaxLun, 1);
- break;
- }
- //
- // This request was not recognized so stall.
- //
- default:
- {
- USBDCDStallEP0(ulIndex);
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Inquiry command when it is received
- // from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIInquiry(const tUSBDMSCDevice *psDevice, unsigned int ulIndex)
- {
- int iIdx;
- tMSCInstance *psInst;
- #ifdef DMA_MODE
- unsigned char *cmdBuffer;
- #endif
- //
- // Create the serial instance data.
- //
- psInst = psDevice->psPrivateData;
- //
- // Direct Access device, Removable storage and SCSI 1 responses.
- //
- #ifdef _TMS320C6X
- _mem4(&g_pucCommand[0]) = SCSI_INQ_PDT_SBC | (SCSI_INQ_RMB << 8);
- #else
- *(unsigned int *)&g_pucCommand[0] = SCSI_INQ_PDT_SBC | (SCSI_INQ_RMB << 8);
- #endif
- //
- // Additional Length is fixed at 31 bytes.
- //
- #ifdef _TMS320C6X
- _mem4(&g_pucCommand[4]) = 31;
- #else
- *(unsigned int *)&g_pucCommand[4] = 31;
- #endif
- //
- // Copy the Vendor string.
- //
- for(iIdx = 0; iIdx < 8; iIdx++)
- {
- g_pucCommand[iIdx + 8] = psDevice->pucVendor[iIdx];
- }
- //
- // Copy the Product string.
- //
- for(iIdx = 0; iIdx < 16; iIdx++)
- {
- g_pucCommand[iIdx + 16] = psDevice->pucProduct[iIdx];
- }
- //
- // Copy the Version string.
- //
- for(iIdx = 0; iIdx < 4; iIdx++)
- {
- g_pucCommand[iIdx + 32] = psDevice->pucVersion[iIdx];
- }
-
- #ifdef DMA_MODE
-
- //
- //Allocate buffer for the command
- //
- cmdBuffer = (unsigned char*)cppiDmaAllocBuffer();
- memcpy(cmdBuffer, g_pucCommand, 36);
-
- //
- //send command response
- //
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, cmdBuffer, 36, psInst->ucINEndpoint);
- enableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #else
- //
- // Send the SCSI Inquiry Response.
- //
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, g_pucCommand, 36);
- //
- // Send the data to the host.
- //
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- #endif
-
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = 0;
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Read Capacities command when it is
- // received from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIReadCapacities(const tUSBDMSCDevice *psDevice, unsigned int ulIndex)
- {
- unsigned int ulBlocks;
- tMSCInstance *psInst;
- #ifdef DMA_MODE
- unsigned char *cmdBuffer;
- #endif
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- if(psInst->pvMedia != 0)
- {
- ulBlocks = psDevice->sMediaFunctions.NumBlocks(psInst->pvMedia);
- #ifdef _TMS320C6X
- _mem4(&g_pucCommand[0]) = 0x08000000;
- #else
- *(unsigned int *)&g_pucCommand[0] = 0x08000000;
- #endif
- //
- // Fill in the number of blocks, the bytes endianness must be changed.
- //
- g_pucCommand[4] = ulBlocks >> 24;
- g_pucCommand[5] = 0xff & (ulBlocks >> 16);
- g_pucCommand[6] = 0xff & (ulBlocks >> 8);
- g_pucCommand[7] = 0xff & (ulBlocks);
- //
- // Current media capacity
- //
- g_pucCommand[8] = 0x02;
- //
- // Fill in the block size, which is fixed at DEVICE_BLOCK_SIZE.
- //
- g_pucCommand[9] = 0xff & (DEVICE_BLOCK_SIZE >> 16);
- g_pucCommand[10] = 0xff & (DEVICE_BLOCK_SIZE >> 8);
- g_pucCommand[11] = 0xff & DEVICE_BLOCK_SIZE;
- //
- // Send out the 12 bytes that are in this response.
- //
- #ifdef DMA_MODE
- //
- //Allocate buffer for the command
- //
- cmdBuffer = (unsigned char*)cppiDmaAllocBuffer();
- ASSERT(NULL!=(void*)cmdBuffer);
- memcpy(cmdBuffer, g_pucCommand, 12);
-
- //
- //Send the command response
- //
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, cmdBuffer, 12, psInst->ucINEndpoint);
- enableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #else
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, g_pucCommand, 12);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- #endif
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = 0;
- }
- else
- {
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 1;
- g_sSCSICSW.dCSWDataResidue = 0;
- //
- // Stall the IN endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_EP_DEV_IN);
- //
- // Mark the sense code as valid and indicate that these is no media
- // present.
- //
- psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
- psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
- psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
- }
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Read Capacity command when it is
- // received from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIReadCapacity(const tUSBDMSCDevice *psDevice, unsigned int ulIndex)
- {
- unsigned int ulBlocks;
- tMSCInstance *psInst;
- #ifdef DMA_MODE
- unsigned char *cmdBuffer;
- #endif
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- ulBlocks = psDevice->sMediaFunctions.NumBlocks(psInst->pvMedia);
- //
- // Only decrement if any blocks were found.
- //
- if(ulBlocks != 0)
- {
- //
- // One less than the maximum number is the last addressable
- // block.
- //
- ulBlocks--;
- }
- if(psInst->pvMedia != 0)
- {
- //
- // Fill in the number of blocks, the bytes endianness must be changed.
- //
- g_pucCommand[0] = 0xff & (ulBlocks >> 24);
- g_pucCommand[1] = 0xff & (ulBlocks >> 16);
- g_pucCommand[2] = 0xff & (ulBlocks >> 8);
- g_pucCommand[3] = 0xff & (ulBlocks);
-
- g_pucCommand[4] = 0;
- //
- // Fill in the block size, which is fixed at DEVICE_BLOCK_SIZE.
- //
- g_pucCommand[5] = 0xff & (DEVICE_BLOCK_SIZE >> 16);
- g_pucCommand[6] = 0xff & (DEVICE_BLOCK_SIZE >> 8);
- g_pucCommand[7] = 0xff & DEVICE_BLOCK_SIZE;
- //
- // Send the SCSI Inquiry Response.
- //
- #ifdef DMA_MODE
- //
- //Allocate buffer for the command
- //
- cmdBuffer = (unsigned char*)cppiDmaAllocBuffer();
- ASSERT(NULL!=(void*)cmdBuffer);
- memcpy(cmdBuffer, g_pucCommand, 8);
-
- //
- //Send the command response
- //
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, cmdBuffer, 8, psInst->ucINEndpoint);
- enableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #else
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, g_pucCommand, 8);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- #endif
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = 0;
- }
- else
- {
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 1;
- g_sSCSICSW.dCSWDataResidue = 0;
- //
- // Stall the IN endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_EP_DEV_IN);
- //
- // Mark the sense code as valid and indicate that these is no media
- // present.
- //
- psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
- psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
- psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
- }
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Request Sense command when it is
- // received from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIRequestSense(const tUSBDMSCDevice *psDevice, unsigned int ulIndex)
- {
- tMSCInstance *psInst;
- #ifdef DMA_MODE
- unsigned char *cmdBuffer;
- #endif
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- //
- // The request sense response.
- //
- g_pucCommand[0] = psInst->ucErrorCode;
- g_pucCommand[1] = 0;
- g_pucCommand[2] = psInst->ucSenseKey;
- g_pucCommand[3] = 0;
- g_pucCommand[4] = 0;
- g_pucCommand[5] = 0;
- g_pucCommand[6] = 0;
- //*(unsigned long *)&g_pucCommand[3] = 0;
- //
- // There are 10 more bytes of data.
- //
- g_pucCommand[7] = 10;
- // *(unsigned long *)&g_pucCommand[8] = 0;
- g_pucCommand[8] = 0;
- g_pucCommand[9] = 0;
- g_pucCommand[10] = 0;
- g_pucCommand[11] = 0;
- //
- // Transition from not ready to ready.
- //
- g_pucCommand[12] = 0xff & (psInst->usAddSenseCode >> 8);
- g_pucCommand[12] = 0xff & (psInst->usAddSenseCode);
- // *(unsigned short *)&g_pucCommand[12] = psInst->usAddSenseCode;
- // *(unsigned long *)&g_pucCommand[14] = 0;
- g_pucCommand[14] = 0;
- g_pucCommand[15] = 0;
- g_pucCommand[16] = 0;
- g_pucCommand[17] = 0;
- //
- // Send the SCSI Inquiry Response.
- //
- #ifdef DMA_MODE
- //
- //Allocate buffer for the command
- //
- cmdBuffer = (unsigned char*)cppiDmaAllocBuffer();
- memcpy(cmdBuffer, g_pucCommand, 18);
- //
- //send the command response
- //
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, cmdBuffer, 18, psInst->ucINEndpoint);
- enableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #else
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, g_pucCommand, 18);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- #endif
- //
- // Reset the valid flag on errors.
- //
- psInst->ucErrorCode = SCSI_RS_CUR_ERRORS;
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = 0;
- //
- // Move on to the status phase.
- //
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Read 10 command when it is
- // received from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIRead10(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW,
- unsigned int ulIndex)
- {
- tMSCInstance *psInst;
- unsigned int usNumBlocks;
- #ifdef DMA_MODE
- unsigned int txBuffer;
- unsigned int nBlocks;
- #endif
- //
- // Default the number of blocks.
- //
- usNumBlocks = 0;
-
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
-
- if(psInst->pvMedia != 0)
- {
- //
- // Get the logical block from the CBW structure. This switching
- // is required to convert from big to little endian.
- //
- psInst->ulCurrentLBA = (pSCSICBW->CBWCB[2] << 24) |
- (pSCSICBW->CBWCB[3] << 16) |
- (pSCSICBW->CBWCB[4] << 8) |
- (pSCSICBW->CBWCB[5] << 0);
-
- //
- // More bytes to read.
- //
- usNumBlocks = (pSCSICBW->CBWCB[7] << 8) | pSCSICBW->CBWCB[8];
- #ifdef PROFILE_USB_MSC_READ
- g_USBPerfInfo[ulPerfInfoCounter].ulBytesToTransfer = (DEVICE_BLOCK_SIZE * usNumBlocks);
- PerfTimerStart();
- fReadEnabled = 1;
- #endif//PROFILE_USB_MSC_READ
- #ifdef DMA_MODE
- if(usNumBlocks > (DMA_TX_MAX_CHUNK_SIZE / MAX_TRANSFER_SIZE))
- nBlocks = (DMA_TX_MAX_CHUNK_SIZE / MAX_TRANSFER_SIZE);
- else
- nBlocks = usNumBlocks;
-
- //
- //Allocate buffer for TX data
- //
- txBuffer=(unsigned int)cppiDmaAllocnBuffer(nBlocks);
-
- //
- // Read the next logical block from the storage device.
- //
- if(NULL!=(void *)txBuffer)
- {
- if(psDevice->sMediaFunctions.BlockRead(psInst->pvMedia,
- ((unsigned char *)txBuffer),
- psInst->ulCurrentLBA, nBlocks) == 0)
- {
- psInst->pvMedia = 0;
- psDevice->sMediaFunctions.Close(0);
- }
- }
- #else
- //
- // Read the next logical block from the storage device.
- //
- if(psDevice->sMediaFunctions.BlockRead(psInst->pvMedia,
- ((unsigned char *)psInst->pulBuffer),
- psInst->ulCurrentLBA, 1) == 0)
- {
- psInst->pvMedia = 0;
- psDevice->sMediaFunctions.Close(0);
- }
- #endif
- }
-
-
- //
- // If there is media present then start transferring the data.
- //
- if(psInst->pvMedia != 0)
- {
-
- //
- // Schedule the remaining bytes to send.
- //
- psInst->ulBytesToTransfer = (DEVICE_BLOCK_SIZE * usNumBlocks);
- #ifdef DMA_MODE
- //
- //Load the DMA queue with the data buffer
- //
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, (unsigned char *)txBuffer,
- (nBlocks *DEVICE_BLOCK_SIZE), psInst->ucINEndpoint);
- //
- //Enable the DMA for TX operation
- //
- enableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #else
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint,
- (unsigned char *)psInst->pulBuffer,
- MAX_TRANSFER_SIZE);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint,
- USB_TRANS_IN);
- #endif
- //
- // Move on and start sending blocks.
- //
- psInst->ucSCSIState = STATE_SCSI_SEND_BLOCKS;
- if(psDevice->pfnEventCallback)
- {
- psDevice->pfnEventCallback(0, USBD_MSC_EVENT_READING, 0, 0);
- }
- }
- else
- {
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 1;
- g_sSCSICSW.dCSWDataResidue = 0;
- //
- // Stall the IN endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_EP_DEV_IN);
- //
- // Mark the sense code as valid and indicate that these is no media
- // present.
- //
- psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
- psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
- psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Read 10 command when it is
- // received from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIWrite10(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW,
- unsigned int ulIndex)
- {
- unsigned short usNumBlocks;
- tMSCInstance *psInst;
-
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- //
- // If there is media present then start transferring the data.
- //
- if(psInst->pvMedia != 0)
- {
- //
- // Get the logical block from the CBW structure. This switching
- // is required to convert from big to little endian.
- //
- psInst->ulCurrentLBA = (pSCSICBW->CBWCB[2] << 24) |
- (pSCSICBW->CBWCB[3] << 16) |
- (pSCSICBW->CBWCB[4] << 8) |
- (pSCSICBW->CBWCB[5] << 0);
- //
- // More bytes to read.
- //
- usNumBlocks = (pSCSICBW->CBWCB[7] << 8) | pSCSICBW->CBWCB[8];
- psInst->ulBytesToTransfer = DEVICE_BLOCK_SIZE * usNumBlocks;
- //UARTprintf("#Blocks: %30d, #Bytes: %30d \n", usNumBlocks, psInst->ulBytesToTransfer);
- #ifdef PROFILE_USB_MSC_WRITE
- g_USBPerfInfo[ulPerfInfoCounter].ulBytesToTransfer = psInst->ulBytesToTransfer;
- PerfTimerStart();
- fWriteEnabled = 1;
- #endif//PROFILE_USB_MSC_WRITE
-
- //
- // Start sending logical blocks, these are always multiples of
- // DEVICE_BLOCK_SIZE bytes.
- //
- psInst->ucSCSIState = STATE_SCSI_RECEIVE_BLOCKS;
-
- #ifdef DMA_MODE
- enableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- #endif
-
- //
- // Notify the application of the write event.
- //
- if(psDevice->pfnEventCallback)
- {
- psDevice->pfnEventCallback(0, USBD_MSC_EVENT_WRITING, 0, 0);
- }
-
-
- }
- else
- {
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 1;
- g_sSCSICSW.dCSWDataResidue = 0;
- //
- // Stall the IN endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint, USB_EP_DEV_OUT);
- //
- // Mark the sense code as valid and indicate that these is no media
- // present.
- //
- psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
- psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
- psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- }
- //*****************************************************************************
- //
- // This function is used to handle the SCSI Mode Sense 6 command when it is
- // received from the host.
- //
- //*****************************************************************************
- static void
- USBDSCSIModeSense6(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW,
- unsigned int ulIndex)
- {
- tMSCInstance *psInst;
- #ifdef DMA_MODE
- unsigned char *cmdBuffer;
- #endif
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- //
- // If there is media present send the response.
- //
- if(psInst->pvMedia != 0)
- {
- //
- // Three extra bytes in this response.
- //
- g_pucCommand[0] = 3;
- g_pucCommand[1] = 0;
- g_pucCommand[2] = 0;
- g_pucCommand[3] = 0;
- //
- // Manually send the response back to the host.
- //
- #ifdef DMA_MODE
- //
- //Allocate buffer for the command
- //
- cmdBuffer = (unsigned char*)cppiDmaAllocBuffer();
- memcpy(cmdBuffer, g_pucCommand, 4);
- //
- //Send the command response
- //
- doDmaTxTransfer(g_USBInstance[ulIndex].uiUSBInstance, cmdBuffer, 4, psInst->ucINEndpoint);
- enableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- #else
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, g_pucCommand, 4);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- #endif
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = pSCSICBW->dCBWDataTransferLength - 4;
- }
- else
- {
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 1;
- g_sSCSICSW.dCSWDataResidue = 0;
- //
- // Stall the IN endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_EP_DEV_IN);
- //
- // Mark the sense code as valid and indicate that these is no media
- // present.
- //
- psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
- psInst->ucSenseKey = SCSI_RS_KEY_NOT_READY;
- psInst->usAddSenseCode = SCSI_RS_MED_NOT_PRSNT;
- }
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- //*****************************************************************************
- //
- // This function is used to send out the response data based on the current
- // status of the mass storage class.
- //
- //*****************************************************************************
- static void
- USBDSCSISendStatus(const tUSBDMSCDevice *psDevice, unsigned int ulIndex)
- {
- tMSCInstance *psInst;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- //
- // Respond with the requested status.
- //
-
- USBEndpointDataPut(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint,
- (unsigned char *)&g_sSCSICSW, 13);
- USBEndpointDataSend(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint, USB_TRANS_IN);
- //
- // Move the state to status sent so that the next interrupt will move the
- // statue to idle.
- //
- psInst->ucSCSIState = STATE_SCSI_SENT_STATUS;
- }
- //*****************************************************************************
- //
- // This function is used to handle all SCSI commands.
- //
- //*****************************************************************************
- unsigned int
- USBDSCSICommand(const tUSBDMSCDevice *psDevice, tMSCCBW *pSCSICBW,
- unsigned int ulIndex)
- {
- unsigned int ulRetCode;
- unsigned int ulTransferLength;
- tMSCInstance *psInst;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateData;
- //
- // Initialize the return code.
- //
- ulRetCode = 1;
- //
- // Save the transfer length because it may be overwritten by some calls.
- //
- ulTransferLength = pSCSICBW->dCBWDataTransferLength;
-
- switch(pSCSICBW->CBWCB[0])
- {
- //
- // Respond to the SCSI Inquiry command.
- //
- case SCSI_INQUIRY_CMD:
- {
- USBDSCSIInquiry(psDevice, ulIndex);
- break;
- }
- //
- // Respond to the test unit ready command.
- //
- case SCSI_TEST_UNIT_READY:
- {
- g_sSCSICSW.dCSWDataResidue = 0;
- if(psInst->pvMedia != 0)
- {
- //
- // Set the status to success for now, this could be different
- // if there is no media present.
- //
- g_sSCSICSW.bCSWStatus = 0;
- }
- else
- {
- //
- // Since there was no media, check for media here.
- //
- psInst->pvMedia = psDevice->sMediaFunctions.Open(0);
- //
- // If it is still not present then fail this command.
- //
- if(psInst->pvMedia != 0)
- {
- g_sSCSICSW.bCSWStatus = 0;
- }
- else
- {
- g_sSCSICSW.bCSWStatus = 1;
- }
- }
- break;
- }
- //
- // Handle the Read Capacities command.
- //
- case SCSI_READ_CAPACITIES:
- {
- USBDSCSIReadCapacities(psDevice, ulIndex);
- break;
- }
- //
- // Handle the Read Capacity command.
- //
- case SCSI_READ_CAPACITY:
- {
- USBDSCSIReadCapacity(psDevice, ulIndex);
- break;
- }
- //
- // Handle the Request Sense command.
- //
- case SCSI_REQUEST_SENSE:
- {
- USBDSCSIRequestSense(psDevice, ulIndex);
- break;
- }
- //
- // Handle the Read 10 command.
- //
- case SCSI_READ_10:
- {
- USBDSCSIRead10(psDevice, pSCSICBW, ulIndex);
- break;
- }
- //
- // Handle the Write 10 command.
- //
- case SCSI_WRITE_10:
- {
- USBDSCSIWrite10(psDevice, pSCSICBW, ulIndex);
- break;
- }
- //
- // Handle the Mode Sense 6 command.
- //
- case SCSI_MODE_SENSE_6:
- {
- USBDSCSIModeSense6(psDevice, pSCSICBW, ulIndex);
- break;
- }
- case SCSI_VERIFY_10:
- {
- psInst->ucSCSIState = STATE_SCSI_IDLE;
- g_sSCSICSW.bCSWStatus = 0;
- g_sSCSICSW.dCSWDataResidue = pSCSICBW->dCBWDataTransferLength;
- break;
- }
-
- default:
- {
- psInst->ucSCSIState = STATE_SCSI_IDLE;
- //
- // Set the status so that it can be sent when this response has
- // has be successfully sent.
- //
- g_sSCSICSW.bCSWStatus = 1;
- g_sSCSICSW.dCSWDataResidue = pSCSICBW->dCBWDataTransferLength;
- //
- // If there is data then there is more work to do.
- //
- if(pSCSICBW->dCBWDataTransferLength != 0)
- {
- if(pSCSICBW->bmCBWFlags & CBWFLAGS_DIR_IN)
- {
- //
- // Stall the IN endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucINEndpoint,
- USB_EP_DEV_IN);
- }
- else
- {
- //
- // Stall the OUT endpoint
- //
- USBDevEndpointStall(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint,
- USB_EP_DEV_OUT);
- }
- //
- // Send the status once the stall occurs.
- //
- psInst->ucSCSIState = STATE_SCSI_SEND_STATUS;
- }
- //
- // Set the sense codes.
- //
- psInst->ucErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
- psInst->ucSenseKey = SCSI_RS_KEY_ILGL_RQST;
- psInst->usAddSenseCode = SCSI_RS_PV_INVALID;
- break;
- }
- }
- //
- // If there is no data then send out the current status.
- //
- if(ulTransferLength == 0)
- {
- #ifdef DMA_MODE
- disableCoreTxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucINEndpoint);
- disableCoreRxDMA(g_USBInstance[ulIndex].uiUSBInstance, psInst->ucOUTEndpoint);
- #endif
- USBDSCSISendStatus(psDevice, ulIndex);
- }
- return(ulRetCode);
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|