blob: 6876c12e85eabc81d59c58f3339e933c38a040eb [file] [log] [blame]
/*******************************************************************************
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,
&current_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 */