/******************************************************************************
*
* Copyright (C) 2006 Vreelin Engineering, Inc.  All Rights Reserved.
* (c) Copyright 2007-2013 Xilinx, Inc. All rights reserved.
*
* This file contains confidential and proprietary information of Xilinx, Inc.
* and is protected under U.S. and international copyright and other
* intellectual property laws.
*
* DISCLAIMER
* This disclaimer is not a license and does not grant any rights to the
* materials distributed herewith. Except as otherwise provided in a valid
* license issued to you by Xilinx, and to the maximum extent permitted by
* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
* and (2) Xilinx shall not be liable (whether in contract or tort, including
* negligence, or under any other theory of liability) for any loss or damage
* of any kind or nature related to, arising under or in connection with these
* materials, including for any direct, or any indirect, special, incidental,
* or consequential loss or damage (including loss of data, profits, goodwill,
* or any type of loss or damage suffered as a result of any action brought by
* a third party) even if such damage or loss was reasonably foreseeable or
* Xilinx had been advised of the possibility of the same.
*
* CRITICAL APPLICATIONS
* Xilinx products are not designed or intended to be fail-safe, or for use in
* any application requiring fail-safe performance, such as life-support or
* safety devices or systems, Class III medical devices, nuclear facilities,
* applications related to the deployment of airbags, or any other applications
* that could lead to death, personal injury, or severe property or
* environmental damage (individually and collectively, "Critical
* Applications"). Customer assumes the sole risk and liability of any use of
* Xilinx products in Critical Applications, subject only to applicable laws
* and regulations governing limitations on product liability.
*
* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
* AT ALL TIMES.
*
******************************************************************************/
/******************************************************************************/
/**
 * @file xusb_storage.h
 *
 * This file contains the constants, type definitions, variables and function
 * prototypes used in the mass storage application.
 *
 * @note	None.
 *
 * <pre>
 * MODIFICATION HISTORY:
 *
 * Ver   Who  Date     Changes
 * ----- ---- ------------------------------------------------------------------
 * 1.00a hvm  2/12/07 First release
 * 1.01a hvm  10/2/08 The variables IntLba in Lba and IntBlockCount in
 *			BlockCount are declared as volatile.
 * 2.00a hvm  03/12/09 Modified the RAMDISKSECTORS constant value from 0x4000 to
 *			0x400 as this would reduce the code size and the example
 *			can run in a smaller memory systems.
 * 3.02a hvm  08/16/10 Updated with the little endian support changes.
 * 4.00a hvm  10/25/10 Updated with DmaIntrHandler function prototype. Updated
 *			INQUIRY command with pad values.
 * 4.00a hvm  06/01/11 Modified the USB Mass Storage Command Status Wrapper
 * 			structure. The union for Signature is removed and
 *			only the array definition of Signature is retained.
 *			CR611761 fix.
 * 4.00a hvm  06/24/11 Updated the INQUIRY command fourth parameter value to 0.
 *			CR614794
 * 4.01a hvm  08/11/11 Updated the RamDisk variable to have a 32 bit address
 *			alignment.
 * 4.01a hvm  09/14/11 Fixed the compilation issue at the RamDisk variable
 *			declaration. CR625055.
 *
 * </pre>
 *****************************************************************************/

#ifndef  XUSB_STORAGE_H
#define  XUSB_STORAGE_H

