📄 usbbulkdevlib.c
字号:
{
OSS_MUTEX_DESTROY (bulkDevMutex);
bulkDevMutex = NULL;
}
if (bulkIrpSem != NULL)
{
OSS_SEM_DESTROY (bulkIrpSem);
bulkIrpSem = NULL;
}
initCount--;
return ossStatus (errCode);
}
/***************************************************************************
*
* usbBulkDevInit - registers USB Bulk only mass storage class driver.
*
* This routine registers the mass storage class driver with USB driver. It
* also registers attach callback routine to get notified of the USB/MSC/BULK
* ONLY devices.
*
* RETURNS: OK, or ERROR if unable to register with USBD.
*
* ERRNO:
* S_usbbulkDevLib_OUT_OF_RESOURCES
* S_usbbulkDevLib_USBD_FAULT
*/
STATUS usbBulkDevInit (void)
{
/*
* Check whether already initilized. If not, then initialise the required
* structures and register the class driver with USBD.
*/
if (initCount == 0)
{
memset (&bulkDevList, 0, sizeof (bulkDevList));
memset (&reqList, 0, sizeof (reqList));
bulkDevMutex = NULL;
bulkIrpSem = NULL;
usbdHandle = NULL;
if (OSS_MUTEX_CREATE (&bulkDevMutex) != OK)
return (usbBulkDevShutDown (S_usbBulkDevLib_OUT_OF_RESOURCES));
if (OSS_SEM_CREATE (1, 1 , &bulkIrpSem) != OK)
return (usbBulkDevShutDown (S_usbBulkDevLib_OUT_OF_RESOURCES));
/* Establish connection to USBD and register for attach callback */
if (usbdClientRegister ("BULK_CLASS", &usbdHandle) != OK ||
usbdDynamicAttachRegister (usbdHandle, USB_CLASS_MASS_STORAGE,
USB_SUBCLASS_SCSI_COMMAND_SET,
USB_INTERFACE_PROTOCOL_BULK_ONLY,
usbBulkDevAttachCallback) != OK)
{
USB_BULK_ERR ("usbBulkDevInit: Client Registration Failed \n",
0, 0, 0, 0, 0, 0);
return usbBulkDevShutDown (S_usbBulkDevLib_USBD_FAULT);
}
}
initCount++;
return (OK);
}
/***************************************************************************
*
* usbBulkDevIoctl - perform a device-specific control.
*
* Typically called to invoke device-specific functions which are not needed
* by a file system.
*
* RETURNS: The status of the request, or ERROR if the request is unsupported.
*/
STATUS usbBulkDevIoctl
(
BLK_DEV * pBlkDev, /* pointer to bulk device */
int request, /* request type */
int someArg /* arguments related to request */
)
{
UINT16 actLen= 0xffff;
/* get a pointer to the bulk device */
pUSB_BULK_DEV pBulkDev = (USB_BULK_DEV *)pBlkDev;
if ( pBulkDev == (pUSB_BULK_DEV)NULL )
return (ERROR);
/* Check whether the device exists or not */
if (usbBulkDevFind (pBulkDev->bulkDevId) != pBulkDev)
{
USB_BULK_ERR ("usbBulkDevIoctl: Bulk Device not found\n",
0, 0, 0, 0, 0, 0);
return (ERROR);
}
switch (request)
{
case FIODISKFORMAT:
/*
* This is the IO control function supported by file system,
* but supplied by the device driver. Other IO control functions
* are directly handled by file system with out the use of this
* routine.
*/
if ( usbBulkFormScsiCmd (pBulkDev,
USB_SCSI_FORMAT_UNIT,
NULL,
NULL)
!= OK )
return (ERROR);
if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
{
USB_BULK_ERR ("usbBulkDevIoctl: FORMAT UNIT Command failed\n",
0, 0, 0, 0, 0, 0);
return (ERROR);
}
return (OK);
case USB_BULK_DESCRIPTOR_GET:
/* invoke routine to display all descriptors */
return (usbBulkDescShow (pBulkDev->bulkDevId));
case USB_BULK_DEV_RESET:
/* send a class-specific mass storage reset command */
return (usbBulkDevResetRecovery (pBulkDev));
case USB_BULK_EJECT_MEDIA:
/* Only applicable if media is removable */
if ( pBulkDev->blkDev.bd_removable != TRUE )
return (ERROR);
else
{
if ( usbBulkFormScsiCmd (pBulkDev,
USB_SCSI_START_STOP_START,
USB_SCSI_START_STOP_LOEJ,
NULL)
!= OK )
return (ERROR);
if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
{
USB_BULK_ERR ("usbBulkDevIoctl: EJECT Command " \
"failed\n", 0, 0, 0, 0, 0, 0);
return (ERROR);
}
}
return (OK);
case USB_BULK_MAX_LUN:
/* May not be supported by devices having single LUN */
if (usbdVendorSpecific (usbdHandle, pBulkDev->bulkDevId,
USB_RT_DEV_TO_HOST | USB_RT_CLASS | USB_RT_INTERFACE,
USB_BULK_GET_MAX_LUN, 0, pBulkDev->interface, 1,
&(pBulkDev->maxLun), &actLen) != OK )
{
USB_BULK_ERR ("usbBulkDevIoctl: Failed to acquire max lun \n",
0, 0, 0, 0, 0, 0);
}
else
{
USB_BULK_DEBUG ("usbBulkDevIoctl: Max Lun = %c \n",
pBulkDev->maxLun, 0, 0, 0, 0, 0);
}
return (OK);
default:
errnoSet (S_ioLib_UNKNOWN_REQUEST);
USB_BULK_DEBUG ("usbBulkDevIoctl: Unknown Request\n",
0, 0, 0, 0, 0, 0);
return (ERROR);
}
}
/***************************************************************************
*
* usbBulkDevResetRecovery - Performs reset recovery on the specified device.
*
* Reset recovery shall be done when device returns a phase error status
* while executing a CBW. It is also done, when a stall condition is detected
* on bulk-out endpoint during CBW transport. The following sequence is
* performed on the device
*
* - BulkOnly Mass Storage Reset
* - Clear HALT feature on the Bulk-in Endpoint
* - Clear HALT feature on the Bulk-out Endpoint
*
* RETURNS: OK, if reset sequence successful otherwise ERROR.
*/
LOCAL STATUS usbBulkDevResetRecovery
(
pUSB_BULK_DEV pBulkDev /* pointer to bulk device */
)
{
OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
/* issue bulk-only mass storage reset request on control End point */
if ((usbdVendorSpecific (usbdHandle,
pBulkDev->bulkDevId,
USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
USB_BULK_RESET,
0,
pBulkDev->interface,
0,
NULL,
NULL))
!= OK )
{
USB_BULK_ERR ("usbBulkDevResetRecovery: Failed to reset %x\n",
0, 0, 0, 0, 0, 0);
OSS_MUTEX_RELEASE (bulkDevMutex);
return (ERROR);
}
else
{
USB_BULK_DEBUG ("usbBulkDevResetRecovery: Reset...done\n",
0, 0, 0, 0, 0, 0);
}
/* clear HALT feature on bulk in and bulk out end points */
if ((usbdFeatureClear (usbdHandle,
pBulkDev->bulkDevId,
USB_RT_ENDPOINT,
USB_FSEL_DEV_ENDPOINT_HALT,
(pBulkDev->inEpAddress & 0x0F)))
!= OK)
{
USB_BULK_ERR ("usbBulkDevResetRecovery: Failed to clear HALT feauture"\
" on bulk in Endpoint %x\n", 0, 0, 0, 0, 0, 0);
}
if ((usbdFeatureClear (usbdHandle,
pBulkDev->bulkDevId,
USB_RT_ENDPOINT,
USB_FSEL_DEV_ENDPOINT_HALT,
(pBulkDev->outEpAddress & 0x0F)))
!= OK)
{
USB_BULK_ERR ("usbBulkDevResetRecovery: Failed to clear HALT feauture"\
" on bulk out Endpoint %x\n", 0, 0, 0, 0, 0, 0);
}
OSS_MUTEX_RELEASE (bulkDevMutex);
return (OK);
}
/***************************************************************************
*
* usbBulkFormScsiCmd - forms command block wrapper(CBW) for requested SCSI command
*
* This routine forms SCSI command blocks as per the Bulk-only command
* specifications and SCSI protocol.
*
* The following are the input parameters
*
* .IP <pBulkDev>
* pointer to USB/BULK-ONLY/SCSI device for which the command has to be formed.
*
* .IP <scsiCmd>
* identifies the SCSI command to be formed.
*
* .IP <cmdParam1>
* parameter required to form a SCSI comamnd, if any.
*
* .IP <cmdParam2>
* parameter required to form a SCSI comamnd, if any.
*
* RETURNS: OK, or ERROR if the command is unsupported.
*/
LOCAL STATUS usbBulkFormScsiCmd
(
pUSB_BULK_DEV pBulkDev, /* pointer to bulk device */
UINT scsiCmd, /* SCSI command */
UINT cmdParam1, /* command parameter */
UINT cmdParam2 /* command parameter */
)
{
BOOL status = OK;
/* TODO : how to support a LUN other than 0. Also support for more than
* one scsi device on the usb-scsi bus. how can we get SCSI ID
*/
pBulkDev->bulkCbw.signature = USB_BULK_SWAP_32 (USB_CBW_SIGNATURE);
pBulkDev->bulkCbw.tag = USB_BULK_SWAP_32 (USB_CBW_TAG);
pBulkDev->bulkCbw.lun = 0x00;
switch (scsiCmd)
{
case USB_SCSI_WRITE10: /* 6-byte SCSI WRITE command */
cmdParam1 += pBulkDev->blkOffset; /* add offset to blk number */
/*
* For WRITE10 command, cmdParam1 refers to the block number from
* which cmdParam2 number of blocks are to be written. Calculate
* the transfer length based on the block size and num. of blocks
*/
pBulkDev->bulkCbw.dataXferLength = USB_BULK_SWAP_32(((cmdParam2) *
(pBulkDev->blkDev.bd_bytesPerBlk)));
pBulkDev->bulkCbw.direction = USB_CBW_DIR_OUT;
pBulkDev->bulkCbw.length = 0x0A;
/* op code */
pBulkDev->bulkCbw.CBD[0] = 0x2A;
/* DPU, FOA, and RELADR bits*/
pBulkDev->bulkCbw.CBD[1] = 0x0;
/* lba is bytes 2-5 MSB first, LSB .last */
#if 0
pBulkDev->bulkCbw.CBD[2] = 0x0;
pBulkDev->bulkCbw.CBD[3] = 0x0;
#else
pBulkDev->bulkCbw.CBD[2] = (UINT8)((cmdParam1 & 0xFF000000) >>24);;
pBulkDev->bulkCbw.CBD[3] = (UINT8)((cmdParam1 & 0xFF0000) >>16);;
#endif
pBulkDev->bulkCbw.CBD[4] = (UINT8)((cmdParam1 & 0xFF00) >>8);
pBulkDev->bulkCbw.CBD[5] = (UINT8)(cmdParam1 & 0xFF);
/* Reserved */
pBulkDev->bulkCbw.CBD[6] = 0x0;
/* transfer length */
pBulkDev->bulkCbw.CBD[7] = (UINT8)((cmdParam2 & 0xFF00) >>8);
pBulkDev->bulkCbw.CBD[8] = (UINT8)(cmdParam2 & 0xFF);
/* Control */
pBulkDev->bulkCbw.CBD[9] = 0x0;
break;
case USB_SCSI_WRITE6: /* 6-byte SCSI WRITE command */
cmdParam1 += pBulkDev->blkOffset; /* add offset to blk number */
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -