📄 usbbulkdevlib.c
字号:
/***************************************************************************** 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 */ pBulkDev->bulkCbw.CBD[2] = 0x0; pBulkDev->bulkCbw.CBD[3] = 0x0; 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 */ /* * For WRITE6 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 = 0x06; pBulkDev->bulkCbw.CBD[0] = USB_SCSI_WRITE6; pBulkDev->bulkCbw.CBD[1] = 0x0; pBulkDev->bulkCbw.CBD[2] = (UINT8)((cmdParam1 & 0xFF00) >>8) ; pBulkDev->bulkCbw.CBD[3] = (UINT8)(cmdParam1 & 0xFF); pBulkDev->bulkCbw.CBD[4] = (UINT8)cmdParam2; pBulkDev->bulkCbw.CBD[5] = 0x0; break; case USB_SCSI_READ10: /* 10-byte SCSI READ command */ cmdParam1 += pBulkDev->blkOffset; /* * For READ10 command, cmdParam1 refers to the block number from * which cmdParam2 number of blocks are to be read. 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_IN; pBulkDev->bulkCbw.length = 0x0A; pBulkDev->bulkCbw.CBD[0] = 0x28; /* op code */ pBulkDev->bulkCbw.CBD[1] = 0x0; /* DPU, FOA, and RELADR bits*/ pBulkDev->bulkCbw.CBD[2] = 0x0; /* lba is bytes 2-5 MSB */ pBulkDev->bulkCbw.CBD[3] = 0x0; /* lba is bytes 2-5 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -