⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stor.c

📁 一个USB主机核的驱动程序
💻 C
字号:
/****************************************************************
*                      MT View Silicon Tech. Inc.
*
*    Copyright 2007, MT View Silicon Tech. Inc., ShangHai, China
*                    All rights reserved.
*
*
* Filename:      	stor.c
*
* Programmer:    	Grey
*
* Created: 	 		01/xx/2008
*
* Description: 		usb mass storage device driver
*					
*              
*****************************************************************/

#include "stor.h"
#include <string.h>

STORAGE			XDATA	gStor[TOTAL_STOR_NUM];
BYTE			XDATA	gStorMap = 0;

LOGICAL_UNIT	XDATA	gLu[TOTAL_LOGICAL_UNIT_NUM];
WORD			XDATA	gLuMap = 0;


/*------------------Allocate storage source------------------*/
extern STORAGE*
AllocStorage(VOID)
{
	BYTE		DATA	i;
	STORAGE*	DATA	stor;

	i = SearchMapZero(&gStorMap, TOTAL_STOR_NUM);
	if (i == TOTAL_STOR_NUM)
		return NULL;
	
	SetMap(&gStorMap, i);
	stor = &gStor[i];
	memset(stor, 0, sizeof(STORAGE));
	stor->Set = i;

	return stor;
}

extern VOID
FreeStorage(
	STORAGE			*stor
	)
{
	BYTE	DATA	i;

	for (i = 0; i < MAX_STOR_LOGICAL_UNIT_NUM; ++i)
	{
		if (stor->Lu[i] != NULL)
			FreeLogicalUnit(stor->Lu[i]);
	}

	ClearMap(&gStorMap, stor->Set);
}


extern LOGICAL_UNIT*
AllocLogicalUnit(VOID)
{
	BYTE			DATA	i;
	LOGICAL_UNIT*	DATA	lu;

	i = SearchMapZero(&gLuMap, TOTAL_LOGICAL_UNIT_NUM);
	if (i == TOTAL_LOGICAL_UNIT_NUM)
		return NULL;
	
	SetMap(&gLuMap, i);
	lu = &gLu[i];
	memset(lu, 0, sizeof(LOGICAL_UNIT));
	lu->Set = i;

	return lu;
}

extern VOID
FreeLogicalUnit(
	LOGICAL_UNIT	*lu
	)
{
	ClearMap(&gLuMap, lu->Set);
}

/*-----------------------------------------------------------*/


/*--------------------storage control pipe-------------------*/
extern BYTE
StorGetMaxLUN(
	STORAGE			*stor
	)
{
	/* send get max lun request */
	return UsbControlMsg(stor->Device,
						stor->Device->PipeCtrlIn,
						US_BULK_GET_MAX_LUN,
						(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
						0,
						stor->InterfaceNum,
						1,
						&stor->MaxLogicalUnitNum
						);
}

extern BYTE
StorResetRecovery(
	STORAGE			*stor
	)
{
	/* send get max lun request */
	return UsbControlMsg(stor->Device,
						stor->Device->PipeCtrlOut,
						US_BULK_RESET_REQUEST,
						(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
						0,
						stor->InterfaceNum,
						0,
						NULL
						);
}

extern BYTE
StorClearHalt(
	STORAGE			*stor,
	DWORD			pipe
	)
{
	return UsbClearHalt(stor->Device, pipe);
}


extern VOID
StorFillScsiCmd(
	BYTE		*buf,
	SCSI_CMD	*scsiCmd
	)
{
	memset(buf, 0, 16);
	switch(scsiCmd->Cmd)
	{
		case INQUIRY:
			buf[0] = INQUIRY;
			buf[1] = scsiCmd->Lun;		/* set scsi command lun */
			buf[1] <<= 5;
			buf[4] = 36;			/* set transfer length */
			break;

		case TEST_UNIT_READY:
			buf[0] = TEST_UNIT_READY;
			buf[1] = scsiCmd->Lun;		/* set scsi command lun */
			buf[1] <<= 5;
			buf[4] = 0;			/* set transfer length */
			break;

		case REQUEST_SENSE:
			buf[0] = REQUEST_SENSE;
			buf[1] = scsiCmd->Lun;		/* set scsi command lun */
			buf[1] <<= 5;
			buf[4] = 18;			/* set transfer length */
			break;

		case READ_CAPACITY:
			buf[0] = READ_CAPACITY;
			buf[1] = scsiCmd->Lun;		/* set scsi command lun */
			buf[1] <<= 5;
			buf[4] = 8;			/* set transfer length */
			break;

		case MODE_SENSE:
			buf[0] = MODE_SENSE;
			buf[1] = scsiCmd->Lun;		/* set scsi command lun */
			buf[1] <<= 5;

		case READ_10:
			buf[0] = READ_10;

			buf[1] = scsiCmd->Lun;		/* set scsi command lun */
			buf[1] <<= 5;

			buf[2] = (scsiCmd->Lba >> 24);		/* set LBA */
			buf[3] = (scsiCmd->Lba >> 16);
			buf[4] = (scsiCmd->Lba >> 8);
			buf[5] = scsiCmd->Lba;

			buf[7] = ((scsiCmd->BufLen / scsiCmd->BlockSize) >> 8);		/* set transfer length */
			buf[8] = scsiCmd->BufLen / scsiCmd->BlockSize;

		default:
			break;
	}/* end switch */
}


extern BYTE
StorBulkTransport(
	STORAGE		*stor,
	SCSI_CMD	*scsiCmd
	)
{
	CBW			cbw;
	WORD		actLength;
	DWORD		pipe;
	BYTE		scsi[16];
	CSW			csw;
	BYTE		err;
	BYTE		transportStatus = 0;
	BYTE		to;

	/* fill scsi command buffer */
	StorFillScsiCmd(scsi, scsiCmd);		

	/* config CBW */
	memset(&cbw, 0, sizeof(CBW));
	cbw.Signature = LE32ToCPU(US_BULK_CB_SIGN);
	cbw.Tag = GetSysTime();
	cbw.DataTransferLength = LE32ToCPU(scsiCmd->BufLen);
	cbw.Flags = (scsiCmd->DataDirection << 7);
	cbw.Lun = scsiCmd->Lun;
	cbw.Length = scsiCmd->CmdLen;
	memcpy(cbw.CDB, scsi, sizeof(cbw.CDB));

	/* bulk transfer status stream control */
	to = 10;
	while(to)
	{
		if (transportStatus == 0)		
		{
			/* send CBW */
			err = UsbBulkMsg(stor->Device,
							stor->PipeBulkOut,
							&cbw,
							sizeof(CBW),
							FALSE,
							&actLength
							);
			if (err == STALL)
			{
				/* mass storage spec 5.3.1 and 5.3.4 */
				if (StorResetRecovery(stor) != NO_ERROR)
					return STOR_TRANSPORT_ERR;
				if (StorClearHalt(stor, stor->PipeBulkIn) != NO_ERROR)
					return STOR_TRANSPORT_ERR;
				if (StorClearHalt(stor, stor->PipeBulkOut) != NO_ERROR)
					return STOR_TRANSPORT_ERR;
				/* recovery storage successful and resend the cbw */
			}
			else if (err == DEVICE_NOT_RESPONDING)
			{
				return STOR_TRANSPORT_ERR;
			}
			else if (err == ERR)
			{
				return STOR_TRANSPORT_ERR;
			}
			else if (err == NO_ERROR)
			{
				transportStatus = (cbw.DataTransferLength != 0) ? 1 : 2;
			}
			else
			{
				return UNKNOW;
			}
		}
		else if (transportStatus == 1)
		{
			/* send or receive data */
			pipe = (scsiCmd->DataDirection == US_BULK_FLAG_IN) ? stor->PipeBulkIn : stor->PipeBulkOut;
			err = UsbBulkMsg(stor->Device,
							pipe,
							scsiCmd->Buf,
							scsiCmd->BufLen,
							(scsiCmd->Cmd == READ_10 || scsiCmd->Cmd == WRITE_10),
							&actLength
							);
			if (err == STALL)
			{
				/* if data transport stall, there is a bug in the code, return failed directly */
				StorClearHalt(stor, pipe);
				return STOR_TRANSPORT_ERR;
			}
			else if (err == DEVICE_NOT_RESPONDING)
			{
				return STOR_TRANSPORT_ERR;
			}
			else if (err == ERR)
			{
				return STOR_TRANSPORT_ERR;
			}
			else if (err == NO_ERROR)
			{
				transportStatus = 2;
			}
			else
			{
				return UNKNOW;
			}
		}
		else if (transportStatus == 2)
		{
			/* receive csw */
			err = UsbBulkMsg(stor->Device,
							stor->PipeBulkIn,
							&csw,
							sizeof(CSW),
							FALSE,
							&actLength
							);
			if (err == STALL || err == DEVICE_NOT_RESPONDING)
			{
				if (StorClearHalt(stor, stor->PipeBulkIn) != NO_ERROR)
					return STOR_TRANSPORT_ERR;
			}
			else if (err == ERR)
			{
				return STOR_TRANSPORT_ERR;
			}
			else if (LE32ToCPU(csw.Signature) != US_BULK_CS_SIGN || csw.Tag != cbw.Tag)
			{
				/* invalid csw, recorvery storage device and resend cbw */
				if (StorResetRecovery(stor) != NO_ERROR)
					return US_BULK_STAT_FAIL;	
				transportStatus = 0;
			}
			else if (csw.Status == US_BULK_STAT_FAIL)
			{
				return US_BULK_STAT_FAIL;
			}
			else if (csw.Status == US_BULK_STAT_PHASE)
			{
				return STOR_TRANSPORT_ERR;
			}
			else
			{
				return US_BULK_STAT_OK;
			}
		}
		else
		{
			return UNKNOW;
		}
		to--;
	}/* end while */
	
	return STOR_TRANSPORT_ERR;
}


extern BYTE
StorInquiry(
	STORAGE			*stor,
	BYTE			lun,
	BYTE			*buf,
	BYTE			size
	)
{
	SCSI_CMD		scsiCmd;

	scsiCmd.Cmd = INQUIRY;
	scsiCmd.CmdLen = 6;
	scsiCmd.Lun = lun;
	scsiCmd.DataDirection = US_BULK_FLAG_IN;
	scsiCmd.Buf = buf;
	scsiCmd.BufLen = size;

	return StorBulkTransport(stor, &scsiCmd);
}


extern BYTE
StorTestUnitReady(
	STORAGE			*stor,
	BYTE			lun
	)
{
	SCSI_CMD		scsiCmd;
	
	scsiCmd.Cmd = TEST_UNIT_READY;
	scsiCmd.CmdLen = 6;
	scsiCmd.Lun = lun;
	scsiCmd.DataDirection = US_BULK_FLAG_OUT;
	scsiCmd.Buf = NULL;
	scsiCmd.BufLen = 0;

	return StorBulkTransport(stor, &scsiCmd);
}


extern BYTE
StorRequestSense(
	STORAGE			*stor,
	BYTE			lun,
	BYTE			*buf,
	BYTE			size
	)
{
	SCSI_CMD		scsiCmd;
	
	scsiCmd.Cmd = REQUEST_SENSE;
	scsiCmd.CmdLen = 12;
	scsiCmd.Lun = lun;
	scsiCmd.DataDirection = US_BULK_FLAG_IN;
	scsiCmd.Buf = buf;
	scsiCmd.BufLen = size;

	return StorBulkTransport(stor, &scsiCmd);
}



extern BYTE
StorReadCapacity(
	STORAGE			*stor,
	BYTE			lun,
	BYTE			*buf,
	BYTE			size
	)
{
	SCSI_CMD		scsiCmd;
	
	scsiCmd.Cmd = READ_CAPACITY;
	scsiCmd.CmdLen = 10;
	scsiCmd.Lun = lun;
	scsiCmd.DataDirection = US_BULK_FLAG_IN;
	scsiCmd.Buf = buf;
	scsiCmd.BufLen = size;

	return StorBulkTransport(stor, &scsiCmd);
}
/*-----------------------------------------------------------*/

/*-------------------file system interface-------------------*/
extern BYTE
StorReadBlock(
	BYTE		lun,
	DWORD		lba,
	VOID		*buf,
	WORD		size	
	)
{
	LOGICAL_UNIT	*lu;
	SCSI_CMD		scsiCmd;

	lu = &gLu[lun];
	if (lba > lu->LastLBA)
		return STOR_TRANSPORT_ERR;

	scsiCmd.Cmd = READ_10;
	scsiCmd.CmdLen = 10;
	scsiCmd.Lun = lun;
	scsiCmd.DataDirection = US_BULK_FLAG_IN;
	scsiCmd.Buf = buf;
	scsiCmd.BufLen = size * lu->BlockSize;
	scsiCmd.Lba = lba;
	scsiCmd.BlockSize = lu->BlockSize;

	return StorBulkTransport(lu->Stor, &scsiCmd);
}


extern BYTE
GetStorLun(VOID)
{
	BYTE	i, retVal = 0;

	for (i = 0; i < TOTAL_LOGICAL_UNIT_NUM; ++i)
	{
		if ((gLuMap & (0x01 << i)) != 0
			&& gLu[i].BlockSize != 0)
		retVal++;
	}

	return retVal;
}

/*-----------------------------------------------------------*/

/*--------------------init storage device--------------------*/
extern BOOL
OpenStor(
	STORAGE			*stor,
	USB_DEVICE		*device,
	USB_CONFIG		*config,
	USB_INTERFACE	*interface
	)
{
	USB_ENDPOINT	*endpoint;
	LOGICAL_UNIT	*lu;
	DWORD			temp;
	BYTE			i, j;
	BYTE			buffer[64];
	BYTE			to;

	stor->Device = device;
	stor->Interface = interface;
	stor->InterfaceNum = interface->InterfaceDescriptor.bInterfaceNumber;
	stor->SubClass = interface->InterfaceDescriptor.bInterfaceSubClass;
	stor->Protocol = interface->InterfaceDescriptor.bInterfaceProtocol;

	/* open pipe */
	for (i = 0; i < interface->InterfaceDescriptor.bNumEndpoints; ++i)
	{
		endpoint = interface->Endpoint[i];
		if ((endpoint->EndpointDescriptor.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
		{
			if ((endpoint->EndpointDescriptor.bEndpointAddress & USB_DIR_IN) == USB_DIR_IN)
			{
				/* load bulk in pipe */
				stor->PipeBulkIn = 0xC0000080;
				temp = (endpoint->EndpointDescriptor.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
				temp <<= 15;
				stor->PipeBulkIn |= temp;
				temp = device->DevAddress;
				temp <<= 8;
				stor->PipeBulkIn |= temp;
				temp = LE16ToCPU(endpoint->EndpointDescriptor.wMaxPacketSize);
				j = 0;
				while(temp > 0x0008)
				{
					j++;
					temp >>= 1;
				}
				stor->PipeBulkIn |= j;
			}
			else
			{
				/* load bulk out pipe */
				stor->PipeBulkOut = 0xC0000000;
				temp = (endpoint->EndpointDescriptor.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
				temp <<= 15;
				stor->PipeBulkOut |= temp;
				temp = device->DevAddress;
				temp <<= 8;
				stor->PipeBulkOut |= temp;
				temp = LE16ToCPU(endpoint->EndpointDescriptor.wMaxPacketSize);
				j = 0;
				while(temp > 0x0008)
				{
					j++;
					temp >>= 1;
				}
				stor->PipeBulkOut |= j;
			}
		}
		else
		{
			/* ignore other endpoint */
			continue;
		}
	}/* end for */

	/* set usb device configuration */
	if (UsbSetDeviceConfig(device, config, interface) != NO_ERROR)
		return FALSE;

	/* get storage max lun */
	if (StorGetMaxLUN(stor) != NO_ERROR)
		return FALSE;

	for (i = 0; i < stor->MaxLogicalUnitNum + 1; ++i)
	{
		lu = AllocLogicalUnit();
		if (lu == NULL)
			return FALSE;
		stor->Lu[i] = lu;
		lu->Stor = stor;
		lu->LogicalUnitNum = i;
		
		if (StorInquiry(stor, i, buffer, 36) != US_BULK_STAT_OK)
			return FALSE;

		for (to = 0; to < 3; ++to)
		{
			if (StorTestUnitReady(stor, i) != US_BULK_STAT_OK)
			{
				if (StorRequestSense(stor, i, buffer, 18) != US_BULK_STAT_OK)
					break;
				continue;
			}/* end if */

			if (StorReadCapacity(stor, i, buffer, 8) != US_BULK_STAT_OK)
				continue;
			lu->LastLBA = *(DWORD *)buffer;
			lu->BlockSize = *(DWORD *)(buffer + 4);
			break;
		}/* end for (to = 0; to < 3; ++to) */
	}/* end for (i = 0; i < stor->MaxLogicalUnitNum + 1; ++i) */
	
	return TRUE;
}





/*-----------------------------------------------------------*/






⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -