usb官方例程 zynq xusbps_class_storage.c 已经实现了ddr的虚拟u盘功能,但这个U盘会掉电丢失。
ZYNQ裸机实现 USB MASS STORAGE (usb+sd卡 实现U盘功能)_zynq usb库-CSDN博客
将 zynq xusbps_class_storage.c 里的scsi的相关usb的读写命令从读写内存替换为读写sd卡的接口。
我的sd卡的裸机接口读写失败,代码挂载的是emmc。
xusbps_intr_example.c的代码
/******************************************************************************
*
* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xusbps_intr_example.c
*
* This file contains an example of how to use the USB driver with the USB
* controller in DEVICE mode.
*
*
*<pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ------ -------- ----------------------------------------------------
* 1.00a wgr/nm 10/09/10 First release
* 1.01a nm 03/05/10 Included xpseudo_asm.h instead of xpseudo_asm_gcc.h
* 1.04a nm 02/05/13 Fixed CR# 696550.
* Added template code for Vendor request.
* 1.06a kpc 11/11/13 Fixed CR#759458, cacheInvalidate size should be
* ailgned to ccahe line size.
* 2.1 kpc 04/28/14 Cleanup and removed unused functions
*</pre>
******************************************************************************//***************************** Include Files *********************************/#include "xparameters.h" /* XPAR parameters */
#include "xusbps.h" /* USB controller driver */
#include "xscugic.h"
#include "xusbps_ch9.h" /* Generic Chapter 9 handling code */
#include "xusbps_class_storage.h" /* Storage class handling code */
#include "xil_exception.h"
#include "xpseudo_asm.h"
#include "xreg_cortexa9.h"
#include "xil_cache.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <stdio.h>
#include "xparameters.h"
#include "xsdps.h"
#include "xil_printf.h"
#include "ff.h"XSdPs ps7_EMMC;
XSdPs_Config * EMMC_Config;
u8 WR_Buf[1024];
u8 RD_Buf[1024];
u8 Emmc_ExtCsd[1024];static FATFS SD_Dev; // File System instance
char *SD_Path = "0:/"; // string pointer to the logical drive number
static char FileName[32] = "0:test.txt"; // name of the logu8 WR_Buf[1024] __attribute__ ((aligned(32))); // Buffer should be word aligned (multiple of 4)
u8 RD_Buf[1024] __attribute__ ((aligned(32))); // Buffer should be word aligned (multiple of 4)/************************** Constant Definitions *****************************/
#define MEMORY_SIZE (64 * 1024)
#ifdef __ICCARM__
#pragma data_alignment = 32
u8 Buffer[MEMORY_SIZE];
#pragma data_alignment = 4
#else
u8 Buffer[MEMORY_SIZE] ALIGNMENT_CACHELINE;
#endif/**************************** Type Definitions *******************************//***************** Macros (Inline Functions) Definitions *********************//************************** Function Prototypes ******************************/static int UsbIntrExample(XScuGic *IntcInstancePtr, XUsbPs *UsbInstancePtr,u16 UsbDeviceId, u16 UsbIntrId);static void UsbIntrHandler(void *CallBackRef, u32 Mask);
static void XUsbPs_Ep0EventHandler(void *CallBackRef, u8 EpNum,u8 EventType, void *Data);
static void XUsbPs_Ep1EventHandler(void *CallBackRef, u8 EpNum,u8 EventType, void *Data);
static int UsbSetupIntrSystem(XScuGic *IntcInstancePtr,XUsbPs *UsbInstancePtr, u16 UsbIntrId);
static void UsbDisableIntrSystem(XScuGic *IntcInstancePtr, u16 UsbIntrId);/************************** Variable Definitions *****************************//* The instances to support the device drivers are global such that the* are initialized to zero each time the program runs.*/
static XScuGic IntcInstance; /* The instance of the IRQ Controller */
static XUsbPs UsbInstance; /* The instance of the USB Controller */static volatile int NumIrqs = 0;
static volatile int NumReceivedFrames = 0;/*****************************************************************************/
/**** Main function to call the USB interrupt example.** @param None** @return* - XST_SUCCESS if successful* - XST_FAILURE on error*******************************************************************************/
FIL file;
int SD_init()
{FRESULT result;//-----------------------mount dev-----------------------------------------------result = f_mount(&SD_Dev,SD_Path, 0);if (result != 0) {printf("f_mount failed: %d\n", result);return XST_FAILURE;}return XST_SUCCESS;
}int main(void)
{int Status;#if 1u32 i;u32 Buffer_size=1024;u8 SD_ERROR=0;sleep(3);EMMC_Config= XSdPs_LookupConfig(XPAR_PS7_SD_0_DEVICE_ID);Status = XSdPs_CfgInitialize(&ps7_EMMC, EMMC_Config, EMMC_Config->BaseAddress);if (Status != XST_SUCCESS){print("EMMC Config failed !\n\r");return XST_FAILURE;}Status=XSdPs_MmcCardInitialize(&ps7_EMMC);if (Status != XST_SUCCESS){print("EMMC Config failed !\n\r");return XST_FAILURE;}Status=XSdPs_Change_ClkFreq(&ps7_EMMC,50000000);Status=XSdPs_Select_Card(&ps7_EMMC);Status=XSdPs_SetBlkSize(&ps7_EMMC,XSDPS_BLK_SIZE_512_MASK);Status=XSdPs_Get_Mmc_ExtCsd(&ps7_EMMC,Emmc_ExtCsd);//SD_init();printf("sd init ok\n");for(i=0;i<Buffer_size;i++){WR_Buf[i]=i;}Status = XSdPs_WritePolled(&ps7_EMMC, 0x01, 2, WR_Buf);if (Status!=0){printf("XSdPs_WritePolled failed\n");}else{printf("XSdPs_WritePolled ok\n");}Status = XSdPs_ReadPolled(&ps7_EMMC, 0x01, 2, RD_Buf);if (Status!=0){printf("XSdPs_ReadPolled failed\n");}else{printf("XSdPs_ReadPolled ok\n");}#endif/* Run the USB Interrupt example.*/Status = UsbIntrExample(&IntcInstance, &UsbInstance,XPAR_XUSBPS_0_DEVICE_ID, XPAR_XUSBPS_0_INTR);if (Status != XST_SUCCESS) {return XST_FAILURE;}return XST_SUCCESS;
}/*****************************************************************************/
/**** This function does a minimal DEVICE mode setup on the USB device and driver* as a design example. The purpose of this function is to illustrate how to* set up a USB flash disk emulation system.*** @param IntcInstancePtr is a pointer to the instance of the INTC driver.* @param UsbInstancePtr is a pointer to the instance of USB driver.* @param UsbDeviceId is the Device ID of the USB Controller and is the* XPAR_<USB_instance>_DEVICE_ID value from xparameters.h.* @param UsbIntrId is the Interrupt Id and is typically* XPAR_<INTC_instance>_<USB_instance>_IP2INTC_IRPT_INTR value* from xparameters.h.** @return* - XST_SUCCESS if successful* - XST_FAILURE on error*******************************************************************************/
static int UsbIntrExample(XScuGic *IntcInstancePtr, XUsbPs *UsbInstancePtr,u16 UsbDeviceId, u16 UsbIntrId)
{int Status;u8 *MemPtr = NULL;int ReturnStatus = XST_FAILURE;/* For this example we only configure 2 endpoints:* Endpoint 0 (default control endpoint)* Endpoint 1 (BULK data endpoint)*/const u8 NumEndpoints = 2;XUsbPs_Config *UsbConfigPtr;XUsbPs_DeviceConfig DeviceConfig;/* Initialize the USB driver so that it's ready to use,* specify the controller ID that is generated in xparameters.h*/UsbConfigPtr = XUsbPs_LookupConfig(UsbDeviceId);if (NULL == UsbConfigPtr) {goto out;}/* We are passing the physical base address as the third argument* because the physical and virtual base address are the same in our* example. For systems that support virtual memory, the third* argument needs to be the virtual base address.*/Status = XUsbPs_CfgInitialize(UsbInstancePtr,UsbConfigPtr,UsbConfigPtr->BaseAddress);if (XST_SUCCESS != Status) {goto out;}/* Set up the interrupt subsystem.*/Status = UsbSetupIntrSystem(IntcInstancePtr,UsbInstancePtr,UsbIntrId);if (XST_SUCCESS != Status){goto out;}/* Configuration of the DEVICE side of the controller happens in* multiple stages.** 1) The user configures the desired endpoint configuration using the* XUsbPs_DeviceConfig data structure. This includes the number of* endpoints, the number of Transfer Descriptors for each endpoint* (each endpoint can have a different number of Transfer Descriptors)* and the buffer size for the OUT (receive) endpoints. Each endpoint* can have different buffer sizes.** 2) Request the required size of DMAable memory from the driver using* the XUsbPs_DeviceMemRequired() call.** 3) Allocate the DMAable memory and set up the DMAMemVirt and* DMAMemPhys members in the XUsbPs_DeviceConfig data structure.** 4) Configure the DEVICE side of the controller by calling the* XUsbPs_ConfigureDevice() function.*//** For this example we only configure Endpoint 0 and Endpoint 1.** Bufsize = 0 indicates that there is no buffer allocated for OUT* (receive) endpoint 0. Endpoint 0 is a control endpoint and we only* receive control packets on that endpoint. Control packets are 8* bytes in size and are received into the Queue Head's Setup Buffer.* Therefore, no additional buffer space is needed.*/DeviceConfig.EpCfg[0].Out.Type = XUSBPS_EP_TYPE_CONTROL;DeviceConfig.EpCfg[0].Out.NumBufs = 2;DeviceConfig.EpCfg[0].Out.BufSize = 64;DeviceConfig.EpCfg[0].Out.MaxPacketSize = 64;DeviceConfig.EpCfg[0].In.Type = XUSBPS_EP_TYPE_CONTROL;DeviceConfig.EpCfg[0].In.NumBufs = 2;DeviceConfig.EpCfg[0].In.MaxPacketSize = 64;DeviceConfig.EpCfg[1].Out.Type = XUSBPS_EP_TYPE_BULK;DeviceConfig.EpCfg[1].Out.NumBufs = 16;DeviceConfig.EpCfg[1].Out.BufSize = 512;DeviceConfig.EpCfg[1].Out.MaxPacketSize = 512;DeviceConfig.EpCfg[1].In.Type = XUSBPS_EP_TYPE_BULK;DeviceConfig.EpCfg[1].In.NumBufs = 16;DeviceConfig.EpCfg[1].In.MaxPacketSize = 512;DeviceConfig.NumEndpoints = NumEndpoints;MemPtr = (u8 *)&Buffer[0];memset(MemPtr,0,MEMORY_SIZE);Xil_DCacheFlushRange((unsigned int)MemPtr, MEMORY_SIZE);/* Finish the configuration of the DeviceConfig structure and configure* the DEVICE side of the controller.*/DeviceConfig.DMAMemPhys = (u32) MemPtr;Status = XUsbPs_ConfigureDevice(UsbInstancePtr, &DeviceConfig);if (XST_SUCCESS != Status) {goto out;}/* Set the handler for receiving frames. */Status = XUsbPs_IntrSetHandler(UsbInstancePtr, UsbIntrHandler, NULL,XUSBPS_IXR_UE_MASK);if (XST_SUCCESS != Status) {goto out;}/* Set the handler for handling endpoint 0 events. This is where we* will receive and handle the Setup packet from the host.*/Status = XUsbPs_EpSetHandler(UsbInstancePtr, 0,XUSBPS_EP_DIRECTION_OUT,XUsbPs_Ep0EventHandler, UsbInstancePtr);/* Set the handler for handling endpoint 1 events.** Note that for this example we do not need to register a handler for* TX complete events as we only send data using static data buffers* that do not need to be free()d or returned to the OS after they have* been sent.*/Status = XUsbPs_EpSetHandler(UsbInstancePtr, 1,XUSBPS_EP_DIRECTION_OUT,XUsbPs_Ep1EventHandler, UsbInstancePtr);/* Enable the interrupts. */XUsbPs_IntrEnable(UsbInstancePtr, XUSBPS_IXR_UR_MASK |XUSBPS_IXR_UI_MASK);/* Start the USB engine */XUsbPs_Start(UsbInstancePtr);/* At this point we wait for the user to plug in the usb plug. This* will cause the host to send USB packets. Once we received something,* we clean up and stop the controller.** This will not really work if we want to use the USB storage* example. What can we do instead?*/while (NumReceivedFrames < 1) {/* NOP */}/* Set return code to indicate success and fall through to clean-up* code.*/ReturnStatus = XST_SUCCESS;out:/* Clean up. It's always safe to disable interrupts and clear the* handlers, even if they have not been enabled/set. The same is true* for disabling the interrupt subsystem.*/XUsbPs_Stop(UsbInstancePtr);XUsbPs_IntrDisable(UsbInstancePtr, XUSBPS_IXR_ALL);(int) XUsbPs_IntrSetHandler(UsbInstancePtr, NULL, NULL, 0);UsbDisableIntrSystem(IntcInstancePtr, UsbIntrId);/* Free allocated memory.*/if (NULL != UsbInstancePtr->UserDataPtr) {free(UsbInstancePtr->UserDataPtr);}return ReturnStatus;
}/*****************************************************************************/
/**** This function is the handler which performs processing for the USB driver.* It is called from an interrupt context such that the amount of processing* performed should be minimized.** This handler provides an example of how to handle USB interrupts and* is application specific.** @param CallBackRef is the Upper layer callback reference passed back* when the callback function is invoked.* @param Mask is the Interrupt Mask.* @param CallBackRef is the User data reference.** @return* - XST_SUCCESS if successful* - XST_FAILURE on error** @note None.*******************************************************************************/
static void UsbIntrHandler(void *CallBackRef, u32 Mask)
{NumIrqs++;
}/*****************************************************************************/
/**
* This funtion is registered to handle callbacks for endpoint 0 (Control).
*
* It is called from an interrupt context such that the amount of processing
* performed should be minimized.
*
*
* @param CallBackRef is the reference passed in when the function
* was registered.
* @param EpNum is the Number of the endpoint on which the event occured.
* @param EventType is type of the event that occured.
*
* @return None.
*
******************************************************************************/
static void XUsbPs_Ep0EventHandler(void *CallBackRef, u8 EpNum,u8 EventType, void *Data)
{XUsbPs *InstancePtr;int Status;XUsbPs_SetupData SetupData;u8 *BufferPtr;u32 BufferLen;u32 Handle;Xil_AssertVoid(NULL != CallBackRef);InstancePtr = (XUsbPs *) CallBackRef;switch (EventType) {/* Handle the Setup Packets received on Endpoint 0. */case XUSBPS_EP_EVENT_SETUP_DATA_RECEIVED:Status = XUsbPs_EpGetSetupData(InstancePtr, EpNum, &SetupData);if (XST_SUCCESS == Status) {/* Handle the setup packet. */(int) XUsbPs_Ch9HandleSetupPacket(InstancePtr,&SetupData);}break;/* We get data RX events for 0 length packets on endpoint 0. We receive* and immediately release them again here, but there's no action to be* taken.*/case XUSBPS_EP_EVENT_DATA_RX:/* Get the data buffer. */Status = XUsbPs_EpBufferReceive(InstancePtr, EpNum,&BufferPtr, &BufferLen, &Handle);if (XST_SUCCESS == Status) {/* Return the buffer. */XUsbPs_EpBufferRelease(Handle);}break;default:/* Unhandled event. Ignore. */break;}
}/*****************************************************************************/
/**
* This funtion is registered to handle callbacks for endpoint 1 (Bulk data).
*
* It is called from an interrupt context such that the amount of processing
* performed should be minimized.
*
*
* @param CallBackRef is the reference passed in when the function was
* registered.
* @param EpNum is the Number of the endpoint on which the event occured.
* @param EventType is type of the event that occured.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void XUsbPs_Ep1EventHandler(void *CallBackRef, u8 EpNum,u8 EventType, void *Data)
{XUsbPs *InstancePtr;int Status;u8 *BufferPtr;u32 BufferLen;u32 InavalidateLen;u32 Handle;Xil_AssertVoid(NULL != CallBackRef);InstancePtr = (XUsbPs *) CallBackRef;switch (EventType) {case XUSBPS_EP_EVENT_DATA_RX:/* Get the data buffer.*/Status = XUsbPs_EpBufferReceive(InstancePtr, EpNum,&BufferPtr, &BufferLen, &Handle);/* Invalidate the Buffer Pointer */InavalidateLen = BufferLen;if (BufferLen % 32) {InavalidateLen = (BufferLen/32) * 32 + 32;}Xil_DCacheInvalidateRange((unsigned int)BufferPtr,InavalidateLen);if (XST_SUCCESS == Status) {/* Handle the storage class request. */XUsbPs_HandleStorageReq(InstancePtr, EpNum,BufferPtr, BufferLen);/* Release the buffer. */XUsbPs_EpBufferRelease(Handle);}break;default:/* Unhandled event. Ignore. */break;}
}/*****************************************************************************/
/**
*
* This function setups the interrupt system such that interrupts can occur for
* the USB controller. This function is application specific since the actual
* system may or may not have an interrupt controller. The USB controller could
* be directly connected to a processor without an interrupt controller. The
* user should modify this function to fit the application.
*
* @param IntcInstancePtr is a pointer to instance of the Intc controller.
* @param UsbInstancePtr is a pointer to instance of the USB controller.
* @param UsbIntrId is the Interrupt Id and is typically
* XPAR_<INTC_instance>_<USB_instance>_VEC_ID value
* from xparameters.h
*
* @return
* - XST_SUCCESS if successful
* - XST_FAILURE on error
*
******************************************************************************/
static int UsbSetupIntrSystem(XScuGic *IntcInstancePtr,XUsbPs *UsbInstancePtr, u16 UsbIntrId)
{int Status;XScuGic_Config *IntcConfig;/** Initialize the interrupt controller driver so that it is ready to* use.*/IntcConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);if (NULL == IntcConfig) {return XST_FAILURE;}Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS) {return XST_FAILURE;}Xil_ExceptionInit();/** Connect the interrupt controller interrupt handler to the hardware* interrupt handling logic in the processor.*/Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,IntcInstancePtr);/** Connect the device driver handler that will be called when an* interrupt for the device occurs, the handler defined above performs* the specific interrupt processing for the device.*/Status = XScuGic_Connect(IntcInstancePtr, UsbIntrId,(Xil_ExceptionHandler)XUsbPs_IntrHandler,(void *)UsbInstancePtr);if (Status != XST_SUCCESS) {return Status;}/** Enable the interrupt for the device.*/XScuGic_Enable(IntcInstancePtr, UsbIntrId);/** Enable interrupts in the Processor.*/Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);return XST_SUCCESS;
}/*****************************************************************************/
/**
*
* This function disables the interrupts that occur for the USB controller.
*
* @param IntcInstancePtr is a pointer to instance of the INTC driver.
* @param UsbIntrId is the Interrupt Id and is typically
* XPAR_<INTC_instance>_<USB_instance>_VEC_ID value
* from xparameters.h
*
* @return None
*
* @note None.
*
******************************************************************************/
static void UsbDisableIntrSystem(XScuGic *IntcInstancePtr, u16 UsbIntrId)
{/* Disconnect and disable the interrupt for the USB controller. */XScuGic_Disconnect(IntcInstancePtr, UsbIntrId);
}
xusbps_class_storage.c代码
/******************************************************************************
*
* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/*** @file xusbps_class_storage.c** This file contains the implementation of the storage class code for the* example.**<pre>* MODIFICATION HISTORY:** Ver Who Date Changes* ----- ---- -------- ---------------------------------------------------------* 1.00a wgr 10/10/10 First release* 2.1 kpc 4/28/14 Align DMA buffers to cache line boundary*</pre>******************************************************************************//***************************** Include Files *********************************/#include <string.h>#include "xusbps.h" /* USB controller driver */#include "xusbps_ch9_storage.h"
#include "xusbps_ch9.h"
#include "xusbps_class_storage.h"
#include "xil_printf.h"#include <stdio.h>
#include "xparameters.h"
#include "xsdps.h"
#include "xil_printf.h"
#include "ff.h"#define CLASS_STORAGE_DEBUGextern XSdPs ps7_EMMC;#ifdef CLASS_STORAGE_DEBUG
#define printf xil_printf
#endif/************************** Constant Definitions *****************************//************************** Function Prototypes ******************************//************************** Variable Definitions *****************************//* Pre-manufactured response to the SCSI Inquirey command.*/
#ifdef __ICCARM__
#pragma data_alignment = 32
const static SCSI_INQUIRY scsiInquiry = {0x00,0x80,0x00,0x01,0x1f,0x00,0x00,0x00,{"Xilinx "}, /* Vendor ID: must be 8 characters long. */{"PS USB VirtDisk"}, /* Product ID: must be 16 characters long. */{"1.00"} /* Revision: must be 4 characters long. */
};
static u8 MaxLUN = 0;
/* Buffer for virtual flash disk space. */
static u8 VirtFlash[VFLASH_SIZE];static USB_CBW lastCBW;/* Local transmit buffer for simple replies. */
static u8 txBuffer[128];
#pragma data_alignment = 4
#else
const static SCSI_INQUIRY scsiInquiry ALIGNMENT_CACHELINE = {0x00,0x80,0x00,0x01,0x1f,0x00,0x00,0x00,{"Xilinx "}, /* Vendor ID: must be 8 characters long. */{"PS USB VirtDisk"}, /* Product ID: must be 16 characters long. */{"1.00"} /* Revision: must be 4 characters long. */
};
static u8 MaxLUN ALIGNMENT_CACHELINE = 0;
/* Buffer for virtual flash disk space. */
static u8 VirtFlash[VFLASH_SIZE] ALIGNMENT_CACHELINE;static USB_CBW lastCBW ALIGNMENT_CACHELINE;/* Local transmit buffer for simple replies. */
static u8 txBuffer[128] ALIGNMENT_CACHELINE;
#endif/*****************************************************************************/
/**
* This function handles Reduced Block Command (RBC) requests from the host.
*
* @param InstancePtr is a pointer to XUsbPs instance of the controller.
* @param EpNum is the number of the endpoint on which the RBC was received.
* @param BufferPtr is the data buffer containing the RBC or data.
* @param BufferLen is the length of the data buffer.
*
* @return None.
*
* @note None.
*
******************************************************************************/
extern FIL file;
void XUsbPs_HandleStorageReq(XUsbPs *InstancePtr, u8 EpNum,u8 *BufferPtr, u32 BufferLen)
{USB_CBW *CBW;u32 Offset;//static u8 *VirtFlashWritePointer = VirtFlash;/* Static variables used for data transfers.*/static int rxBytesLeft;static u32 SdOffset = 0;UINT bytesRead;UINT bytesWritten;FRESULT res;u32 Lba;u16 BlockCount;s32 Status;u8 DataBuffer[SD_BLOCK_SIZE];/* Current SCSI machine state. */static int phase = USB_EP_STATE_COMMAND;/* COMMAND phase. */if (USB_EP_STATE_COMMAND == phase) {CBW = (USB_CBW *) BufferPtr;switch (CBW->CBWCB[0]) {case USB_RBC_INQUIRY:
#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: INQUIRY\n");
#endifXUsbPs_EpBufferSend(InstancePtr, 1,(void *) &scsiInquiry,sizeof(scsiInquiry));/* Send Success Status */CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1, (void *) CBW, 13);break;case USB_UFI_GET_CAP_LIST:{SCSI_CAP_LIST *CapList;CapList = (SCSI_CAP_LIST *) txBuffer;
#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: CAPLIST\n");
#endifCapList->listLength = 8;CapList->descCode = 3;CapList->numBlocks = htonl(SD_NUM_BLOCKS);CapList->blockLength = htons(SD_BLOCK_SIZE);
#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: GET CAP LIST\n");//printf(" Total Blocks: %u\n", fileSize / VFLASH_BLOCK_SIZE);//printf(" Block Size: %u\n", VFLASH_BLOCK_SIZE);
#endifXUsbPs_EpBufferSend(InstancePtr, 1, txBuffer,sizeof(SCSI_CAP_LIST));/* Send Success Status*/CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength =be2le(be2le(CBW->dCBWDataTransferLength) -sizeof(SCSI_CAP_LIST));CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *) CBW, 13);break;}case USB_RBC_READ_CAP:{SCSI_READ_CAPACITY *Cap;Cap = (SCSI_READ_CAPACITY *) txBuffer;
#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: READCAP\n");
#endifCap->numBlocks = htonl(SD_NUM_BLOCKS - 1);Cap->blockSize = htonl(SD_BLOCK_SIZE);XUsbPs_EpBufferSend(InstancePtr, 1, txBuffer,sizeof(SCSI_READ_CAPACITY));/* Send Success Status */CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *) CBW, 13);break;}case USB_RBC_READ:/*Offset = htonl(((SCSI_READ_WRITE *) CBW->CBWCB)->block) * VFLASH_BLOCK_SIZE;u32 length = htons(((SCSI_READ_WRITE *) CBW->CBWCB)->length) * VFLASH_BLOCK_SIZE;*/// 计算起始逻辑块地址(LBA)和块数Lba = htonl(((SCSI_READ_WRITE *)CBW->CBWCB)->block);BlockCount = htons(((SCSI_READ_WRITE *)CBW->CBWCB)->length);#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: Lba 0x%08x,BlockCount 0x%x\n\r", (int) Lba,BlockCount);
#endif// 从 SD 卡读取数据(多块读取)res = XSdPs_ReadPolled(&ps7_EMMC, Lba, BlockCount, VirtFlash);if (res != XST_SUCCESS) {printf("XSdPs_ReadPolled failed\n\r");// 读取失败,返回错误状态CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 1; // 设置为失败标志XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *)CBW, 13);return;}// 发送读取的数据XUsbPs_EpBufferSend(InstancePtr, 1, VirtFlash, BlockCount * SD_BLOCK_SIZE);/*XUsbPs_EpBufferSend(InstancePtr, 1, &VirtFlash[Offset],htons(((SCSI_READ_WRITE *) CBW->CBWCB)->length) * VFLASH_BLOCK_SIZE);*//* Send Success Status */CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *) CBW, 13);break;case USB_RBC_MODE_SENSE:
#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: MODE SENSE\n");
#endifXUsbPs_EpBufferSend(InstancePtr, 1,(u8 *) "\003\000\000\000", 4);/* Send Success Status */CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength =be2le(be2le(CBW->dCBWDataTransferLength) - 4);CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *) CBW, 13);break;case USB_RBC_TEST_UNIT_READY:case USB_RBC_MEDIUM_REMOVAL:case USB_RBC_VERIFY:
#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: TEST UNIT READY\n\r");
#endif/* Send Success Status */CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *) CBW, 13);break;case USB_RBC_WRITE:Offset = htonl(((SCSI_READ_WRITE *) CBW->CBWCB)->block) * VFLASH_BLOCK_SIZE;Lba = htonl(((SCSI_READ_WRITE *)CBW->CBWCB)->block);BlockCount = htons(((SCSI_READ_WRITE *)CBW->CBWCB)->length);#ifdef CLASS_STORAGE_DEBUG//printf("SCSI: WRITE Offset 0x%08x\n", (int) Offset);
#endif//VirtFlashWritePointer = &VirtFlash[Offset];/* Save the CBW for the DATA and STATUS phases. *///lastCBW = *CBW;rxBytesLeft =htons(((SCSI_READ_WRITE *) CBW->CBWCB)->length)* VFLASH_BLOCK_SIZE;//printf("SCSI: WRITE LBA 0x%08x,BlockCount 0x%x,BufferLen 0x%x\n\r", (int) Offset,BlockCount,BufferLen);SdOffset = Lba;lastCBW = *CBW;//rxBytesLeft = BlockCount * SD_BLOCK_SIZE;phase = USB_EP_STATE_DATA;break;case USB_RBC_STARTSTOP_UNIT:{u8 immed;immed = ((SCSI_START_STOP *) CBW->CBWCB)->immed;
#ifdef CLASS_STORAGE_DEBUGprintf("SCSI: START/STOP unit: immed %02x\n", immed);
#endif/* If the immediate bit is 0 we are supposed to send* a success status.*/if (0 == (immed & 0x01)) {/* Send Success Status */CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1,(u8 *) CBW, 13);}break;}/* Commands that we do not support for this example. */case 0x04: /* Format Unit */case 0x15: /* Mode Select */case 0x5e: /* Persistent Reserve In */case 0x5f: /* Persistent Reserve Out */case 0x17: /* Release */case 0x03: /* Request Sense */case 0x16: /* Reserve */case 0x35: /* Sync Cache */case 0x3b: /* Write Buffer */
#ifdef CLASS_STORAGE_DEBUGprintf("SCSI: Got unhandled command %02x\n", CBW->CBWCB[0]);
#endifdefault:break;}}/* DATA phase.*/else if (USB_EP_STATE_DATA == phase) {switch (lastCBW.CBWCB[0]) {case USB_RBC_WRITE:/* Copy the data we just read into the VirtFlash buffer. *///memcpy(VirtFlashWritePointer, BufferPtr, BufferLen);//VirtFlashWritePointer += BufferLen;//printf("SCSI: WRITE LBA 0x%08x,BlockCount 0x%x,BufferLen 0x%x\n\r", SdOffset,BlockCount,BufferLen);memcpy(DataBuffer, BufferPtr, BufferLen);Status =XSdPs_WritePolled(&ps7_EMMC, SdOffset, 1, DataBuffer);if (res != XST_SUCCESS) {printf("XSdPs_WritePolled failed\n\r");// 读取失败,返回错误状态CBW->dCBWSignature = 0x55534253;CBW->dCBWDataTransferLength = 0;CBW->bmCBWFlags = 1; // 设置为失败标志XUsbPs_EpBufferSend(InstancePtr, 1, (u8 *)CBW, 13);return;}SdOffset++;rxBytesLeft -= BufferLen;if (rxBytesLeft <= 0) {/* Send Success Status */lastCBW.dCBWSignature = 0x55534253;lastCBW.dCBWDataTransferLength = 0;lastCBW.bmCBWFlags = 0;XUsbPs_EpBufferSend(InstancePtr, 1,(void *) &lastCBW, 13);phase = USB_EP_STATE_COMMAND;}break;}}
}/*****************************************************************************/
/**
* This function handles a Storage Class Setup request from the host.
*
* @param InstancePtr is a pointer to XUsbPs instance of the controller.
* @param SetupData is the setup data structure containing the setup
* request.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void XUsbPs_ClassReq(XUsbPs *InstancePtr, XUsbPs_SetupData *SetupData)
{Xil_AssertVoid(InstancePtr != NULL);Xil_AssertVoid(SetupData != NULL);switch (SetupData->bRequest) {case XUSBPS_CLASSREQ_MASS_STORAGE_RESET:XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);break;case XUSBPS_CLASSREQ_GET_MAX_LUN:XUsbPs_EpBufferSend(InstancePtr, 0, &MaxLUN, 1);break;default:XUsbPs_EpStall(InstancePtr, 0, XUSBPS_EP_DIRECTION_IN);break;}
}