www.pudn.com > ucosii_core.rar > mass_storage.c, change:2007-06-26,size:12701b


#include "usb.h"
#include "udc.h"
#if 0
#define dprintf(x...) printf(x)
#else
#define dprintf(x...)
#endif
#ifndef NULL
#define NULL
#endif

/*
 * USB mass storage class subclasses
 */
enum UMASS_SUBCLASS
{
	MASS_SUBCLASS_RBC = 1,	// Flash
	MASS_SUBCLASS_8020,	// CD-ROM
	MASS_SUBCLASS_QIC,	// Tape
	MASS_SUBCLASS_UFI,	// Floppy disk device
	MASS_SUBCLASS_8070,	// Floppy disk device
	MASS_SUBCLASS_SCSI	// Any device with a SCSI-defined command set
};


/*
 * USB mass storage class protocols
 */
enum UMASS_PROTOCOL
{
	MASS_PROTOCOL_CBI,	// Command/Bulk/Interrupt
	MASS_PROTOCOL_CBI_CCI,	// Command/Bulk/Interrupt
	MASS_PROTOCOL_BULK = 0x50	// Bulk-Only transport
};

static u32 epout, epin;

static USB_DeviceDescriptor devDesc = 
{
	sizeof(USB_DeviceDescriptor),
	DEVICE_DESCRIPTOR,	//1
	0x0110,
	0x08,
	0x01,
	0x50,
	8,	/* Ep0 FIFO size */
	0x07c4,
	0xa4a5,
	0xffff,
	0x00,
	0x00,
	0x00,
	0x01
};

#define	CONFIG_DESCRIPTOR_LEN	(sizeof(USB_ConfigDescriptor) + \
				 sizeof(USB_InterfaceDescriptor) + \
				 sizeof(USB_EndPointDescriptor) * 2)

static struct {
	USB_ConfigDescriptor    configuration_descriptor;
	USB_InterfaceDescriptor interface_descritor;
	USB_EndPointDescriptor  endpoint_descriptor[2];
} __attribute__ ((packed)) confDesc = {
	{
		sizeof(USB_ConfigDescriptor),
		CONFIGURATION_DESCRIPTOR,
		CONFIG_DESCRIPTOR_LEN,
		0x01,
		0x01,
		0x00,
		0xc0,	// Self Powered, no remote wakeup
		0x64	// Maximum power consumption 2000 mA
	},
	{
		sizeof(USB_InterfaceDescriptor),
		INTERFACE_DESCRIPTOR,
		0x00,
		0x00,
		0x02,	/* ep number */
		CLASS_MASS_STORAGE,
		MASS_SUBCLASS_SCSI,
		MASS_PROTOCOL_BULK,
		0x04
	},
	{
		{
			sizeof(USB_EndPointDescriptor),
			ENDPOINT_DESCRIPTOR,
			(1 << 7) | 2,// endpoint 2 is IN endpoint
			2, /* bulk */
			/* Transfer Type: Bulk;
			 * Synchronization Type: No Synchronization;
			 * Usage Type: Data endpoint
			 */
			64, /* IN EP FIFO size */
			255
		},
		{
			sizeof(USB_EndPointDescriptor),
			ENDPOINT_DESCRIPTOR,
			(0 << 7) | 5,// endpoint 5 is OUT endpoint
			2, /* bulk */
			/* Transfer Type: Bulk;
			 * Synchronization Type: No Synchronization;
			 * Usage Type: Data endpoint
			 */
			64, /* OUT EP FIFO size */
			255
		}
	}
};
void sendDevDescString(int size)
{
	u16 str_ret[13] = {
		   0x031a,//0x1a=26 byte
		   0x0041,
		   0x0030,
		   0x0030,
		   0x0041,
		   0x0030,
		   0x0030,
		   0x0041,
		   0x0030,
		   0x0030,
		   0x0041,
		   0x0030,
		   0x0030
		  };
	printf("sendDevDescString size = %d\r\n",size);
	if(size >= 26)
		size = 26;
	str_ret[0] = (0x0300 | size);
	HW_SendPKT(0, str_ret,size);
	
	
}

void sendDevDesc(int size)
{
       switch (size) {
	case 18:
		devDesc.iSerialNumber = GetMassDevNum();
		if(devDesc.iSerialNumber > 0)
			devDesc.iSerialNumber--;
		HW_SendPKT(0, &devDesc, sizeof(devDesc));
		break;
	default:
		HW_SendPKT(0, &devDesc, 8);
		break;
	}
}

void sendConfDesc(int size)
{
	switch (size) {
	case 9:
		HW_SendPKT(0, &confDesc, 9);
		break;
	case 8:
		HW_SendPKT(0, &confDesc, 8);
		break;
	default:
		HW_SendPKT(0, &confDesc, sizeof(confDesc));
		break;
	}
}



void usbHandleClassDevReq(u8 *buf)
{
	u8 scsiLUN = 0;	
	switch (buf[1]) {
	case 0xfe:
		scsiLUN = GetMassDevNum();
		if(scsiLUN > 0)
			scsiLUN --;
		dprintf("Get max lun\n");
		
		if (buf[0] == 0xa1)
			HW_SendPKT(0, &scsiLUN, 1);
		break;
	case 0xff:
		dprintf("Mass storage reset\n");
		break;
	}
}


/*
 * Command Block Wrapper (CBW)
 */
#define	CBWSIGNATURE	0x43425355		// "CBSU"
#define	CBWFLAGS_OUT	0x00			// HOST-to-DEVICE
#define	CBWFLAGS_IN	0x80			// DEVICE-to-HOST
#define	CBWCDBLENGTH	16

typedef struct
{
	u32 dCBWSignature;
	u32 dCBWTag;
	s32 dCBWDataXferLength;
	u8 bmCBWFlags;
	/* The bits of this field are defined as follows:
	 *     Bit 7 Direction - the device shall ignore this bit if the
	 *                       dCBWDataTransferLength zero, otherwise:
	 *         0 = Data-Out from host to the device,
	 *         1 = Data-In from the device to the host.
	 *     Bit 6 Obsolete. The host shall set this bit to zero.
	 *     Bits 5..0 Reserved - the host shall set these bits to zero.
	 */
	u8 bCBWLUN : 4,
	   reserved0 : 4;

	u8 bCBWCBLength : 5,
	   reserved1    : 3;
	u8 CBWCB[CBWCDBLENGTH];
} __attribute__ ((packed)) CBW;


/*
 * Command Status Wrapper (CSW)
 */
#define	CSWSIGNATURE			0x53425355	// "SBSU"
#define	CSWSIGNATURE_IMAGINATION_DBX1	0x43425355	// "CBSU"
#define	CSWSIGNATURE_OLYMPUS_C1		0x55425355	// "UBSU"

#define	CSWSTATUS_GOOD			0x0
#define	CSWSTATUS_FAILED		0x1
#define	CSWSTATUS_PHASE_ERR		0x2

typedef struct
{
	u32 dCSWSignature;
	u32 dCSWTag;
	u32 dCSWDataResidue;
	u8 bCSWStatus;
	/* 00h Command Passed ("good status")
	 * 01h Command Failed
	 * 02h Phase Error
	 * 03h and 04h Reserved (Obsolete)
	 * 05h to FFh Reserved
	 */
} __attribute__ ((packed)) CSW;


/*
 * Required UFI Commands
 */
