2297 lines
82 KiB
C
2297 lines
82 KiB
C
/*******************************************************************************
|
|
|
|
This software file (the "File") is distributed by Marvell International Ltd.
|
|
or its affiliate(s) under the terms of the GNU General Public License Version 2,
|
|
June 1991 (the "License"). You may use, redistribute and/or modify this File
|
|
in accordance with the terms and conditions of the License, a copy of which
|
|
is available along with the File in the license.txt file or by writing to the
|
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
|
|
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
|
|
DISCLAIMED. The GPL License provides additional details about this warranty
|
|
disclaimer.
|
|
|
|
(C) Copyright 2004 - 2007 Marvell Semiconductor Israel Ltd. All Rights Reserved.
|
|
(C) Copyright 1999 - 2004 Chipidea Microelectronica, S.A. All Rights Reserved.
|
|
|
|
*******************************************************************************/
|
|
|
|
/**************************************************************************
|
|
Include the USB stack and local header files.
|
|
**************************************************************************/
|
|
|
|
#include "usb/api/mvUsbDefs.h"
|
|
#include "usb/api/mvUsbCh9.h"
|
|
#include "usb/api/mvUsbDebug.h"
|
|
#include "usb/api/mvUsbDevApi.h"
|
|
#include "usb/examples/disk.h"
|
|
|
|
/* MSB of debug flags for USB device usage */
|
|
#define ARC_DEBUG_FLAG_DISK 0x01000000
|
|
#define ARC_DEBUG_FLAG_DISK_READ 0x02000000
|
|
#define ARC_DEBUG_FLAG_DISK_WRITE 0x04000000
|
|
#define ARC_DEBUG_FLAG_DISK_CAP 0x08000000
|
|
#define ARC_DEBUG_FLAG_DISK_DATA 0x10000000
|
|
#define ARC_DEBUG_FLAG_DISK_DUMP 0x20000000
|
|
|
|
|
|
/**************************************************************************
|
|
Include the OS and BSP dependent files that define IO functions and
|
|
basic types. You may like to change these files for your board and RTOS
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************
|
|
Global variables and some defines for device.
|
|
**************************************************************************/
|
|
|
|
#define BUFFERSIZE (2048)
|
|
|
|
#define EP_TEMP_BUFFERSIZE (32)
|
|
#define MASS_STORAGE_INTERFACE (0)
|
|
|
|
#define APP_CONTROL_MAX_PKT_SIZE (64)
|
|
#define DEV_DESC_MAX_PACKET_SIZE (7)
|
|
#define DISK_FS_MAX_PACKET_SIZE (64)
|
|
#define DISK_HS_MAX_PACKET_SIZE (512)
|
|
|
|
#define CFG_DESC_EP_IN_TYPE_OFFSET (21)
|
|
#define CFG_DESC_EP_IN_MAX_PACKET_SIZE_OFFSET (22)
|
|
#define CFG_DESC_EP_OUT_TYPE_OFFSET (28)
|
|
#define CFG_DESC_EP_OUT_MAX_PACKET_SIZE_OFFSET (29)
|
|
|
|
#define TOTAL_LOGICAL_ADDRESS_BLOCKS (4096)
|
|
#define LENGTH_OF_EACH_LAB (512)
|
|
|
|
#define DISK_IN_EP_NO 1
|
|
#define DISK_OUT_EP_NO 2
|
|
|
|
#define DISK_IN_EP_TYPE 2 /* Bulk */
|
|
#define DISK_OUT_EP_TYPE 2 /* Bulk */
|
|
|
|
typedef struct
|
|
{
|
|
_usb_device_handle usbDevHandle; /* Must be first field */
|
|
uint_32 devNo;
|
|
uint_8_ptr Send_Buffer_Unaligned;
|
|
|
|
uint_8_ptr DevDesc;
|
|
uint_8_ptr DevQualifierDesc;
|
|
uint_8_ptr ConfigDesc;
|
|
uint_8_ptr other_speed_config;
|
|
uint_8_ptr ep1_buf;
|
|
uint_8_ptr epTemp_buf;
|
|
DISK_READ_CAPACITY* pReadCapacity;
|
|
CSW_STRUCT* pCSW;
|
|
uint_8_ptr MASS_STORAGE_DISK;
|
|
|
|
SETUP_STRUCT local_setup_packet;
|
|
|
|
volatile boolean TEST_ENABLED;
|
|
volatile boolean ENTER_TEST_MODE;
|
|
volatile uint_16 test_mode_index;
|
|
volatile uint_8 speed;
|
|
uint_16 logicalBlocks;
|
|
uint_32 hsMaxPktSize;
|
|
uint_32 fsMaxPktSize;
|
|
|
|
uint_32 inEpType;
|
|
uint_32 outEpType;
|
|
|
|
uint_32 inEpNo;
|
|
uint_32 outEpNo;
|
|
boolean CBW_PROCESSED;
|
|
boolean ZERO_TERMINATE;
|
|
|
|
} USB_DISK_STRUCT;
|
|
|
|
uint_32 diskHsMaxPktSize = DISK_HS_MAX_PACKET_SIZE;
|
|
uint_32 diskFsMaxPktSize = DISK_FS_MAX_PACKET_SIZE;
|
|
|
|
uint_32 diskInEpType = DISK_IN_EP_TYPE;
|
|
uint_32 diskOutEpType = DISK_OUT_EP_TYPE;
|
|
|
|
uint_32 diskInEpNo = DISK_IN_EP_NO;
|
|
uint_32 diskOutEpNo = DISK_OUT_EP_NO;
|
|
|
|
static USB_DISK_STRUCT* usbDisksPtr[MAX_USB_DEVICES] = { NULL, NULL };
|
|
|
|
/**************************************************************************
|
|
DESCRIPTORS DESCRIPTORS DESCRIPTORS DESCRIPTORS DESCRIPTORS DESCRIPTORS
|
|
**************************************************************************/
|
|
|
|
#define DEVICE_DESCRIPTOR_SIZE 18
|
|
static const uint_8 DevDescData[DEVICE_DESCRIPTOR_SIZE] =
|
|
{
|
|
/* Length of DevDesc */
|
|
DEVICE_DESCRIPTOR_SIZE,
|
|
/* "Device" Type of descriptor */
|
|
1,
|
|
/* BCD USB version */
|
|
0, 2,
|
|
/* Device Class is indicated in the interface descriptors */
|
|
0x00,
|
|
/* Device Subclass is indicated in the interface descriptors */
|
|
0x00,
|
|
/* Mass storage devices do not use class-specific protocols */
|
|
0x00,
|
|
/* Max packet size */
|
|
APP_CONTROL_MAX_PKT_SIZE,
|
|
/* Vendor ID */
|
|
USB_uint_16_low(0x1286), USB_uint_16_high(0x1286),
|
|
/* Product ID */
|
|
USB_uint_16_low(0x1), USB_uint_16_high(0x1),
|
|
/* BCD Device version */
|
|
USB_uint_16_low(0x0002), USB_uint_16_high(0x0002),
|
|
/* Manufacturer string index */
|
|
0x1,
|
|
/* Product string index */
|
|
0x2,
|
|
/* Serial number string index */
|
|
0x6,
|
|
/* Number of configurations available */
|
|
0x1
|
|
};
|
|
|
|
/* USB 2.0 specific descriptor */
|
|
#define DEVICE_QUALIFIER_DESCRIPTOR_SIZE 10
|
|
static const uint_8 DevQualifierDescData[DEVICE_QUALIFIER_DESCRIPTOR_SIZE] =
|
|
{
|
|
DEVICE_QUALIFIER_DESCRIPTOR_SIZE, /* bLength Length of this descriptor */
|
|
6, /* bDescType This is a DEVICE Qualifier descr */
|
|
0,2, /* bcdUSB USB revision 2.0 */
|
|
0, /* bDeviceClass */
|
|
0, /* bDeviceSubClass */
|
|
0, /* bDeviceProtocol */
|
|
APP_CONTROL_MAX_PKT_SIZE, /* bMaxPacketSize0 */
|
|
0x01, /* bNumConfigurations */
|
|
0
|
|
};
|
|
|
|
#define CONFIG_DESC_NUM_INTERFACES (4)
|
|
/* This must be counted manually and updated with the descriptor */
|
|
/* 1*Config(9) + 1*Interface(9) + 2*Endpoint(7) = 32 bytes */
|
|
#define CONFIG_DESC_SIZE (32)
|
|
|
|
/**************************************************************
|
|
we declare the config desc as USB_Uncached because this descriptor
|
|
is updated on the fly for max packet size during enumeration. Making
|
|
it uncached ensures that main memory is updated whenever this
|
|
descriptor pointer is used.
|
|
**************************************************************/
|
|
static const uint_8 ConfigDescData[CONFIG_DESC_SIZE] =
|
|
{
|
|
/* Configuration Descriptor - always 9 bytes */
|
|
9,
|
|
/* "Configuration" type of descriptor */
|
|
2,
|
|
/* Total length of the Configuration descriptor */
|
|
USB_uint_16_low(CONFIG_DESC_SIZE),
|
|
USB_uint_16_high(CONFIG_DESC_SIZE),
|
|
/* NumInterfaces */
|
|
1,
|
|
/* Configuration Value */
|
|
1,
|
|
/* Configuration Description String Index*/
|
|
4,
|
|
/* Attributes. Self-powered. */
|
|
0xc0,
|
|
/* Current draw from bus */
|
|
0,
|
|
/* Interface 0 Descriptor - always 9 bytes */
|
|
9,
|
|
/* "Interface" type of descriptor */
|
|
4,
|
|
/* Number of this interface */
|
|
MASS_STORAGE_INTERFACE,
|
|
/* Alternate Setting */
|
|
0,
|
|
/* Number of endpoints on this interface */
|
|
2,
|
|
/* Interface Class */
|
|
0x08,
|
|
/* Interface Subclass: SCSI transparent command set */
|
|
0x06,
|
|
/* Interface Protocol: Bulk only protocol */
|
|
0x50,
|
|
/* Interface Description String Index */
|
|
0,
|
|
/* Endpoint 1 (Bulk In Endpoint), Interface 0 Descriptor - always 7 bytes*/
|
|
7,
|
|
/* "Endpoint" type of descriptor */
|
|
5,
|
|
/*
|
|
** Endpoint address. The low nibble contains the endpoint number and the
|
|
** high bit indicates TX(1) or RX(0).
|
|
*/
|
|
((ARC_USB_SEND<<7) | DISK_IN_EP_NO) /*0x81*/,
|
|
/* Attributes. 0=Control 1=Isochronous 2=Bulk 3=Interrupt */
|
|
DISK_IN_EP_TYPE,
|
|
/* Max Packet Size for this endpoint */
|
|
USB_uint_16_low(DISK_FS_MAX_PACKET_SIZE),
|
|
USB_uint_16_high(DISK_FS_MAX_PACKET_SIZE),
|
|
/* Polling Interval (ms) */
|
|
0,
|
|
/* Endpoint 2 (Bulk Out Endpoint), Interface 0 Descriptor - always 7 bytes*/
|
|
7,
|
|
/* "Endpoint" type of descriptor */
|
|
5,
|
|
/*
|
|
** Endpoint address. The low nibble contains the endpoint number and the
|
|
** high bit indicates TX(1) or RX(0).
|
|
*/
|
|
((ARC_USB_RECV<<7) | DISK_OUT_EP_NO), /*0x02*/
|
|
/* Attributes. 0=Control 1=Isochronous 2=Bulk 3=Interrupt */
|
|
DISK_OUT_EP_TYPE,
|
|
/* Max Packet Size for this endpoint */
|
|
USB_uint_16_low(DISK_FS_MAX_PACKET_SIZE),
|
|
USB_uint_16_high(DISK_FS_MAX_PACKET_SIZE),
|
|
/* Polling Interval (ms) */
|
|
0
|
|
};
|
|
|
|
#define OTHER_SPEED_CONFIG_DESC_SIZE CONFIG_DESC_SIZE
|
|
static const uint_8 other_speed_config_data[CONFIG_DESC_SIZE] =
|
|
{
|
|
9, /* bLength Length of this descriptor */
|
|
7, /* bDescType This is a Other speed config descr */
|
|
USB_uint_16_low(OTHER_SPEED_CONFIG_DESC_SIZE),
|
|
USB_uint_16_high(OTHER_SPEED_CONFIG_DESC_SIZE),
|
|
1,
|
|
1,
|
|
4,
|
|
0xc0,
|
|
0,
|
|
/* Interface 0 Descriptor - always 9 bytes */
|
|
9,
|
|
/* "Interface" type of descriptor */
|
|
4,
|
|
/* Number of this interface */
|
|
MASS_STORAGE_INTERFACE,
|
|
/* Alternate Setting */
|
|
0,
|
|
/* Number of endpoints on this interface */
|
|
2,
|
|
/* Interface Class */
|
|
0x08,
|
|
/* Interface Subclass: SCSI transparent command set */
|
|
0x06,
|
|
/* Interface Protocol: Bulk only protocol */
|
|
0x50,
|
|
/* Interface Description String Index */
|
|
0,
|
|
/* Endpoint 1 (Bulk In Endpoint), Interface 0 Descriptor - always 7 bytes*/
|
|
7,
|
|
/* "Endpoint" type of descriptor */
|
|
5,
|
|
/*
|
|
** Endpoint address. The low nibble contains the endpoint number and the
|
|
** high bit indicates TX(1) or RX(0).
|
|
*/
|
|
((ARC_USB_SEND<<7) | DISK_IN_EP_NO), /*0x81*/
|
|
/* Attributes. 0=Control 1=Isochronous 2=Bulk 3=Interrupt */
|
|
DISK_IN_EP_TYPE,
|
|
/* Max Packet Size for this endpoint */
|
|
USB_uint_16_low(DISK_HS_MAX_PACKET_SIZE),
|
|
USB_uint_16_high(DISK_HS_MAX_PACKET_SIZE),
|
|
/* Polling Interval (ms) */
|
|
0,
|
|
/* Endpoint 2 (Bulk Out Endpoint), Interface 0 Descriptor - always 7 bytes*/
|
|
7,
|
|
/* "Endpoint" type of descriptor */
|
|
5,
|
|
/*
|
|
** Endpoint address. The low nibble contains the endpoint number and the
|
|
** high bit indicates TX(1) or RX(0).
|
|
*/
|
|
((ARC_USB_RECV<<7) | DISK_OUT_EP_NO), /*0x02*/
|
|
|
|
/* Attributes. 0=Control 1=Isochronous 2=Bulk 3=Interrupt */
|
|
DISK_OUT_EP_TYPE,
|
|
/* Max Packet Size for this endpoint */
|
|
USB_uint_16_low(DISK_HS_MAX_PACKET_SIZE),
|
|
USB_uint_16_high(DISK_HS_MAX_PACKET_SIZE),
|
|
/* Polling Interval (ms) */
|
|
0
|
|
};
|
|
|
|
static uint_8 USB_IF_ALT[4] = { 0, 0, 0, 0};
|
|
|
|
/* number of strings in the table not including 0 or n. */
|
|
static const uint_8 USB_STR_NUM = 7;
|
|
|
|
/*
|
|
** if the number of strings changes, look for USB_STR_0 everywhere and make
|
|
** the obvious changes. It should be found in 3 places.
|
|
*/
|
|
|
|
static uint_16 USB_STR_0[ 2] = {(0x300 + sizeof(USB_STR_0)),(0x0409)};
|
|
static uint_16 USB_STR_1[26] = {(0x300 + sizeof(USB_STR_1)),
|
|
'M','a','r','v','e','l','l',' ','S','e','m','i','c','o','n','d','u','c','t','o','r',' ','L','t','d'};
|
|
static uint_16 USB_STR_2[28] = {(0x300 + sizeof(USB_STR_2)),
|
|
'M','A','R','V','E','L','L',' ','M','a','s','s',' ','S','t','o','r','a','g','e',' ',\
|
|
'D','e','v','i','c','e'};
|
|
static uint_16 USB_STR_3[ 5] = {(0x300 + sizeof(USB_STR_3)),
|
|
'B','E','T','A'};
|
|
static uint_16 USB_STR_4[ 4] = {(0x300 + sizeof(USB_STR_4)),
|
|
'#','0','2'};
|
|
static uint_16 USB_STR_5[ 4] = {(0x300 + sizeof(USB_STR_5)),
|
|
'_','A','1'};
|
|
/* Serial number has to be at least 12 bytes */
|
|
static uint_16 USB_STR_6[ 13] = {(0x300 + sizeof(USB_STR_6)),
|
|
'0','0','0','0','0','0','0','0','0','0','0','1'};
|
|
static uint_16 USB_STR_7[15] = {(0x300 + sizeof(USB_STR_7)),
|
|
'Y','o','u','r',' ','n','a','m','e',' ','h','e','r','e'};
|
|
static uint_16 USB_STR_n[17] = {(0x300 + sizeof(USB_STR_n)),
|
|
'B','A','D',' ','S','T','R','I','N','G',' ','I','n','d','e','x'};
|
|
|
|
#define USB_STRING_ARRAY_SIZE 9
|
|
static uint_8_ptr USB_STRING_DESC[USB_STRING_ARRAY_SIZE] =
|
|
{
|
|
(uint_8_ptr)((pointer)USB_STR_0),
|
|
(uint_8_ptr)((pointer)USB_STR_1),
|
|
(uint_8_ptr)((pointer)USB_STR_2),
|
|
(uint_8_ptr)((pointer)USB_STR_3),
|
|
(uint_8_ptr)((pointer)USB_STR_4),
|
|
(uint_8_ptr)((pointer)USB_STR_5),
|
|
(uint_8_ptr)((pointer)USB_STR_6),
|
|
(uint_8_ptr)((pointer)USB_STR_7),
|
|
(uint_8_ptr)((pointer)USB_STR_n)
|
|
};
|
|
|
|
/*****************************************************************
|
|
MASS STORAGE SPECIFIC GLOBALS
|
|
*****************************************************************/
|
|
|
|
static const DISK_DEVICE_INFO device_information_data =
|
|
{
|
|
0, 0x80, 0, 0x01, 0x1F,
|
|
/* Reserved */
|
|
{0, 0, 0},
|
|
/* Vendor information: "MARVELL " */
|
|
{0x4D, 0x41, 0x52, 0x56, 0x45, 0x4C, 0x4C, 0x20,},
|
|
/* Product information: "Disk " */
|
|
{0x44, 0x69, 0x73, 0x6B, 0x20, 0x20, 0x20, 0x20,
|
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20},
|
|
/* Product Revision level: "Demo" */
|
|
{0x44, 0x65, 0x6D, 0x6F}
|
|
};
|
|
|
|
static const DISK_READ_CAPACITY read_capacity =
|
|
{
|
|
/* Data for the capacity */
|
|
{
|
|
0x00, 0x00, USB_uint_16_high(TOTAL_LOGICAL_ADDRESS_BLOCKS-14),
|
|
USB_uint_16_low(TOTAL_LOGICAL_ADDRESS_BLOCKS-14)
|
|
},
|
|
{
|
|
0x00, 0x00, USB_uint_16_high(LENGTH_OF_EACH_LAB),
|
|
USB_uint_16_low(LENGTH_OF_EACH_LAB)
|
|
}
|
|
};
|
|
|
|
static const uint_8 BOOT_SECTOR_AREA[512] =
|
|
{
|
|
/* Block 0 is the boot sector. Following is the data in the boot sector */
|
|
/* 80x86 "short: jump instruction, indicating that the disk is formatted */
|
|
0xEB,
|
|
/* 8-bit displacement */
|
|
0x3C,
|
|
/* NOP OPCode */
|
|
0x90,
|
|
/* 8-bytes for OEM identification: "ARC 4.3 " */
|
|
0x41, 0x52, 0x43, 0x20, 0x34, 0x2E, 0x33, 0x20,
|
|
/* bytes/sector: 512 bytes (0x0200) */
|
|
0x00, 0x02,
|
|
/* Sectors/allocation unit */
|
|
0x01,
|
|
/* Reserved sectors: 0x0001 */
|
|
0x01, 0x00,
|
|
/* Number of File Allocation Tables (FATs): 2 */
|
|
0x02,
|
|
/* Number of root directory entries */
|
|
0x00, 0x02,
|
|
/* Total Small sectors in logical volume */
|
|
USB_uint_16_low(TOTAL_LOGICAL_ADDRESS_BLOCKS),
|
|
USB_uint_16_high(TOTAL_LOGICAL_ADDRESS_BLOCKS),
|
|
/* Media descriptor byte: 0xF8: Fixed disk */
|
|
0xF8,
|
|
/* Sectors/FAT: 3 (Each FAT starts at a new sector) */
|
|
0x80, 0x00,
|
|
/* Sectors/track: 9 */
|
|
0x09, 0x00,
|
|
/* Number of heads */
|
|
0x02, 0x00,
|
|
/* Number of hidden sectors: 0 */
|
|
0x00, 0x00, 0x00, 0x00,
|
|
/* Total Large sectors in logical volume */
|
|
0x00, 0x00, 0x00, 0x00,
|
|
/* Physical drive number */
|
|
0x00,
|
|
/* Reserved */
|
|
0x00,
|
|
/* Extended boot signature record: 0x29 */
|
|
0x29,
|
|
/* 32-bit binary volume ID */
|
|
0x01, 0x02, 0x03, 0x04,
|
|
/* Volume label */
|
|
0x53, 0x54, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
|
/* Reserved FAT-16*/
|
|
0x46, 0x41, 0x54, 0x31, 0x36, 0x00, 0x00, 0x00,
|
|
/* Bootstrap */
|
|
0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFC, 0xE8, 0x45, 0x00,
|
|
/* String: \r\nNon-System disk\r\nPress any key to reboot\r\n" */
|
|
0x0D, 0x0A, 0x4E, 0x6F, 0x6E, 0x2D, 0x53, 0x79, 0x73, 0x74, 0x65,
|
|
0x6D, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x0D, 0x0A, 0x50, 0x72, 0x65,
|
|
0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20,
|
|
0x74, 0x6F, 0x20, 0x72, 0x65, 0x62, 0x6F, 0x6F, 0x74, 0x0D, 0x0A,
|
|
0x5E, 0xEB, 0x02, 0xCD, 0x10, 0xB4, 0x0E, 0xBB, 0x07, 0x00, 0x2E,
|
|
0xAC, 0x84, 0xC0, 0x75, 0xF3, 0x98, 0xCD, 0x16, 0xCD, 0x19, 0xEB,
|
|
0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/* Partition descriptors */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
|
|
};
|
|
|
|
|
|
static const uint_8 FAT16_SPECIAL_BYTES[3] =
|
|
{
|
|
/* FAT ID: Same as Media descriptor */
|
|
0xF8, 0xFF, 0xFF
|
|
};
|
|
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9GetDescription
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Chapter 9 GetDescription command
|
|
* The Device Request can ask for Device/Config/string/interface/endpoint
|
|
* descriptors (via wValue). We then post an IN response to return the
|
|
* requested descriptor.
|
|
* And then wait for the OUT which terminates the control transfer.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9GetDescription
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
uint_32 max_pkt_size;
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk %s: setup=%d, value=0x%x, length=%d\n",
|
|
__FUNCTION__, (int)setup, setup_ptr->VALUE, setup_ptr->LENGTH);
|
|
|
|
if (setup)
|
|
{
|
|
/* Load the appropriate string depending on the descriptor requested.*/
|
|
switch (setup_ptr->VALUE & 0xFF00)
|
|
{
|
|
case 0x0100:
|
|
_usb_device_send_data(handle, 0, pDiskCtrl->DevDesc,
|
|
MIN(setup_ptr->LENGTH, DEVICE_DESCRIPTOR_SIZE));
|
|
break;
|
|
|
|
case 0x0200:
|
|
/* Set the Max Packet Size in the config and other speed config */
|
|
if(pDiskCtrl->speed == ARC_USB_SPEED_HIGH)
|
|
{
|
|
max_pkt_size = pDiskCtrl->hsMaxPktSize;
|
|
}
|
|
else
|
|
{
|
|
max_pkt_size = pDiskCtrl->fsMaxPktSize;
|
|
} /* Endif */
|
|
|
|
*(pDiskCtrl->ConfigDesc + CFG_DESC_EP_IN_TYPE_OFFSET) = (uint_8)pDiskCtrl->inEpType;
|
|
|
|
*(pDiskCtrl->ConfigDesc + CFG_DESC_EP_IN_MAX_PACKET_SIZE_OFFSET) =
|
|
USB_uint_16_low(max_pkt_size);
|
|
*(pDiskCtrl->ConfigDesc + CFG_DESC_EP_IN_MAX_PACKET_SIZE_OFFSET+1) =
|
|
USB_uint_16_high(max_pkt_size);
|
|
|
|
*(pDiskCtrl->ConfigDesc + CFG_DESC_EP_OUT_TYPE_OFFSET) = (uint_8)pDiskCtrl->outEpType;
|
|
|
|
*(pDiskCtrl->ConfigDesc + CFG_DESC_EP_OUT_MAX_PACKET_SIZE_OFFSET) =
|
|
USB_uint_16_low(max_pkt_size);
|
|
*(pDiskCtrl->ConfigDesc + CFG_DESC_EP_OUT_MAX_PACKET_SIZE_OFFSET+1) =
|
|
USB_uint_16_high(max_pkt_size);
|
|
|
|
_usb_device_send_data(handle, 0, pDiskCtrl->ConfigDesc,
|
|
MIN(setup_ptr->LENGTH, CONFIG_DESC_SIZE));
|
|
break;
|
|
|
|
case 0x0300:
|
|
if ((setup_ptr->VALUE & 0x00FF) > USB_STR_NUM) {
|
|
_usb_device_send_data(handle, 0, USB_STRING_DESC[USB_STR_NUM+1],
|
|
MIN(setup_ptr->LENGTH, USB_STRING_DESC[USB_STR_NUM+1][0]));
|
|
}
|
|
else
|
|
{
|
|
_usb_device_send_data(handle, 0, USB_STRING_DESC[setup_ptr->VALUE & 0x00FF],
|
|
MIN(setup_ptr->LENGTH, USB_STRING_DESC[setup_ptr->VALUE & 0x00FF][0]));
|
|
} /* Endif */
|
|
break;
|
|
|
|
case 0x600:
|
|
_usb_device_send_data(handle, 0, (uint_8_ptr)pDiskCtrl->DevQualifierDesc,
|
|
MIN(setup_ptr->LENGTH, DEVICE_QUALIFIER_DESCRIPTOR_SIZE));
|
|
break;
|
|
|
|
case 0x700:
|
|
if(pDiskCtrl->speed == ARC_USB_SPEED_HIGH)
|
|
{
|
|
max_pkt_size = pDiskCtrl->fsMaxPktSize;
|
|
}
|
|
else
|
|
{
|
|
max_pkt_size = pDiskCtrl->hsMaxPktSize;
|
|
} /* Endif */
|
|
|
|
*(pDiskCtrl->other_speed_config + CFG_DESC_EP_IN_TYPE_OFFSET) = (uint_8)pDiskCtrl->inEpType;
|
|
|
|
*(pDiskCtrl->other_speed_config + CFG_DESC_EP_IN_MAX_PACKET_SIZE_OFFSET) =
|
|
USB_uint_16_low(max_pkt_size);
|
|
*(pDiskCtrl->other_speed_config + CFG_DESC_EP_IN_MAX_PACKET_SIZE_OFFSET+1) =
|
|
USB_uint_16_high(max_pkt_size);
|
|
|
|
*(pDiskCtrl->other_speed_config + CFG_DESC_EP_OUT_TYPE_OFFSET) = (uint_8)pDiskCtrl->outEpType;
|
|
|
|
*(pDiskCtrl->other_speed_config + CFG_DESC_EP_OUT_MAX_PACKET_SIZE_OFFSET) =
|
|
USB_uint_16_low(max_pkt_size);
|
|
*(pDiskCtrl->other_speed_config + CFG_DESC_EP_OUT_MAX_PACKET_SIZE_OFFSET+1) =
|
|
USB_uint_16_high(max_pkt_size);
|
|
|
|
_usb_device_send_data(handle, 0, (uint_8_ptr)pDiskCtrl->other_speed_config,
|
|
MIN(setup_ptr->LENGTH, OTHER_SPEED_CONFIG_DESC_SIZE));
|
|
|
|
break;
|
|
|
|
default:
|
|
USB_printf("usbDisk_%d, %s: Unexpected VALUE=0x%04x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->VALUE);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
return;
|
|
} /* Endswitch */
|
|
/* status phase */
|
|
_usb_device_recv_data(handle, 0, NULL, 0);
|
|
} /* Endif */
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9SetDescription
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Chapter 9 SetDescription command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9SetDescription
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
USB_printf("usbDisk_%d, %s: setup=%d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, (int)setup);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9GetConfig
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Chapter 9 GetConfig command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9GetConfig
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
uint_16 current_config;
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk %s: setup=%d\n", __FUNCTION__, (int)setup);
|
|
|
|
/* Return the currently selected configuration */
|
|
if (setup)
|
|
{
|
|
_usb_device_get_status(handle, ARC_USB_STATUS_CURRENT_CONFIG,
|
|
¤t_config);
|
|
*pDiskCtrl->epTemp_buf = (current_config & 0xFF);
|
|
_usb_device_send_data(handle, 0, pDiskCtrl->epTemp_buf, sizeof(uint_8));
|
|
/* status phase */
|
|
_usb_device_recv_data(handle, 0, NULL, 0);
|
|
} /* Endif */
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9SetConfig
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Chapter 9 SetConfig command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9SetConfig
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
uint_16 usb_state;
|
|
uint_32 max_pkt_size;
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk %s: setup=%d, value=0x%x\n",
|
|
__FUNCTION__, (int)setup, setup_ptr->VALUE);
|
|
|
|
if (setup)
|
|
{
|
|
if ((setup_ptr->VALUE & 0x00FF) > 1)
|
|
{
|
|
/* generate stall */
|
|
USB_printf("usbDisk_%d, %s: Wrong VALUE=0x%04x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->VALUE);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
return;
|
|
} /* Endif */
|
|
|
|
/* 0 indicates return to unconfigured state */
|
|
if ((setup_ptr->VALUE & 0x00FF) == 0)
|
|
{
|
|
_usb_device_get_status(handle, ARC_USB_STATUS_DEVICE_STATE, &usb_state);
|
|
if( (usb_state == ARC_USB_STATE_CONFIG) ||
|
|
(usb_state == ARC_USB_STATE_ADDRESS) )
|
|
{
|
|
/* clear the currently selected config value */
|
|
_usb_device_set_status(handle, ARC_USB_STATUS_CURRENT_CONFIG, 0);
|
|
_usb_device_set_status(handle, ARC_USB_STATUS_DEVICE_STATE,
|
|
ARC_USB_STATE_ADDRESS);
|
|
/* status phase */
|
|
_usb_device_send_data(handle, 0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong usb_state=%d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, usb_state);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
} /* Endif */
|
|
return;
|
|
} /* Endif */
|
|
|
|
/*
|
|
** If the configuration value (setup_ptr->VALUE & 0x00FF) differs
|
|
** from the current configuration value, then endpoints must be
|
|
** reconfigured to match the new device configuration
|
|
*/
|
|
_usb_device_get_status(handle, ARC_USB_STATUS_CURRENT_CONFIG,
|
|
&usb_state);
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk: Set configuration: old=%d, new=%d\n",
|
|
usb_state, setup_ptr->VALUE & 0x00FF);
|
|
|
|
if (usb_state != (setup_ptr->VALUE & 0x00FF))
|
|
{
|
|
/* Reconfigure endpoints here */
|
|
switch (setup_ptr->VALUE & 0x00FF)
|
|
{
|
|
default:
|
|
break;
|
|
} /* Endswitch */
|
|
|
|
_usb_device_set_status(handle, ARC_USB_STATUS_CURRENT_CONFIG,
|
|
setup_ptr->VALUE & 0x00FF);
|
|
} /* Endif */
|
|
|
|
if (pDiskCtrl->speed == ARC_USB_SPEED_HIGH)
|
|
{
|
|
max_pkt_size = pDiskCtrl->hsMaxPktSize;
|
|
}
|
|
else
|
|
{
|
|
max_pkt_size = pDiskCtrl->fsMaxPktSize;
|
|
} /* Endif */
|
|
|
|
_usb_device_init_endpoint(handle, pDiskCtrl->outEpNo, max_pkt_size,
|
|
ARC_USB_RECV, ARC_USB_BULK_ENDPOINT, ARC_USB_DEVICE_DONT_ZERO_TERMINATE);
|
|
_usb_device_init_endpoint(handle, pDiskCtrl->inEpNo, max_pkt_size,
|
|
ARC_USB_SEND, ARC_USB_BULK_ENDPOINT, ARC_USB_DEVICE_DONT_ZERO_TERMINATE);
|
|
|
|
if (_usb_device_get_transfer_status(handle, pDiskCtrl->outEpNo, ARC_USB_RECV) == USB_OK)
|
|
{
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
} /* Endif */
|
|
|
|
pDiskCtrl->TEST_ENABLED = TRUE;
|
|
|
|
_usb_device_set_status(handle, ARC_USB_STATUS_DEVICE_STATE,
|
|
ARC_USB_STATE_CONFIG);
|
|
/* status phase */
|
|
_usb_device_send_data(handle, 0, 0, 0);
|
|
|
|
USB_printf("USB %s speed disk: config = %d\n",
|
|
(pDiskCtrl->speed == ARC_USB_SPEED_HIGH) ? "High" : "Full",
|
|
setup_ptr->VALUE & 0x00FF);
|
|
|
|
} /* Endif */
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9GetInterface
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Chapter 9 GetInterface command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9GetInterface
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
uint_16 usb_state;
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk %s: setup=%d\n", __FUNCTION__, (int)setup);
|
|
|
|
_usb_device_get_status(handle, ARC_USB_STATUS_DEVICE_STATE, &usb_state);
|
|
if (usb_state != ARC_USB_STATE_CONFIG)
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong usb_state=%d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, usb_state);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
return;
|
|
} /* Endif */
|
|
|
|
if (setup)
|
|
{
|
|
_usb_device_send_data(handle, 0, &USB_IF_ALT[setup_ptr->INDEX & 0x00FF],
|
|
MIN(setup_ptr->LENGTH, sizeof(uint_8)));
|
|
/* status phase */
|
|
_usb_device_recv_data(handle, 0, NULL, 0);
|
|
} /* Endif */
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9SetInterface
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Chapter 9 SetInterface command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9SetInterface
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk %s: setup=%d\n", __FUNCTION__, (int)setup);
|
|
|
|
if (setup)
|
|
{
|
|
if (setup_ptr->REQUESTTYPE != 0x01)
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong REQUESTTYPE=0x%02x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__,
|
|
setup_ptr->REQUESTTYPE);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
return;
|
|
} /* Endif */
|
|
|
|
/*
|
|
** If the alternate value (setup_ptr->VALUE & 0x00FF) differs
|
|
** from the current alternate value for the specified interface,
|
|
** then endpoints must be reconfigured to match the new alternate
|
|
*/
|
|
if (USB_IF_ALT[setup_ptr->INDEX & 0x00FF]
|
|
!= (setup_ptr->VALUE & 0x00FF))
|
|
{
|
|
USB_IF_ALT[setup_ptr->INDEX & 0x00FF] = (setup_ptr->VALUE & 0x00FF);
|
|
/* Reconfigure endpoints here. */
|
|
|
|
} /* Endif */
|
|
|
|
/* status phase */
|
|
_usb_device_send_data(handle, 0, 0, 0);
|
|
} /* Endif */
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9SynchFrame
|
|
* Returned Value :
|
|
* Comments :
|
|
* Chapter 9 SynchFrame command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9SynchFrame
|
|
(
|
|
/* USB handle */
|
|
_usb_device_handle handle,
|
|
|
|
/* Is it a Setup phase? */
|
|
boolean setup,
|
|
|
|
/* The setup packet pointer */
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
|
|
uint_16 usbStatus;
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "usbDisk %s: setup=%d\n",
|
|
__FUNCTION__, (int)setup);
|
|
|
|
if (setup)
|
|
{
|
|
if (setup_ptr->REQUESTTYPE != (REQ_RECIP_ENDPOINT | REQ_TYPE_STANDARD | REQ_DIR_OUT) )
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong REQUESTTYPE=0x%02x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__,
|
|
setup_ptr->REQUESTTYPE);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
return;
|
|
} /* Endif */
|
|
|
|
if ((setup_ptr->INDEX & 0x00FF) >=
|
|
pDiskCtrl->ConfigDesc[CONFIG_DESC_NUM_INTERFACES])
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong INDEX=0x%02x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->INDEX);
|
|
_usb_device_stall_endpoint(handle, 0, ARC_USB_RECV);
|
|
return;
|
|
} /* Endif */
|
|
|
|
_usb_device_get_status(handle, ARC_USB_STATUS_SOF_COUNT, &usbStatus);
|
|
pDiskCtrl->epTemp_buf[0] = USB_uint_16_low(usbStatus);
|
|
pDiskCtrl->epTemp_buf[1] = USB_uint_16_high(usbStatus);
|
|
_usb_device_send_data(handle, 0, pDiskCtrl->epTemp_buf, MIN(setup_ptr->LENGTH, sizeof(uint_16)));
|
|
/* status phase */
|
|
_usb_device_recv_data(handle, 0, NULL, 0);
|
|
} /* Endif */
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : ch9Class
|
|
* Returned Value :
|
|
* Comments :
|
|
* Chapter 9 Class specific request
|
|
* See section 9.4.11 (page 195) of the USB 1.1 Specification.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void ch9Class
|
|
(
|
|
_usb_device_handle handle,
|
|
boolean setup,
|
|
uint_8 direction,
|
|
SETUP_STRUCT_PTR setup_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_CLASS,
|
|
"usbDisk %s: setup=%d, request=0x%x, value=%d, index=%d, size=%d\n",
|
|
__FUNCTION__, (int)setup, setup_ptr->REQUEST,
|
|
setup_ptr->VALUE, setup_ptr->INDEX, setup_ptr->LENGTH);
|
|
|
|
if (setup)
|
|
{
|
|
switch (setup_ptr->REQUEST)
|
|
{
|
|
case 0xFF:
|
|
/* Bulk-Only Mass Storage Reset: Ready the device for the next
|
|
** CBW from the host
|
|
*/
|
|
if ((setup_ptr->VALUE != 0) ||
|
|
(setup_ptr->INDEX != MASS_STORAGE_INTERFACE) ||
|
|
(setup_ptr->LENGTH != 0))
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong Setup: VALUE=%d, INDEX=%d, LENGTH=%d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->VALUE,
|
|
setup_ptr->INDEX, setup_ptr->LENGTH);
|
|
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
}
|
|
else
|
|
{ /* Body */
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
pDiskCtrl->ZERO_TERMINATE = FALSE;
|
|
_usb_device_cancel_transfer(handle, pDiskCtrl->outEpNo, ARC_USB_RECV);
|
|
_usb_device_cancel_transfer(handle, pDiskCtrl->inEpNo, ARC_USB_SEND);
|
|
|
|
/* unstall bulk endpoint */
|
|
_usb_device_unstall_endpoint(handle, pDiskCtrl->outEpNo, ARC_USB_RECV);
|
|
_usb_device_unstall_endpoint(handle, pDiskCtrl->inEpNo, ARC_USB_SEND);
|
|
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
/* send zero packet to control pipe */
|
|
_usb_device_send_data(handle, 0, NULL, 0);
|
|
} /* Endbody */
|
|
break;
|
|
|
|
case 0xFE:
|
|
/* For Get Max LUN use any of these responses*/
|
|
if (setup_ptr->LENGTH == 0)
|
|
{ /* Body */
|
|
|
|
USB_printf("usbDisk_%d, %s: Wrong Length: LENGTH=%d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->LENGTH);
|
|
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
if ((setup_ptr->VALUE != 0) ||
|
|
(setup_ptr->INDEX != MASS_STORAGE_INTERFACE) ||
|
|
(setup_ptr->LENGTH != 1))
|
|
{ /* Body */
|
|
USB_printf("usbDisk_%d, %s: Wrong Setup: VALUE=%d, INDEX=%d, LENGTH=%d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->VALUE,
|
|
setup_ptr->INDEX, setup_ptr->LENGTH);
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
}
|
|
else
|
|
{ /* Body */
|
|
/* Send Max LUN = 0 to the the control pipe */
|
|
*pDiskCtrl->epTemp_buf = 0;
|
|
_usb_device_send_data(handle, 0, pDiskCtrl->epTemp_buf, 1);
|
|
/* status phase */
|
|
_usb_device_recv_data(handle, 0, 0, 0);
|
|
} /* Endbody */
|
|
}
|
|
break;
|
|
|
|
default :
|
|
USB_printf("usbDisk_%d, %s: Wrong REQUEST=0x%02x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, setup_ptr->REQUEST);
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
return;
|
|
} /* EndSwitch */
|
|
}
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : service_ep0
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Called upon a completed endpoint 0 (USB 1.1 Chapter 9) transfer
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void service_ep0
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] request type as registered */
|
|
uint_8 type,
|
|
|
|
/* [IN] Is it a setup packet? */
|
|
boolean setup,
|
|
|
|
/* [IN] Direction of the transfer. Is it transmit? */
|
|
uint_8 direction,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
uint_8_ptr buffer,
|
|
|
|
/* [IN] Length of the transfer */
|
|
uint_32 length,
|
|
|
|
/* [IN] Error, if any */
|
|
uint_8 error
|
|
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
SETUP_STRUCT* pSetupPacket = &pDiskCtrl->local_setup_packet;
|
|
|
|
if (setup)
|
|
{
|
|
_usb_device_read_setup_data(handle, 0, (uint_8_ptr)pSetupPacket);
|
|
pSetupPacket->VALUE = USB_16BIT_LE(pSetupPacket->VALUE);
|
|
pSetupPacket->INDEX = USB_16BIT_LE(pSetupPacket->INDEX);
|
|
pSetupPacket->LENGTH = USB_16BIT_LE(pSetupPacket->LENGTH);
|
|
}
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_EP0,
|
|
"disk %s: setup=%s, dir=%s, pBuf=0x%x, length=%d, reqType=0x%x, req=0x%x\n",
|
|
__FUNCTION__, (setup ? "YES" : "NO"),
|
|
(direction == ARC_USB_RECV) ? "RECV" : "SEND",
|
|
(unsigned)buffer, (int)length, pSetupPacket->REQUESTTYPE,
|
|
pSetupPacket->REQUEST);
|
|
|
|
switch (pSetupPacket->REQUESTTYPE & REQ_TYPE_MASK)
|
|
{
|
|
case REQ_TYPE_STANDARD:
|
|
switch (pSetupPacket->REQUEST)
|
|
{
|
|
case REQ_GET_STATUS:
|
|
mvUsbCh9GetStatus(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_CLEAR_FEATURE:
|
|
mvUsbCh9ClearFeature(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_SET_FEATURE:
|
|
mvUsbCh9SetFeature(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_SET_ADDRESS:
|
|
mvUsbCh9SetAddress(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_GET_DESCRIPTOR:
|
|
ch9GetDescription(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_SET_DESCRIPTOR:
|
|
ch9SetDescription(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_GET_CONFIGURATION:
|
|
ch9GetConfig(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_SET_CONFIGURATION:
|
|
ch9SetConfig(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_GET_INTERFACE:
|
|
ch9GetInterface(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_SET_INTERFACE:
|
|
ch9SetInterface(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
case REQ_SYNCH_FRAME:
|
|
ch9SynchFrame(handle, setup, pSetupPacket);
|
|
break;
|
|
|
|
default:
|
|
USB_printf("usbDisk_%d, %s: Wrong REQUEST = 0x%02x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, pSetupPacket->REQUEST);
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
break;
|
|
|
|
} /* Endswitch */
|
|
|
|
break;
|
|
|
|
case REQ_TYPE_CLASS:
|
|
/* class specific request */
|
|
ch9Class(handle, setup, direction, pSetupPacket);
|
|
return;
|
|
|
|
case REQ_TYPE_VENDOR:
|
|
/* vendor specific request can be handled here*/
|
|
USB_printf("usbDisk_%d, %s: Vendor REQUESTTYPE (%d) not supported\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, REQ_TYPE_VENDOR);
|
|
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
USB_printf("usbDisk_%d, %s: Unexpected REQUESTTYPE = 0x%x\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__,
|
|
pSetupPacket->REQUESTTYPE);
|
|
|
|
_usb_device_stall_endpoint(handle, 0, 0);
|
|
break;
|
|
|
|
} /* Endswitch */
|
|
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_inquiry_command
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Process a Mass storage class Inquiry command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_inquiry_command
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
if (cbw_ptr->DCBWDATALENGTH)
|
|
{
|
|
if (cbw_ptr->BMCBWFLAGS & USB_CBW_DIRECTION_BIT)
|
|
{
|
|
/* Send the device information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)&device_information_data, 36);
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
/* The actual length will never exceed the DCBWDATALENGTH */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH - 36);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_unsupported_command
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Responds appropriately to unsupported commands
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_unsupported_command
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK,
|
|
"disk unsupported command: BMCBWFLAGS = 0x%02x\n", cbw_ptr->BMCBWFLAGS);
|
|
|
|
/* The actual length will never exceed the DCBWDATALENGTH */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
|
|
if (cbw_ptr->BMCBWFLAGS & USB_CBW_DIRECTION_BIT)
|
|
{
|
|
/* Send a zero-length packet */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
} /* Endif */
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_report_capacity
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Reports the media capacity as a response to READ CAPACITY Command.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_report_capacity
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_CAP,
|
|
"disk read_capacity: BMCBWFLAGS = 0x%02x\n", cbw_ptr->BMCBWFLAGS);
|
|
|
|
if (cbw_ptr->BMCBWFLAGS & USB_CBW_DIRECTION_BIT)
|
|
{
|
|
/* Send a zero-length packet */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pReadCapacity, 8);
|
|
|
|
} /* Endif */
|
|
|
|
/* The actual length will never exceed the DCBWDATALENGTH */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_read_command
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Sends data as a response to READ Command.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_read_command
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
uint_32 index1 = 0, index2 = 0;
|
|
uint_32 max_pkt_size, byteSize;
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
if (cbw_ptr->BMCBWFLAGS & USB_CBW_DIRECTION_BIT)
|
|
{
|
|
/* Send a zero-length packet */
|
|
index1 = ((uint_32)cbw_ptr->CBWCB[4] << 8);
|
|
index1 |= cbw_ptr->CBWCB[5];
|
|
index2 = ((uint_32)cbw_ptr->CBWCB[7] << 8);
|
|
index2 |= (uint_32)cbw_ptr->CBWCB[8];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_READ,
|
|
"disk read: FLAGS=0x%02x, LENGTH=0x%x, index1=0x%x, index2=0x%x\n",
|
|
cbw_ptr->BMCBWFLAGS, cbw_ptr->DCBWDATALENGTH, index1, index2);
|
|
|
|
if(cbw_ptr->CBWCB[0] != 0x3E)
|
|
{
|
|
byteSize = index2 * LENGTH_OF_EACH_LAB;
|
|
}
|
|
else
|
|
{
|
|
byteSize = index2;
|
|
index2 = (USB_MEM_ALIGN(byteSize, LENGTH_OF_EACH_LAB) / LENGTH_OF_EACH_LAB);
|
|
}
|
|
|
|
/* Check index validities */
|
|
if( (index1 + index2) >= pDiskCtrl->logicalBlocks)
|
|
{
|
|
USB_printf("USB disk read: invalid indexes - addr=%d, size=%d\n",
|
|
index1, index2);
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 1;
|
|
/* Send zero size packet */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)NULL, 0);
|
|
return;
|
|
}
|
|
|
|
if (cbw_ptr->DCBWDATALENGTH == 0)
|
|
{ /* Body */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 2;
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
return;
|
|
}
|
|
else
|
|
{ /* Body */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
if (byteSize > cbw_ptr->DCBWDATALENGTH)
|
|
{ /* Body */
|
|
byteSize = cbw_ptr->DCBWDATALENGTH;
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 2;
|
|
}
|
|
else
|
|
{
|
|
if (byteSize < cbw_ptr->DCBWDATALENGTH)
|
|
{ /* Body */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH - index2);
|
|
if (byteSize > 0)
|
|
{ /* Body */
|
|
if (pDiskCtrl->speed == ARC_USB_SPEED_HIGH)
|
|
{
|
|
max_pkt_size = pDiskCtrl->hsMaxPktSize;
|
|
}
|
|
else
|
|
{
|
|
max_pkt_size = pDiskCtrl->fsMaxPktSize;
|
|
}
|
|
|
|
if( (byteSize % max_pkt_size) == 0)
|
|
{ /* Body */
|
|
/* Need send a zero terminate packet to host */
|
|
pDiskCtrl->ZERO_TERMINATE = TRUE;
|
|
} /* Endbody */
|
|
} /* Endbody */
|
|
} /* Endbody */
|
|
}
|
|
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo,
|
|
pDiskCtrl->MASS_STORAGE_DISK + (index1*LENGTH_OF_EACH_LAB), byteSize);
|
|
} /* Endbody */
|
|
}
|
|
else
|
|
{ /* Body */
|
|
USB_printf("disk read incorrect: FLAGS=0x%02x, LENGTH=0x%x\n",
|
|
cbw_ptr->BMCBWFLAGS, cbw_ptr->DCBWDATALENGTH);
|
|
|
|
/* Incorrect but valid CBW */
|
|
if (cbw_ptr->DCBWDATALENGTH > BUFFERSIZE)
|
|
byteSize = BUFFERSIZE;
|
|
else
|
|
byteSize = cbw_ptr->DCBWDATALENGTH;
|
|
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 2;
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, index2);
|
|
} /* Endbody */
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_write_command
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Sends data as a response to WRITE Command.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_write_command
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
uint_32 index1 = 0, index2 = 0;
|
|
uint_32 byteSize;
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
if (!(cbw_ptr->BMCBWFLAGS & USB_CBW_DIRECTION_BIT))
|
|
{
|
|
index1 = ((uint_32)cbw_ptr->CBWCB[4] << 8);
|
|
index1 |= cbw_ptr->CBWCB[5];
|
|
index2 = ((uint_32)cbw_ptr->CBWCB[7] << 8);
|
|
index2 |= (uint_32)cbw_ptr->CBWCB[8];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_WRITE,
|
|
"disk write: FLAGS=0x%02x, LENGTH=0x%x, index1=0x%x, index2=0x%x\n",
|
|
cbw_ptr->BMCBWFLAGS, cbw_ptr->DCBWDATALENGTH, index1, index2);
|
|
|
|
if(cbw_ptr->CBWCB[0] != 0x3F)
|
|
{
|
|
byteSize = index2 * LENGTH_OF_EACH_LAB;
|
|
}
|
|
else
|
|
{
|
|
byteSize = index2;
|
|
index2 = (USB_MEM_ALIGN(byteSize, LENGTH_OF_EACH_LAB) / LENGTH_OF_EACH_LAB);
|
|
}
|
|
|
|
/* Check index validities */
|
|
if( (index1 + index2) >= pDiskCtrl->logicalBlocks)
|
|
{
|
|
USB_printf("USB disk write: invalid indexes - addr=%d, size=%d\n",
|
|
index1, index2);
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 1;
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
return;
|
|
}
|
|
|
|
if (cbw_ptr->DCBWDATALENGTH == 0)
|
|
{ /* Body */
|
|
/* Zero transfer length */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 2;
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
return;
|
|
}
|
|
else
|
|
{ /* Body */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
|
|
if (byteSize < cbw_ptr->DCBWDATALENGTH)
|
|
{ /* Body */
|
|
/* The actual length will never exceed the DCBWDATALENGTH */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH - byteSize);
|
|
byteSize = cbw_ptr->DCBWDATALENGTH;
|
|
}
|
|
else if (byteSize > cbw_ptr->DCBWDATALENGTH)
|
|
{ /* Body */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 2;
|
|
byteSize = cbw_ptr->DCBWDATALENGTH;
|
|
} /* Endbody */
|
|
|
|
if (_usb_device_get_transfer_status(handle, pDiskCtrl->outEpNo, ARC_USB_RECV) != USB_OK)
|
|
{
|
|
_usb_device_cancel_transfer(handle, ep_num, ARC_USB_RECV);
|
|
} /* Endif */
|
|
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo,
|
|
pDiskCtrl->MASS_STORAGE_DISK + (index1*LENGTH_OF_EACH_LAB), byteSize);
|
|
}
|
|
}
|
|
else
|
|
{ /* Body */
|
|
USB_printf("disk write incorrect: FLAGS=0x%02x, LENGTH=0x%x\n",
|
|
cbw_ptr->BMCBWFLAGS, cbw_ptr->DCBWDATALENGTH);
|
|
|
|
/* Incorrect but valid CBW */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 2;
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, 0, 0);
|
|
return;
|
|
} /* Endbody */
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_test_unit_ready
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Responds appropriately to unit ready query
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_test_unit_ready
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
uint_32 bufSize;
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
if ((cbw_ptr->BMCBWFLAGS & USB_CBW_DIRECTION_BIT) ||
|
|
(cbw_ptr->DCBWDATALENGTH == 0))
|
|
{
|
|
/* The actual length will never exceed the DCBWDATALENGTH */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
}
|
|
else
|
|
{ /* Body */
|
|
/* Incorrect but valid CBW */
|
|
if (cbw_ptr->DCBWDATALENGTH > BUFFERSIZE)
|
|
bufSize = BUFFERSIZE;
|
|
else
|
|
bufSize = cbw_ptr->DCBWDATALENGTH;
|
|
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 1;
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, bufSize);
|
|
} /* Endbody */
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_prevent_allow_medium_removal
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Responds appropriately to unit ready query
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_prevent_allow_medium_removal
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
/* The actual length will never exceed the DCBWDATALENGTH */
|
|
pDiskCtrl->pCSW->DCSWDATARESIDUE = 0;
|
|
pDiskCtrl->pCSW->BCSWSTATUS = 0;
|
|
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : _process_mass_storage_command
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Process a Mass storage class command
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
void _process_mass_storage_command
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Endpoint number */
|
|
uint_8 ep_num,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
CBW_STRUCT_PTR cbw_ptr
|
|
)
|
|
{ /* Body */
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK,
|
|
"disk command: CBWCB[0]=0x%02x, FLAGS=0x%02x, LENGTH=0x%x\n",
|
|
cbw_ptr->CBWCB[0], cbw_ptr->BMCBWFLAGS, cbw_ptr->DCBWDATALENGTH);
|
|
|
|
switch (cbw_ptr->CBWCB[0])
|
|
{
|
|
case 0x00: /* Request the device to report if it is ready */
|
|
_process_test_unit_ready(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x12: /* Inquity command. Get device information */
|
|
_process_inquiry_command(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x1A:
|
|
_process_unsupported_command(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x1E: /* Prevent or allow the removal of media from a removable media device */
|
|
_process_prevent_allow_medium_removal(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x23: /* Read Format Capacities. Report current media capacity and
|
|
** formattable capacities supported by media
|
|
*/
|
|
/* We bahave like already installed medium. No need to send any data */
|
|
_process_unsupported_command(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x25: /* Report current media capacity */
|
|
_process_report_capacity(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x28: /* Read (10) Transfer binary data from media to the host */
|
|
case 0x3E:
|
|
_process_read_command(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x2A: /* Write (10) Transfer binary data from the host to the media */
|
|
case 0x3F:
|
|
_process_write_command(handle, ep_num, cbw_ptr);
|
|
break;
|
|
|
|
case 0x01: /* Position a head of the drive to zero track */
|
|
case 0x03: /* Transfer status sense data to the host */
|
|
case 0x04: /* Format unformatted media */
|
|
case 0x1B: /* Request a request a removable-media device to load or
|
|
** unload its media
|
|
*/
|
|
case 0x1D: /* Perform a hard reset and execute diagnostics */
|
|
case 0x2B: /* Seek the device to a specified address */
|
|
case 0x2E: /* Transfer binary data from the host to the media and
|
|
** verify data
|
|
*/
|
|
case 0x2F: /* Verify data on the media */
|
|
case 0x55: /* Allow the host to set parameters in a peripheral */
|
|
case 0x5A: /* Report parameters to the host */
|
|
case 0xA8: /* Read (12) Transfer binary data from the media to the host */
|
|
case 0xAA: /* Write (12) Transfer binary data from the host to the
|
|
** media
|
|
*/
|
|
default:
|
|
_process_unsupported_command(handle, ep_num, cbw_ptr);
|
|
break;
|
|
} /* Endswitch */
|
|
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : service_ep1
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Called upon a completed endpoint 1 (USB 1.1 Chapter 9) transfer
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void service_ep1
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] Service type as registered */
|
|
uint_8 type,
|
|
|
|
/* [IN] Is it a setup packet? */
|
|
boolean setup,
|
|
|
|
/* [IN] Direction of the transfer. Is it transmit? */
|
|
uint_8 direction,
|
|
|
|
/* [IN] Pointer to the data buffer */
|
|
uint_8_ptr buffer,
|
|
|
|
/* [IN] Length of the transfer */
|
|
uint_32 length,
|
|
|
|
/* [IN] Error, if any */
|
|
uint_8 error
|
|
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
CBW_STRUCT_PTR cbw_ptr = (CBW_STRUCT_PTR)((pointer)buffer);
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_EP1,
|
|
"disk %s: ep=%d, dir=%s, pBuf=0x%x, length=%d, error=0x%x\n",
|
|
__FUNCTION__, type, (direction == ARC_USB_RECV) ? "RECV" : "SEND",
|
|
(unsigned)buffer, (int)length, error);
|
|
|
|
if ((!direction) && (!pDiskCtrl->CBW_PROCESSED) && (length == 31) &&
|
|
(cbw_ptr->DCBWSIGNATURE == USB_32BIT_LE(USB_DCBWSIGNATURE)))
|
|
{
|
|
/* A valid CBW was received */
|
|
pDiskCtrl->pCSW->DCSWSIGNATURE = USB_32BIT_LE(USB_DCSWSIGNATURE);
|
|
pDiskCtrl->pCSW->DCSWTAG = cbw_ptr->DCBWTAG;
|
|
pDiskCtrl->CBW_PROCESSED = TRUE;
|
|
|
|
/* Swap 32 bit fields if neccessary */
|
|
cbw_ptr->DCBWDATALENGTH = USB_32BIT_LE(cbw_ptr->DCBWDATALENGTH);
|
|
|
|
/* Process the command */
|
|
_process_mass_storage_command(handle, type, cbw_ptr);
|
|
}
|
|
else
|
|
{
|
|
/* If a CBW was processed then send the status information and
|
|
** queue another cbw receive request, else just queue another CBW receive
|
|
** request if we received an invalid CBW
|
|
*/
|
|
if (pDiskCtrl->CBW_PROCESSED)
|
|
{
|
|
int i;
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_DATA,
|
|
"disk %s: ep=%d, dir=%s, pBuf=0x%x, length=%d, error=0x%x\n",
|
|
__FUNCTION__, type, (direction == ARC_USB_RECV) ? "RECV" : "SEND",
|
|
(unsigned)buffer, (int)length, error);
|
|
|
|
for(i=0; i<64; i++)
|
|
{
|
|
if( (i % 16) == 0)
|
|
{
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_DUMP, "\n0x%08x: ", &buffer[i]);
|
|
}
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_DUMP, "%02x ", buffer[i]);
|
|
if( (i % 3) == 0)
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_DISK_DUMP, " ");
|
|
}
|
|
|
|
if (pDiskCtrl->ZERO_TERMINATE)
|
|
{ /* Body */
|
|
pDiskCtrl->ZERO_TERMINATE = FALSE;
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, 0, 0);
|
|
}
|
|
else
|
|
{ /* Body */
|
|
pDiskCtrl->CBW_PROCESSED = FALSE;
|
|
|
|
/* Send the command status information */
|
|
_usb_device_send_data(handle, pDiskCtrl->inEpNo, (uint_8_ptr)pDiskCtrl->pCSW, 13);
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!direction)
|
|
{
|
|
USB_printf("usbDisk_%d, %s: Wrong direction = %d\n",
|
|
_usb_device_get_dev_num(handle), __FUNCTION__, direction);
|
|
_usb_device_stall_endpoint(handle, pDiskCtrl->outEpNo, ARC_USB_RECV);
|
|
_usb_device_stall_endpoint(handle, pDiskCtrl->inEpNo, ARC_USB_SEND);
|
|
|
|
/* Invalid CBW received. Queue another receive buffer */
|
|
_usb_device_recv_data(handle, pDiskCtrl->outEpNo, pDiskCtrl->ep1_buf, 31);
|
|
}
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
return;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : service_speed
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Called upon a speed detection event.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void service_speed
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] request type as registered */
|
|
uint_8 type,
|
|
|
|
/* [IN] Unused */
|
|
boolean setup,
|
|
|
|
/* [IN] Unused */
|
|
uint_8 direction,
|
|
|
|
/* [IN] Unused */
|
|
uint_8_ptr buffer,
|
|
|
|
/* [IN] Unused */
|
|
uint_32 length,
|
|
|
|
/* [IN] Error, if any */
|
|
uint_8 error
|
|
|
|
)
|
|
{ /* EndBody */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SPEED, "disk %s: speed = %d\n", __FUNCTION__, (unsigned)length);
|
|
|
|
pDiskCtrl->speed = length;
|
|
return;
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : reset_ep0
|
|
* Returned Value : None
|
|
* Comments :
|
|
* Called upon a bus reset event. Initialises the control endpoint.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
static void reset_ep0
|
|
(
|
|
/* [IN] Handle of the USB device */
|
|
_usb_device_handle handle,
|
|
|
|
/* [IN] request type as registered */
|
|
uint_8 type,
|
|
|
|
/* [IN] Unused */
|
|
boolean setup,
|
|
|
|
/* [IN] Unused */
|
|
uint_8 direction,
|
|
|
|
/* [IN] Unused */
|
|
uint_8_ptr buffer,
|
|
|
|
/* [IN] Unused */
|
|
uint_32 length,
|
|
|
|
/* [IN] Error, if any */
|
|
uint_8 error
|
|
|
|
)
|
|
{ /* Body */
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_RESET, "disk-%d %s: pDiskCtrl=%p, handle=%p\n",
|
|
devNo, __FUNCTION__, pDiskCtrl, handle);
|
|
|
|
/* on a reset always ensure all transfers are cancelled on control EP*/
|
|
_usb_device_cancel_transfer(handle, 0, ARC_USB_RECV);
|
|
_usb_device_cancel_transfer(handle, 0, ARC_USB_SEND);
|
|
|
|
_usb_device_start(handle);
|
|
/* Initialize the endpoint 0 in both directions */
|
|
_usb_device_init_endpoint(handle, 0, pDiskCtrl->DevDesc[DEV_DESC_MAX_PACKET_SIZE],
|
|
ARC_USB_RECV, ARC_USB_CONTROL_ENDPOINT, 0);
|
|
_usb_device_init_endpoint(handle, 0, pDiskCtrl->DevDesc[DEV_DESC_MAX_PACKET_SIZE],
|
|
ARC_USB_SEND, ARC_USB_CONTROL_ENDPOINT, 0);
|
|
|
|
|
|
if (pDiskCtrl->TEST_ENABLED)
|
|
{
|
|
int out_ep_count=0, in_ep_count=0;
|
|
|
|
while(_usb_device_get_transfer_status(handle, pDiskCtrl->outEpNo, ARC_USB_RECV) !=
|
|
ARC_USB_STATUS_IDLE)
|
|
{
|
|
out_ep_count++;
|
|
_usb_device_cancel_transfer(handle, pDiskCtrl->outEpNo, ARC_USB_RECV);
|
|
}
|
|
while(_usb_device_get_transfer_status(handle, pDiskCtrl->inEpNo, ARC_USB_SEND) !=
|
|
ARC_USB_STATUS_IDLE)
|
|
{
|
|
in_ep_count++;
|
|
_usb_device_cancel_transfer(handle, pDiskCtrl->inEpNo, ARC_USB_SEND);
|
|
}
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_RESET, "disk %s: out_ep_count=%d, in_ep_count=%d\n",
|
|
__FUNCTION__, out_ep_count, in_ep_count);
|
|
} /* Endif */
|
|
|
|
pDiskCtrl->TEST_ENABLED = FALSE;
|
|
|
|
return;
|
|
} /* EndBody */
|
|
|
|
/*FUNCTION*----------------------------------------------------------------
|
|
*
|
|
* Function Name : usbDiskLoad - main task
|
|
* Inputs:
|
|
* int diskSize - size of created disk in KBytes
|
|
* Returned Value : None
|
|
* Comments :
|
|
* First function called. Initialises the USB and registers Chapter 9
|
|
* callback functions.
|
|
*
|
|
*END*--------------------------------------------------------------------*/
|
|
_usb_device_handle usbDiskLoad(int devNo, int diskSize)
|
|
{ /* Body */
|
|
_usb_device_handle handle;
|
|
USB_DISK_STRUCT* pDiskCtrl;
|
|
uint_8_ptr Send_Buffer_aligned;
|
|
uint_8 error;
|
|
uint_32 send_data_buffer_size=0;
|
|
uint_8_ptr temp;
|
|
int lockKey, i, j;
|
|
static boolean isFirst = TRUE;
|
|
|
|
ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_INIT, "%s: devNo=%d, diskSize=%d\n",
|
|
__FUNCTION__, devNo, diskSize);
|
|
|
|
if(devNo >= MAX_USB_DEVICES)
|
|
{
|
|
USB_printf("USB disk: devNo=%d too large\n", devNo);
|
|
return NULL;
|
|
}
|
|
|
|
/*lock interrupts */
|
|
lockKey = USB_lock();
|
|
|
|
if(isFirst)
|
|
{
|
|
for(i=0; i<MAX_USB_DEVICES; i++)
|
|
{
|
|
usbDisksPtr[i] = NULL;
|
|
}
|
|
/* Swap all USB_STRING_DESC */
|
|
for(i=0; i<(sizeof(USB_STRING_DESC)/sizeof(USB_STRING_DESC[0])); i++)
|
|
{
|
|
uint_16* usbStr = (uint_16*)(USB_STRING_DESC[i]);
|
|
uint_16 size = (usbStr[0]-0x300)/sizeof(uint_16);
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
usbStr[j] = USB_16BIT_LE(usbStr[j]);
|
|
}
|
|
}
|
|
isFirst = FALSE;
|
|
}
|
|
|
|
if(usbDisksPtr[devNo] != NULL)
|
|
{
|
|
USB_printf("USB disk: devNo=%d is busy\n", devNo);
|
|
USB_unlock(lockKey);
|
|
return NULL;
|
|
}
|
|
|
|
/* Allocate Disk control structure */
|
|
pDiskCtrl = USB_memalloc(sizeof(USB_DISK_STRUCT));
|
|
if(pDiskCtrl == NULL)
|
|
{
|
|
USB_printf("USB disk #%d: Can't allocate USB_DISK_STRUCT (%d bytes)\n",
|
|
devNo, sizeof(USB_DISK_STRUCT));
|
|
USB_unlock(lockKey);
|
|
return NULL;
|
|
}
|
|
USB_memzero(pDiskCtrl, sizeof(USB_DISK_STRUCT));
|
|
|
|
if(diskSize == 0)
|
|
pDiskCtrl->logicalBlocks = TOTAL_LOGICAL_ADDRESS_BLOCKS;
|
|
else
|
|
pDiskCtrl->logicalBlocks = (diskSize*1024)/LENGTH_OF_EACH_LAB;
|
|
|
|
if(pDiskCtrl->logicalBlocks < 16)
|
|
{
|
|
USB_printf("USB disk size (%d) is too small. Minimum is 8 Kbytes\n",
|
|
diskSize);
|
|
USB_unlock(lockKey);
|
|
return NULL;
|
|
}
|
|
|
|
pDiskCtrl->devNo = devNo;
|
|
pDiskCtrl->hsMaxPktSize = diskHsMaxPktSize;
|
|
pDiskCtrl->fsMaxPktSize = diskFsMaxPktSize;
|
|
|
|
pDiskCtrl->inEpType = diskInEpType;
|
|
pDiskCtrl->outEpType = diskOutEpType;
|
|
|
|
pDiskCtrl->inEpNo = diskInEpNo;
|
|
pDiskCtrl->outEpNo = diskOutEpNo;
|
|
|
|
/* Initialize the USB interface */
|
|
error = _usb_device_init(devNo, &handle);
|
|
if (error != USB_OK)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("\nUSB Initialization failed. Error: %x", error);
|
|
return NULL;
|
|
} /* Endif */
|
|
|
|
/* Self Power, Remote wakeup disable */
|
|
_usb_device_set_status(handle, ARC_USB_STATUS_DEVICE, (1 << DEVICE_SELF_POWERED));
|
|
|
|
error = _usb_device_register_service(handle, ARC_USB_SERVICE_EP0, service_ep0);
|
|
if (error != USB_OK)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("\nUSB Service Registration failed. Error: %x", error);
|
|
return NULL;
|
|
} /* Endif */
|
|
|
|
error = _usb_device_register_service(handle, ARC_USB_SERVICE_BUS_RESET, reset_ep0);
|
|
if (error != USB_OK)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("\nUSB Service Registration failed. Error: %x", error);
|
|
return NULL;
|
|
} /* Endif */
|
|
|
|
error = _usb_device_register_service(handle, ARC_USB_SERVICE_SPEED_DETECTION,
|
|
service_speed);
|
|
if (error != USB_OK)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("\nUSB Service Registration failed. Error: %x", error);
|
|
return NULL;
|
|
} /* Endif */
|
|
|
|
error = _usb_device_register_service(handle, pDiskCtrl->outEpNo, service_ep1);
|
|
if (error != USB_OK)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("\nUSB Service Registration failed. Error: %x", error);
|
|
return NULL;
|
|
} /* Endif */
|
|
|
|
if(pDiskCtrl->outEpNo != pDiskCtrl->inEpNo)
|
|
{
|
|
error = _usb_device_register_service(handle, pDiskCtrl->inEpNo, service_ep1);
|
|
if (error != USB_OK)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("\nUSB Service Registration failed. Error: %x", error);
|
|
return NULL;
|
|
} /* Endif */
|
|
}
|
|
|
|
/**************************************************************************
|
|
Best way to handle the Data cache is to allocate a large buffer that is
|
|
cache aligned and keep all data inside it. Flush the line of the cache
|
|
that you have changed. In this program, we have static data such as
|
|
descriptors which never changes. Such data can be kept in this buffer
|
|
and flushed only once. Note that you can reduce the size of this buffer
|
|
by aligning the addresses in a different way.
|
|
***************************************************************************/
|
|
send_data_buffer_size = (DEVICE_DESCRIPTOR_SIZE + PSP_CACHE_LINE_SIZE) +
|
|
(CONFIG_DESC_SIZE + PSP_CACHE_LINE_SIZE) +
|
|
(DEVICE_QUALIFIER_DESCRIPTOR_SIZE + PSP_CACHE_LINE_SIZE) +
|
|
(OTHER_SPEED_CONFIG_DESC_SIZE + PSP_CACHE_LINE_SIZE) +
|
|
(BUFFERSIZE + PSP_CACHE_LINE_SIZE) +
|
|
(EP_TEMP_BUFFERSIZE + PSP_CACHE_LINE_SIZE) +
|
|
(sizeof(DISK_READ_CAPACITY) + PSP_CACHE_LINE_SIZE) +
|
|
(sizeof(CSW_STRUCT) + PSP_CACHE_LINE_SIZE) +
|
|
(pDiskCtrl->logicalBlocks*LENGTH_OF_EACH_LAB + PSP_CACHE_LINE_SIZE);
|
|
|
|
pDiskCtrl->Send_Buffer_Unaligned = (uint_8_ptr) USB_memalloc(send_data_buffer_size);
|
|
if (pDiskCtrl->Send_Buffer_Unaligned == NULL)
|
|
{
|
|
USB_unlock(lockKey);
|
|
USB_printf("diskLoad: Buffer allocation of %d bytes is failed\n",
|
|
(unsigned)send_data_buffer_size);
|
|
return NULL;
|
|
}
|
|
|
|
Send_Buffer_aligned = (uint_8_ptr) USB_CACHE_ALIGN((uint_32)pDiskCtrl->Send_Buffer_Unaligned);
|
|
/* keep a temporary copy of the aligned address */
|
|
temp = Send_Buffer_aligned;
|
|
|
|
/**************************************************************************
|
|
Assign pointers to different buffers from it and copy data inside.
|
|
***************************************************************************/
|
|
pDiskCtrl->DevDesc = (uint_8_ptr) Send_Buffer_aligned;
|
|
USB_memcopy(DevDescData, pDiskCtrl->DevDesc, DEVICE_DESCRIPTOR_SIZE);
|
|
Send_Buffer_aligned += ((DEVICE_DESCRIPTOR_SIZE/PSP_CACHE_LINE_SIZE) + 1)* PSP_CACHE_LINE_SIZE;
|
|
|
|
pDiskCtrl->ConfigDesc = (uint_8_ptr) Send_Buffer_aligned;
|
|
USB_memcopy(ConfigDescData, pDiskCtrl->ConfigDesc, CONFIG_DESC_SIZE);
|
|
Send_Buffer_aligned += ((CONFIG_DESC_SIZE/PSP_CACHE_LINE_SIZE) + 1)* PSP_CACHE_LINE_SIZE;
|
|
|
|
pDiskCtrl->DevQualifierDesc = (uint_8_ptr) Send_Buffer_aligned;
|
|
USB_memcopy(DevQualifierDescData, pDiskCtrl->DevQualifierDesc, DEVICE_QUALIFIER_DESCRIPTOR_SIZE);
|
|
Send_Buffer_aligned += ((DEVICE_QUALIFIER_DESCRIPTOR_SIZE/PSP_CACHE_LINE_SIZE) + 1) * PSP_CACHE_LINE_SIZE;
|
|
|
|
pDiskCtrl->other_speed_config = (uint_8_ptr) Send_Buffer_aligned;
|
|
USB_memcopy(other_speed_config_data, pDiskCtrl->other_speed_config, OTHER_SPEED_CONFIG_DESC_SIZE);
|
|
Send_Buffer_aligned += ((OTHER_SPEED_CONFIG_DESC_SIZE/PSP_CACHE_LINE_SIZE) + 1)* PSP_CACHE_LINE_SIZE;
|
|
|
|
/*buffer to receive data from Bulk OUT */
|
|
pDiskCtrl->ep1_buf = (uint_8_ptr) Send_Buffer_aligned;
|
|
USB_memzero(pDiskCtrl->ep1_buf, BUFFERSIZE);
|
|
Send_Buffer_aligned += ((BUFFERSIZE/PSP_CACHE_LINE_SIZE) + 1)* PSP_CACHE_LINE_SIZE;
|
|
|
|
/*buffer for control endpoint to send data */
|
|
pDiskCtrl->epTemp_buf = (uint_8_ptr) Send_Buffer_aligned;
|
|
USB_memzero(pDiskCtrl->epTemp_buf, EP_TEMP_BUFFERSIZE);
|
|
|
|
Send_Buffer_aligned += ((EP_TEMP_BUFFERSIZE/PSP_CACHE_LINE_SIZE) + 1)* PSP_CACHE_LINE_SIZE;
|
|
|
|
/* Buffer for read Capacity message */
|
|
pDiskCtrl->pReadCapacity = (DISK_READ_CAPACITY*)Send_Buffer_aligned;
|
|
USB_memcopy((void*)&read_capacity, pDiskCtrl->pReadCapacity, sizeof(DISK_READ_CAPACITY));
|
|
|
|
/* Update read_capacity */
|
|
pDiskCtrl->pReadCapacity->LAST_LOGICAL_BLOCK_ADDRESS[2] =
|
|
USB_uint_16_high(pDiskCtrl->logicalBlocks-14);
|
|
pDiskCtrl->pReadCapacity->LAST_LOGICAL_BLOCK_ADDRESS[3] =
|
|
USB_uint_16_low(pDiskCtrl->logicalBlocks-14);
|
|
|
|
Send_Buffer_aligned += ((sizeof(DISK_READ_CAPACITY)/PSP_CACHE_LINE_SIZE) + 1) * PSP_CACHE_LINE_SIZE;
|
|
|
|
/* Buffer for CSW message */
|
|
pDiskCtrl->pCSW = (CSW_STRUCT*)Send_Buffer_aligned;
|
|
USB_memzero(pDiskCtrl->pCSW , sizeof(CSW_STRUCT));
|
|
|
|
Send_Buffer_aligned += ((sizeof(CSW_STRUCT)/PSP_CACHE_LINE_SIZE) + 1) * PSP_CACHE_LINE_SIZE;
|
|
|
|
/*buffer for storage disk */
|
|
pDiskCtrl->MASS_STORAGE_DISK = (uint_8_ptr)Send_Buffer_aligned;
|
|
|
|
USB_printf("usbDisk-%d: pDiskCtrl=%p, %d bytes allocated addr=0x%x\n",
|
|
devNo, pDiskCtrl, (unsigned)send_data_buffer_size,
|
|
(unsigned)pDiskCtrl->Send_Buffer_Unaligned);
|
|
USB_printf("usbDisk-%d: DevDesc=0x%x, ConfigDesc=0x%x, QualifierDesc=0x%x, otherSpeedDesc=0x%x\n",
|
|
devNo, (unsigned)pDiskCtrl->DevDesc, (unsigned)pDiskCtrl->ConfigDesc,
|
|
(unsigned)pDiskCtrl->DevQualifierDesc, (unsigned)pDiskCtrl->other_speed_config);
|
|
USB_printf("usbDisk-%d: ep1_buf=0x%x, epTemp_buf=0x%x, MASS_STORAGE_DISK=0x%x\n",
|
|
devNo, (unsigned)pDiskCtrl->ep1_buf, (unsigned)pDiskCtrl->epTemp_buf,
|
|
(unsigned)pDiskCtrl->MASS_STORAGE_DISK);
|
|
|
|
USB_memzero(pDiskCtrl->MASS_STORAGE_DISK, (pDiskCtrl->logicalBlocks*LENGTH_OF_EACH_LAB));
|
|
|
|
/* Format the "disk" */
|
|
USB_memcopy(BOOT_SECTOR_AREA, pDiskCtrl->MASS_STORAGE_DISK, 512);
|
|
|
|
/* Update BOOT Sector "Total Small sectors" field */
|
|
pDiskCtrl->MASS_STORAGE_DISK[19] = USB_uint_16_low(pDiskCtrl->logicalBlocks);
|
|
pDiskCtrl->MASS_STORAGE_DISK[20] = USB_uint_16_high(pDiskCtrl->logicalBlocks);
|
|
|
|
USB_memcopy((void *)FAT16_SPECIAL_BYTES, pDiskCtrl->MASS_STORAGE_DISK + 512, 3);
|
|
USB_memcopy((void *)FAT16_SPECIAL_BYTES, pDiskCtrl->MASS_STORAGE_DISK + 512*4, 3);
|
|
|
|
/**************************************************************************
|
|
Flush the cache to ensure main memory is updated.
|
|
***************************************************************************/
|
|
USB_dcache_flush(temp, send_data_buffer_size);
|
|
|
|
pDiskCtrl->usbDevHandle = handle;
|
|
usbDisksPtr[devNo] = pDiskCtrl;
|
|
|
|
USB_unlock(lockKey);
|
|
|
|
USB_printf("USB Disk is READY: diskSize=%d KBytes, blockSize=%d Bytes, numBlocks=%d\n",
|
|
diskSize, LENGTH_OF_EACH_LAB, pDiskCtrl->logicalBlocks);
|
|
|
|
return pDiskCtrl->usbDevHandle;
|
|
} /* Endbody */
|
|
|
|
void usbDiskUnload(_usb_device_handle handle)
|
|
{
|
|
int lockKey;
|
|
int devNo = _usb_device_get_dev_num(handle);
|
|
USB_DISK_STRUCT* pDiskCtrl = usbDisksPtr[devNo];
|
|
|
|
if(pDiskCtrl == NULL)
|
|
{
|
|
USB_printf("USB disk #%d: Disk is not loaded\n", pDiskCtrl->devNo);
|
|
return;
|
|
}
|
|
/*lock interrupts */
|
|
lockKey = USB_lock();
|
|
|
|
/* ensure all transfers are cancelled */
|
|
_usb_device_cancel_transfer(handle, pDiskCtrl->outEpNo, ARC_USB_RECV);
|
|
_usb_device_cancel_transfer(handle, pDiskCtrl->inEpNo, ARC_USB_SEND);
|
|
|
|
/* Stop Endpoints */
|
|
_usb_device_deinit_endpoint(handle, pDiskCtrl->outEpNo, ARC_USB_RECV);
|
|
_usb_device_deinit_endpoint(handle, pDiskCtrl->inEpNo, ARC_USB_SEND);
|
|
|
|
_usb_device_deinit_endpoint(handle, 0, ARC_USB_RECV);
|
|
_usb_device_deinit_endpoint(handle, 0, ARC_USB_SEND);
|
|
|
|
_usb_device_stop(handle);
|
|
|
|
/* Deregister all services */
|
|
_usb_device_unregister_service(handle, ARC_USB_SERVICE_EP0);
|
|
_usb_device_unregister_service(handle, ARC_USB_SERVICE_BUS_RESET);
|
|
_usb_device_unregister_service(handle, ARC_USB_SERVICE_SPEED_DETECTION);
|
|
_usb_device_unregister_service(handle, pDiskCtrl->outEpNo);
|
|
if(pDiskCtrl->outEpNo != pDiskCtrl->inEpNo)
|
|
{
|
|
_usb_device_unregister_service(handle, pDiskCtrl->inEpNo);
|
|
}
|
|
|
|
_usb_device_shutdown(handle);
|
|
|
|
/* Free memory allocated for Disk device */
|
|
if(pDiskCtrl->Send_Buffer_Unaligned != NULL)
|
|
{
|
|
USB_memfree(pDiskCtrl->Send_Buffer_Unaligned);
|
|
}
|
|
|
|
/* Free Control structure */
|
|
USB_memfree(pDiskCtrl);
|
|
usbDisksPtr[devNo] = NULL;
|
|
|
|
USB_unlock(lockKey);
|
|
}
|
|
|
|
/* EOF */
|
|
|