#ifdef __cplusplus
extern "C" {
#endif

/***************************** Include Files **********************************/

#include "xusb_cp9.h"

/************************** Constant Definitions ******************************/

/*
 * Mass storage device Flash size. The following constants are to be modified
 * to get different size of  memory.
 */
#define RAMDISKSECTORS  		0x400
#define RAMBLOCKS			128

/*
 * Mass storage Class and Sub class codes.
 */
#define MS_SCSI_CMD_SET			0x06
#define CLASS_MASS_STORAGE		0x08

/*
 * Mass Storage Protocols.
 */
#define MS_BULK_ONLY			0x50

/*
 * SCSI Commands.
 */
#define SCSI_READ_10			0x28
#define SCSI_READ_12			0xA8
#define SCSI_WRITE_10			0x2A
#define SCSI_WRITE_12			0xAA
#define SCSI_VERIFY			0x2f
#define SCSI_INQUIRY			0x12
#define SCSI_READ_FORMAT_CAPACITIES	0x23
#define SCSI_MODE_SENSE			0x1a
#define SCSI_READ_CAPACITY		0x25
#define SCSI_TEST_UNIT_READY		0x00
#define SCSI_REQUEST_SENSE		0x03
#define SCSI_MEDIA_REMOVAL		0x1e

#define USBCSW_SIGNATURE 		0x55534253
#define USBCSW_LENGTH			0x0d
#define MODESENSE_RETURNALL		0x3f

/*
 * Valid USB Status block.
 */
#define CMD_PASSED			0x00
#define CMD_FAILED			0x01
#define PHASE_ERROR			0x02

/*
 * Error codes.
 */
#define NO_ERROR			0
#define ERR_NOTERASED			1
#define ERR_NOFREEBLOCKS		2
#define ERR_USBABORT			3
#define ERR_CMDFAILED			4
#define ERR_ECC				5
#define ERR_BADBZ			6
#define ERR_DSMM			7

/*
 * Mass Storage file format related constants.
 */
#define FORMATTED_CURRENT		0x02000000
#define UNFORMATTED			0x01000000
#define BLOCK_SIZE			0x0200

/*
 * End point types.
 */
#define EP_CONTROL			0	/**< Control Endpoint */
#define EP_ISOCHRONOUS			1	/**< Isochronous Endpoint */
#define EP_BULK				2	/**< Bulk Endpoint */
#define EP_INTERRUPT			3	/**< Interrupt Endpoint */

/************************** Variable Definitions ******************************/

/*
 * Flags used to abort read and write command loops.
 */
u8 Read10Abort = 0;
u8 Write10Abort = 0;
u8 ErrCode;
extern u16 MaxControlSize;
extern USB_CMD_BUF Ch9_CmdBuf;
extern IntChar UsbMemData;		/* Dual Port memory */

/*
 * A ram array
 */
u32 RamDisk[RAMDISKSECTORS][RAMBLOCKS] __attribute__ ((aligned(4)));

/*
 * Logical block address.
 */
union {
	volatile u8 CharLba[4];
	volatile u32 IntLba;
} Lba;

/*
 * Mass storage memory block count.
 */
union {
	volatile u8 CharBlockCount[4];
	volatile u32 IntBlockCount;
} BlockCount;

/*
 * SCSI Command descriptor blocks.
 */

/*
 * Modesense.
 */
typedef struct {
	u8 OpCode;
	u8 lun;
	u8 pagecode;
	u8 mb0;
	u8 parmlength;
	u8 mb0_2;
	u8 padding[10];
} SCSI_MODESENSE_CDB, *PSCSI_MODESENSE_CDB;

/*
 * Media Removal.
 */
typedef struct {
	u8 OpCode;
	u8 lun;
	u8 mb0[2];
	u8 prevent;
	u8 padding[11];

} SCSI_MEDIA_REMOVAL_TYPE, *PSCSI_MEDIA_REMOVAL_TYPE;

/*
 * Responses to SCSI commands.
 */

/*
 * Request Sense standard data.
 */
typedef struct {
	u8 error_code;
	u8 padding1;
	u8 sense_key;
	u8 information[4];
	u8 additional_sense_length;
	u8 padding2[4];
	u8 additional_sense_code;
	u8 additional_sense_code_qualifier;
	u8 padding3[4];

} REQUEST_SENSE, *PREQUEST_SENSE;

/*
 * Inquiry Data.
 */
typedef struct {
	u8 device_type;
	u8 RMB;
	u8 mbz;
	u8 mb1;
	u8 mb1f;
	char pad[3];
	char vendor[8];
	char product[16];
	char prodrev[4];

} INQUIRY, *PINQUIRY;

/*
 * Read Format Capacities.
 */
typedef struct {
	u8 caplstlen[4];
	u8 maxnumblocks[4];
	u8 cap_code_blocklength[4];

} CAPACITY_LIST, *PCAPACITY_LIST;

typedef struct {
	u8 lastLBA[4];
	u8 blocklength[4];
} READ_CAPACITY, *PREAD_CAPACITY;

/*
 * MODESENSE Mode Parameter List.
 */
typedef struct {
	u8 mode_data_length;
	u8 medium_type_code;
	u8 device_spec_params;
	u8 block_desc_length;
} MODESENSE_MPL, *PMODESENSE_MPL;

/*
 * MODESENSE Read-Write Error Recovery Page.
 */
typedef struct {
	u8 page_code;
	u8 page_length;
	u8 page_params;
	u8 read_retry_count;
	u8 reserved_mb0[4];
	u8 write_retry_count;
	u8 reserved_mb3;
	u8 recovery_limit[2];

} MODESENSE_RWER, *PMODESENSE_RWER;

/*
 * Modesense Flexible Disk Page.
 */
typedef struct {
	u8 page_code;
	u8 page_length;
	u8 transfer_rate[2];
	u8 heads;
	u8 sectors_track;
	u8 bytes_sector[2];
	u8 cylinders[2];
	u8 mbd8;
	u8 mb0_1[8];
	u8 motor_on_delay;
	u8 motor_off_delay;
	u8 mb0_2[7];
	u8 medium_rotation_rate[2];
	u8 mb0_3[2];

} MODESENSE_FD, *PMODESENSE_FD;

/*
 * Modesense Removable Block Access Capacities Page.
 */
typedef struct {
	u8 page_code;
	u8 page_length;
	u8 mb0_1;
	u8 total_luns;
	u8 mb0_2[8];

} MODESENSE_RBAC, *PMODESENSE_RBAC;

/*
 * Modesense Timer and Protect Page.
 */
typedef struct {
	u8 page_code;
	u8 page_length;
	u8 mb0_1;
	u8 iatm;
	u8 mb0_2[3];
	u8 mb1c;

} MODESENSE_TP, *PMODESENSE_TP;


typedef struct {
	MODESENSE_MPL mpl;
	u8 page1_code;
	u8 page1_length;
	u8 page2_code;
	u8 page2_length;

} MODE_SENSE_REPLY_SHORT, *PMODE_SENSE_REPLY_SHORT;

typedef struct {
	MODESENSE_MPL mpl;
	MODESENSE_RWER rwer;
	MODESENSE_FD fd;
	MODESENSE_RBAC rbac;
	MODESENSE_TP tp;

} MODE_SENSE_REPLY_ALL, *PMODE_SENSE_REPLY_ALL;

/*
 * USB Mass Storage Command Block Wrapper.
 */
typedef struct {
	union Signature {
		u8 dCBWSignature[4];
		u32 VALUE;

	} Signature;

	u32 dCBWTag;

	union Length {
		u8 dCBWDataTransferLength[4];
		u32 VALUE;

	} Length;

	u8 dCBWFlags;
	u8 bCBWLUN;
	u8 bCDBLength;

	volatile u8 OpCode;
	u8 lun;
	u8 lba[4];
	u8 reserved_2;
	u8 transfer_length[2];
	u8 control;
	u8 padding[6];

} USBCBW, *PUSBCBW;

/*
 * USB Mass Storage Command Status Wrapper.
 */
typedef struct {

	u8 dCBWSignature[4];

	u32 dCBWTag;
	union Residue {
		u8 dCSWDataResidue[4];
		u32 value;

	} Residue;

	u8 bCSWStatus;

} USBCSW, *PUSBCSW;

/*
 * Mass Storage Command and Status block instances.
 */
USBCBW CmdBlock;
USBCSW CmdStatusBlock;



USB_STD_DEV_DESC DeviceDescriptor __attribute__ ((aligned(4))) = {
	sizeof(USB_STD_DEV_DESC),	/* Descriptor Size 18 bytes */
		DEVICE_DESCR,	/* This is a device descriptor */
#ifdef __LITTLE_ENDIAN__
		0x0200,		/* USB version */
#else
		0x02,		/* USB version */
#endif
		0,		/* Vendor Specific */
		00,		/* Unused */
		00,		/* Unused */
		0x40,		/* Ep0 Max Pkt Size 64 bytes */
#ifdef __LITTLE_ENDIAN__
		0x03FD,		/* Vendor Id */
		0x0100,		/* Product Id */
		0x0100,		/* BCD device */
#else
		0xFD03,		/* Vendor Id */
		0x0001,		/* Product Id */
		0x01,		/* BCD device */
#endif
		01,		/* String Index of manufacturer */
		02,		/* String Index of product */
		03,		/* String Index of serial number */
		01		/* Number of configurations */
};

USB_STD_QUAL_DESC QualifierDescriptor __attribute__ ((aligned(4))) = {
sizeof(USB_STD_QUAL_DESC),
		QUALIFIER_DESCR, 00, 02, 0, 00, 00, 0x40, 01, 0};

FPGA1_CONFIGURATION __attribute__ ((aligned(4))) HsUsbConfig = {

	/*
	 * Configuration descriptor.
	 */
	{
		sizeof(USB_STD_CFG_DESC),	/* Size of config descriptor 9
		bytes */
			CONFIG_DESCR,	/* This is a config descriptor */
			sizeof(HsUsbConfig),	/* Total size of configuration
			LS */
			0x00,	/* Total size of configuration MS */
			0x01,	/* No. Of interfaces 1 */
			CONFIGURATION_ONE,	/* No of configuration values */
			0x00,	/* Configuration string */
			0xc0,	/* Self Powered */
			0x01	/* Uses 2mA from the USB bus */
	}
	,
		/*
		 * FPGA1 Class interface.
		 */
	{
		sizeof(USB_STD_IF_DESC),	/* Interface Descriptor size 9
		bytes */
			INTERFACE_DESCR,	/* This is an interface
			descriptor */
			0x00,	/* Interface number 0 */
			0x00,	/* Alternate set 0 */
			0x02,	/* Number of end points 2 */
			CLASS_MASS_STORAGE,	/* Vendor specific */
			MS_SCSI_CMD_SET,	/* Interface sub class */
			MS_BULK_ONLY,	/* protocol BULK only */
			0x00	/* Interface unused */
	}
	,
		/*
		 * End_point 1 RX descriptor  from device to host.
		 */
	{
		sizeof(USB_STD_EP_DESC),	/* End point descriptor size */
			ENDPOINT_DESCR,	/* This is an end point descriptor */
			0x81,	/* End point one */
			EP_BULK,	/* End point type */
			0x00,	/* Maximum packet  size 512 bytes LS */
			0x02,	/* Maximum packetsize MS */
			0xff	/* Nak rate */
	}
	,
		/*
		 * End_point 2 RX descriptor  from host to device.
		 */
	{
		sizeof(USB_STD_EP_DESC),	/* End point descriptor size */
			ENDPOINT_DESCR,	/* This is an end point descriptor */
			0x02,	/* End point two */
			EP_BULK,	/* End point type */
			0x00,	/* Maximum packet  size 512 bytes LS */
			0x02,	/* Maximum packetsize MS */
			0xff	/* Nak rate */
	}

};

FPGA1_CONFIGURATION __attribute__ ((aligned(4))) FsUsbConfig = {

	/*
	 * Configuration descriptor.
	 */
	{
		sizeof(USB_STD_CFG_DESC),	/* Size of config descriptor 9
		bytes */
			CONFIG_DESCR,	/* This is a conifig descriptor */
			sizeof(FsUsbConfig),	/* Total size of configuration
			LS */
			0x00,	/* Total size of configuration MS */
			0x01,	/* No. Of interfaces 1 */
			CONFIGURATION_ONE,	/* No of configuration values */
			0x00,	/* Configuration string */
			0xc0,	/* Self Powered */
			0x01	/* Uses 2mA from the USB bus */
	}
	,
		/*
		 * FPGA1 Class interface.
		 */
	{
		sizeof(USB_STD_IF_DESC),	/* Interface Descriptor size 9
		bytes */
			INTERFACE_DESCR,	/* This is an interface
			descriptor */
			0x00,	/* Interface number 0 */
			0x00,	/* Alternate set 0 */
			0x02,	/* Number of end points 2 */
			CLASS_MASS_STORAGE,	/* Vendor specific */
			MS_SCSI_CMD_SET,	/* Interface sub class */
			MS_BULK_ONLY,	/* protocol BULK only */
			0x00	/* Interface unused */
	}
	,
		/*
		 * End_point  1 RX descriptor  from device to host.
		 */
	{
		sizeof(USB_STD_EP_DESC),	/* End point descriptor size */
			ENDPOINT_DESCR,	/* This is an end point descriptor */
			0x81,	/* End point one */
			EP_BULK,	/* End point type */
			0x40,	/* Maximum packet  size 64 bytes LS */
			0x00,	/* Maximum packetsize MS */
			0x00	/* Nak rate */
	}
	,
		/*
		 * End_point 2 RX descriptor  from host to device.
		 */
	{
		sizeof(USB_STD_EP_DESC),	/* End point descriptor size */
			ENDPOINT_DESCR,	/* This is an end point descriptor */
			0x02,	/* End point two */
			EP_BULK,	/* End point type */
			0x40,	/* Maximum packet  size 64 bytes LS */
			0x00,	/* Maximum packetsize MS */
			0x00	/* Nak rate */
	}

};

USB_STD_STRING_DESC LangId __attribute__ ((aligned(4))) = {
	/*
	 * Language ID codes.
	 */
	4, STRING_DESCR, {
	0x0904}
};

USB_STD_STRING_MAN_DESC Manufacturer __attribute__ ((aligned(4))) = {
	/*
	 * Manufacturer String.
	 */
	sizeof(USB_STD_STRING_MAN_DESC), STRING_DESCR, {
	'X', 0, 'I', 0, 'L', 0, 'I', 0, 'N', 0, 'X', 0, ' ', 0}
};

USB_STD_STRING_PS_DESC ProductString __attribute__ ((aligned(4))) = {
	/*
	 * Product ID String.
	 */
	sizeof(USB_STD_STRING_PS_DESC), STRING_DESCR, {
	'F', 0, 'P', 0, 'G', 0, 'A', 0, '1', 0}
};

USB_STD_STRING_SN_DESC SerialNumber __attribute__ ((aligned(4))) = {
	/*
	 * Product ID String.
	 */
	sizeof(USB_STD_STRING_SN_DESC), STRING_DESCR, {
	'0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '1', 0,
			'7', 0, '1', 0, '5', 0, '0', 0, '4', 0, '2', 0,
			'6', 0, '2', 0, '0', 0, '0', 0, '5', 0, '7', 0, '4', 0}
};

/*
 * Mass Storage device enumeration related structure initializations.
 */
REQUEST_SENSE Prss = { 0x70, 0, 0x06,{'0','0','0','0'}, 0x0a, {'0','0','0','0'},
			0x28,0x0, {'0','0','0','0'}};

INQUIRY Piq = { 0, 0x80, 0, 0, 0x1f, {0,0,0},{'X','i','l','i','n','x' },
		{'S','M','S','C',' ','F','l','a','s','h',' ','D','e','m','o'},
		{'0','0','0','1'}};

CAPACITY_LIST Pcl = { {'8','0','0','0'}, {(RAMDISKSECTORS & 0xFF),
			       ((RAMDISKSECTORS & 0xFF00) >> 8),
			       ((RAMDISKSECTORS & 0xFF0000) >> 16),
			       ((RAMDISKSECTORS & 0xFF000000) >> 24)},
{((FORMATTED_CURRENT | BLOCK_SIZE) & 0xFF),
 (((FORMATTED_CURRENT | BLOCK_SIZE) & 0xFF00) >> 8),
 (((FORMATTED_CURRENT | BLOCK_SIZE) & 0xFF0000) >> 16),
 (((FORMATTED_CURRENT | BLOCK_SIZE) & 0xFF0000) >> 24)}
};

READ_CAPACITY Prc;

PSCSI_MEDIA_REMOVAL_TYPE Pmr;

MODE_SENSE_REPLY_SHORT Pmsd_s = { {0x12, 0, 0x00, 0x00},
0x00, 0x00, 0x00, 0x1c };
MODE_SENSE_REPLY_ALL Pmsd_l = { {0x43, 0, 0x00, 0x00},
				{0x1, 0x0a, 0, 0x03, {0, 0, 0, 0},
					0x80, 0x03, { 0, 0} },
				{0x05, 0x1e, {0x13, 0x88}, 0x00, 0x010,
					{0x3f, 00},{0x00, 0x03}, 0xd8,
					{0, 0, 0, 0, 0, 0, 0, 0}, 0x05, 0x1e,
					{0, 0, 0, 0, 0, 0, 0}, {0x1, 0x68},
					{0x0, 0x0} },
				{0x1b, 0x0a, 0, 1, {0, 0, 0, 0, 0, 0, 0, 0}},
				{0x1c, 0x06, 0x0, 0x5, {0, 0, 0}, 0x1c} };


PSCSI_MODESENSE_CDB Pms_cdb;

/************************** Function Prototypes *******************************/

void InitUsbInterface(XUsb * InstancePtr);
void UsbIfIntrHandler(void *CallBackRef, u32 IntrStatus);
void EpIntrHandler(void *CallBackRef, u8 EpNum, u32 IntrStatus);
void Ep0IntrHandler(void *CallBackRef, u8 EpNum, u32 IntrStatus);
void Ep1IntrHandler(void *CallBackRef, u8 EpNum, u32 IntrStatus);
void Ep2IntrHandler(void *CallBackRef, u8 EpNum, u32 IntrStatus);
void ProcessRxCmd(XUsb * InstancePtr);
void Read10(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void Write10(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void RequestSense(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void Media_Removal(PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void ModeSense(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void ReadCapacity(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void RFC(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
void Inquiry(XUsb * InstancePtr, PUSBCBW pCmdBlock, PUSBCSW pStatusBlock);
static int SetupInterruptSystem(XUsb * InstancePtr);
void MassStorageReset(XUsb * InstancePtr);
void GetMaxLUN(XUsb * InstancePtr);

#ifdef __cplusplus
}
#endif

#endif /* XUSB_STORAGE_H */