#define	UFI_FORMAT_UNIT			0x04	// output
#define	UFI_INQUIRY			0x12	// input
#define	UFI_MODE_SELECT			0x55	// output
#define	UFI_MODE_SENSE_6		0x1A	// input
#define	UFI_MODE_SENSE_10		0x5A	// input
#define	UFI_PREVENT_MEDIUM_REMOVAL	0x1E
#define	UFI_READ_10			0x28	// input
#define	UFI_READ_12			0xA8	// input
#define	UFI_READ_CAPACITY		0x25	// input
#define	UFI_READ_FORMAT_CAPACITY	0x23	// input
#define	UFI_REQUEST_SENSE		0x03	// input
#define	UFI_REZERO_UNIT			0x01
#define	UFI_SEEK_10			0x2B
#define	UFI_SEND_DIAGNOSTIC		0x1D
#define	UFI_START_UNIT			0x1B
#define	UFI_TEST_UNIT_READY		0x00
#define	UFI_VERIFY			0x2F
#define	UFI_WRITE_10			0x2A	// output
#define	UFI_WRITE_12			0xAA	// output
#define	UFI_WRITE_AND_VERIFY		0x2E	// output
#define	UFI_ALLOW_MEDIUM_REMOVAL	UFI_PREVENT_MEDIUM_REMOVAL
#define	UFI_STOP_UNIT			UFI_START_UNIT



#define	S_CBW		0
#define S_DATA_OUT	1
#define	S_DATA_IN	2
#define S_CSW		3
#define S_NULL          4

static u32 massStat = S_CBW;
static u32 massBuf[1024];
static u32 start_sector;
static u16 nr_sectors;
static CSW csw;
static CBW cbw;

void massReset(void)
{
	massStat = S_CBW;
	start_sector = 0;
	nr_sectors = 0;
}

static u32 swap32(u32 n)
{
	return (((n & 0x000000ff) >> 0) << 24) |
	       (((n & 0x0000ff00) >> 8) << 16) |
	       (((n & 0x00ff0000) >> 16) << 8) |
	       (((n & 0xff000000) >> 24) << 0);
}

typedef struct _CAPACITY_DATA {
	u32 Blocks;
	u32 BlockLen;   
	
}CAPACITY_DATA;
typedef struct _READ_FORMAT_CAPACITY_DATA {
	u8 Reserve1[3];
	u8 CapacityListLen;
	CAPACITY_DATA CurMaxCapacity;
	CAPACITY_DATA CapacityData[30];
	
}READ_FORMAT_CAPACITY_DATA;

static void ProcessScsiReadFormatCapacity(u8 cbwLUN,u32 size)
{
	struct {
		u32 hiddennum;
		u32 headnum;
		u32 secnum;
		u32 partsize;
	} devinfo;
	READ_FORMAT_CAPACITY_DATA readfcd;
	memset(&readfcd,0,sizeof(readfcd));
	readfcd.CapacityListLen = 1;
	massDevInfo(cbwLUN,&devinfo);
	readfcd.CapacityData[0].Blocks = devinfo.partsize-1;
	readfcd.CapacityData[0].BlockLen = 512;
	readfcd.CurMaxCapacity.Blocks = devinfo.partsize-1;
		
	readfcd.CurMaxCapacity.BlockLen = 512;
	readfcd.CurMaxCapacity.BlockLen = (readfcd.CurMaxCapacity.BlockLen << 8) | 0x2;
	if(size > sizeof(READ_FORMAT_CAPACITY_DATA))
		size = sizeof(READ_FORMAT_CAPACITY_DATA);
	csw.dCSWDataResidue = 0;
	csw.bCSWStatus = CSWSTATUS_GOOD;
	csw.dCSWTag = cbw.dCBWTag;	
	HW_SendPKT(epin, (u8 *) &readfcd, size);

}
int USB_HandleUFICmd(void)
{
	u32 tmp;

	dprintf("massStat:%d\n", massStat);
	switch (massStat) {
	case S_CBW:
		HW_GetPKT(epout, &cbw, sizeof(CBW));
		if (cbw.dCBWSignature != CBWSIGNATURE)
			return 0;
		csw.dCSWSignature = CSWSIGNATURE;
		csw.bCSWStatus = CSWSTATUS_GOOD;
		csw.dCSWTag = cbw.dCBWTag;
		csw.dCSWDataResidue = 0;
		dprintf("cbw.Signature:%08x\n", cbw.dCBWSignature);
		dprintf("cbw.dCBWTag:%08x\n", cbw.dCBWTag);
		dprintf("cbw.dCBWDataXferLength:%x\n", cbw.dCBWDataXferLength);
		dprintf("cbw.bmCBWFlags:%08x\n", cbw.bmCBWFlags);
		dprintf("cbw.bCBWLUN:%d\n", cbw.bCBWLUN);
		dprintf("cbw.bCBWCBLength:%d\n", cbw.bCBWCBLength);
		dprintf("cbw.CBWCB[0]:%02x\n", cbw.CBWCB[0]);
		switch (cbw.CBWCB[0]) {
		case UFI_INQUIRY:
		{
			static const u8 inquiry[] = {
				0x00,	// Direct-access device (floppy)
				0x80,	// 0x80	// Removable Media
				0x00,
				0x01,	// UFI device
				0x5B,
				0x00, 0x00, 0x00,
				'I', 'n', 'g', 'e', 'n', 'i', 'c', ' ',
				'J', 'z', 'S', 'O', 'C', ' ', 'U', 'S',
				'B', '-', 'D', 'I', 'S', 'K', ' ', ' ',
				'0', '1', '0', '0'
			};
			u32 size = sizeof(inquiry);
			if(cbw.dCBWDataXferLength < sizeof(inquiry))
				size = cbw.dCBWDataXferLength;
			HW_SendPKT(epin, inquiry, sizeof(inquiry));
			massStat = S_NULL;
			break;
		}

		case UFI_REQUEST_SENSE:
		{
			static const u8 sense[] = {
				0x70,
				0x00,
				0x05,
				0x00, 0x00, 0x00, 0x00,
				0x0c,
				0x00, 0x00, 0x00, 0x00,
				0x20,
				0x00,
				0x00,
				0x00, 0x00, 0x00
			};
			HW_SendPKT(epin, sense, sizeof(sense));
			massStat = S_DATA_OUT;
			break;
		}

		case UFI_READ_CAPACITY:
		{
			struct {
				u32 hiddennum;
				u32 headnum;
				u32 secnum;
				u32 partsize;
			} devinfo;
			u32 resp[2];

//			FS_IoCtl(USR_DISK, FS_CMD_GET_DEVINFO, 0, (void*)&devinfo);
//			resp[0] = cpu_to_be32(devinfo.partsize - 1);
//			resp[1] = cpu_to_be32(FS_FAT_SEC_SIZE);
//			USB_EndpOut(1, (const u8*)resp, sizeof(resp), false);
			massDevInfo(cbw.bCBWLUN,&devinfo);
			resp[0] = swap32(devinfo.partsize-1); /* last sector */
			resp[1] = swap32(512);		/* sector size */
			HW_SendPKT(epin, (u8 *)resp, sizeof(resp));
			massStat = S_DATA_OUT;
			break;
		}

		case UFI_READ_10:
		case UFI_WRITE_10:
		case UFI_WRITE_AND_VERIFY:
		{
			start_sector =
				((u32)cbw.CBWCB[2] << 24) |
				((u32)cbw.CBWCB[3] << 16) |
				((u32)cbw.CBWCB[4] << 8) |
				(u32)cbw.CBWCB[5];
			nr_sectors   =
				((u16)cbw.CBWCB[7] << 8) | (u16)cbw.CBWCB[8];

			dprintf("s:%d n:%d\n", start_sector, nr_sectors);

			if (cbw.CBWCB[0] == UFI_READ_10) {
				if (nr_sectors > 8) {
					massDevRead(cbw.bCBWLUN ,massBuf, start_sector, 8);
					HW_SendPKT(epin, massBuf, 8*512);
					start_sector += 8;
					nr_sectors -= 8;
				} else {
					massDevRead(cbw.bCBWLUN,massBuf, start_sector,
						    nr_sectors);
					HW_SendPKT(epin, massBuf,
						   nr_sectors * 512);
					start_sector += nr_sectors;
					nr_sectors = 0;
					
				}
				massStat = S_DATA_OUT;
				
			} else
				massStat = S_DATA_IN;
			break;
		}

		case UFI_VERIFY:
//		FS_IoCtl(USR_DISK, FS_CMD_FLUSH_CACHE, 0, 0);
			massStat = S_CSW;
			break;

		case UFI_READ_FORMAT_CAPACITY:
			ProcessScsiReadFormatCapacity(cbw.bCBWLUN,cbw.dCBWDataXferLength);
			
			massStat = S_NULL;
			
			break;
		case UFI_MODE_SENSE_10:
		case UFI_MODE_SENSE_6:

			HW_SendPKT(epin, "\x00\x2a\x00\x00\x00\x00\x00\x00\x01\x0a\x00\x01", 12);
			
			//csw.dCSWTag = cbw.dCBWTag;
			//csw.dCSWDataResidue = 0;
			//csw.bCSWStatus = CSWSTATUS_GOOD;	/* failed ? */
                        massStat = S_NULL;
			
			break;
		default:
			massStat = S_CSW;
			break;
		}

		break;
	case S_DATA_OUT:
		if (!hwTxFifoCount()) {
			if (!nr_sectors) {
				massStat = S_CSW;
				break;
			}
			if (nr_sectors > 8) {
				massDevRead(cbw.bCBWLUN,massBuf, start_sector, 8);
				HW_SendPKT(epin, massBuf, 8*512);
				start_sector += 8;
				nr_sectors -= 8;
			} else {
				massDevRead(cbw.bCBWLUN,massBuf, start_sector, nr_sectors);
				HW_SendPKT(epin, massBuf, nr_sectors * 512);
				start_sector += nr_sectors;
				nr_sectors = 0;
			}
			return;
		}
		break;
	case S_DATA_IN:
		tmp = hwRxFifoCount();
		if ((nr_sectors >= 8) && (tmp >= 4096)) {
			HW_GetPKT(epout, massBuf, 4096);
			massDevWrite(cbw.bCBWLUN,massBuf, start_sector, 8);
			start_sector += 8;
			nr_sectors -= 8;
		} else if ((tmp == nr_sectors * 512) && (nr_sectors < 8)) {
			HW_GetPKT(epout, massBuf, tmp);
			massDevWrite(cbw.bCBWLUN,massBuf, start_sector, nr_sectors);
			start_sector += nr_sectors;
			nr_sectors = 0;
		}
		if (nr_sectors == 0)
			massStat = S_CSW;
		break;
	case S_CSW:
		if (hwTxFifoCount())
			return;
		massStat = S_CBW;
		break;
	case S_NULL:
		if (!hwTxFifoCount())
		{
			//csw.dCSWTag = CSWSTATUS_FAILED;
			//csw.dCSWDataResidue = cbw.dCBWDataXferLength;
			//csw.bCSWStatus = 0;	/* failed ? */
			massStat = S_CSW;
		}
		
		break;
	}

	if (massStat == S_CSW)
	{
		//printf("HW_SendPK %d  ep %d\r\n",cbw.CBWCB[0],epin);
		HW_SendPKT(epin, &csw, sizeof(CSW));
		
	}
	return 0;
}

void mass_storage_assignep(u32 out, u32 out_size, u32 in, u32 in_size)
{
	epout = out;
	epin = in;
	confDesc.endpoint_descriptor[0].bEndpointAddress = (1<<7) | epin;
	confDesc.endpoint_descriptor[0].wMaxPacketSize = in_size;
	confDesc.endpoint_descriptor[1].bEndpointAddress = (0<<7) | epout;
	confDesc.endpoint_descriptor[1].wMaxPacketSize = out_size;
}
void init_mass_storage()
{
	massDevInit();
	massReset();
	mass_storage_assignep(5, MAX_EP5_SIZE, 2, MAX_EP2_SIZE);
}