| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- //*****************************************************************************
- //
- // usbhmsc.c - USB MSC host driver.
- //
- // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
- // Software License Agreement
- //
- // Texas Instruments (TI) is supplying this software for use solely and
- // exclusively on TI's microcontroller products. The software is owned by
- // TI and/or its suppliers, and is protected under applicable copyright
- // laws. You may not combine this software with "viral" open-source
- // software in order to form a larger program.
- //
- // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
- // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
- // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
- // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
- // DAMAGES, FOR ANY REASON WHATSOEVER.
- //
- // This is part of AM1808 StarterWare USB Library, resused from revision 6288 of the
- // stellaris USB Library
- //
- //*****************************************************************************
- #include "hw_types.h"
- #include "usb.h"
- #include "usblib.h"
- #include "usbmsc.h"
- #include "usbhost.h"
- #include "usbhmsc.h"
- #include "usbhscsi.h"
- //*****************************************************************************
- //
- //! \addtogroup usblib_host_class
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // Forward declarations for the driver open and close calls.
- //
- //*****************************************************************************
- static void *USBHMSCOpen(tUSBHostDevice *pDevice, unsigned int ulDeviceNum);
- static void USBHMSCClose(void *pvInstance);
- extern tUSBHCD g_sUSBHCD[];
- //*****************************************************************************
- //
- // The array of USB MSC host drivers.
- //
- //*****************************************************************************
- tUSBHMSCInstance g_USBHMSCDevice[USB_NUM_INSTANCE];
- //*****************************************************************************
- //
- //! This constant global structure defines the Mass Storage Class Driver that
- //! is provided with the USB library.
- //
- //*****************************************************************************
- const tUSBHostClassDriver g_USBHostMSCClassDriver =
- {
- USB_CLASS_MASS_STORAGE,
- USBHMSCOpen,
- USBHMSCClose,
- 0
- };
- //*****************************************************************************
- //
- //! This function is used to open an instance of the MSC driver.
- //!
- //! \param pDevice is a pointer to the device information structure.
- //!
- //! This function will attempt to open an instance of the MSC driver based on
- //! the information contained in the pDevice structure. This call can fail if
- //! there are not sufficient resources to open the device. The function will
- //! return a value that should be passed back into USBMSCClose() when the
- //! driver is no longer needed.
- //!
- //! \return The function will return a pointer to a MSC driver instance.
- //
- //*****************************************************************************
- static void *
- USBHMSCOpen(tUSBHostDevice *pDevice, unsigned int ulInstance)
- {
- int iIdx;
- tEndpointDescriptor *pEndpointDescriptor;
- tInterfaceDescriptor *pInterface;
- tUSBHMSCInstance *sUSBHMSCDevice;
- sUSBHMSCDevice = (tUSBHMSCInstance *)ulInstance;
-
- unsigned int ulIndex = sUSBHMSCDevice->ulIndex;
- //
- // Don't allow the device to be opened without closing first.
- //
- if(sUSBHMSCDevice->pDevice)
- {
- return(0);
- }
- //
- // Save the device pointer.
- //
- sUSBHMSCDevice->pDevice = pDevice;
- //
- // Get the interface descriptor.
- //
- pInterface = USBDescGetInterface(pDevice->pConfigDescriptor, 0, 0);
- //
- // Loop through the endpoints of the device.
- //
- for(iIdx = 0; iIdx < 3; iIdx++)
- {
- //
- // Get the first endpoint descriptor.
- //
- pEndpointDescriptor =
- USBDescGetInterfaceEndpoint(pInterface, iIdx,
- pDevice->ulConfigDescriptorSize);
- //
- // If no more endpoints then break out.
- //
- if(pEndpointDescriptor == 0)
- {
- break;
- }
- //
- // See if this is a bulk endpoint.
- //
- if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
- USB_EP_ATTR_BULK)
- {
- //
- // See if this is bulk IN or bulk OUT.
- //
- if(pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
- {
- //
- // Allocate the USB Pipe for this Bulk IN endpoint.
- //
- sUSBHMSCDevice->ulBulkInPipe =
- USBHCDPipeAllocSize(ulIndex, USBHCD_PIPE_BULK_IN_DMA,
- pDevice->ulAddress,
- pEndpointDescriptor->wMaxPacketSize,
- 0);
- //
- // Configure the USB pipe as a Bulk IN endpoint.
- //
- USBHCDPipeConfig(ulIndex, sUSBHMSCDevice->ulBulkInPipe,
- pEndpointDescriptor->wMaxPacketSize,
- 0,
- (pEndpointDescriptor->bEndpointAddress &
- USB_EP_DESC_NUM_M));
- }
- else
- {
- //
- // Allocate the USB Pipe for this Bulk OUT endpoint.
- //
- sUSBHMSCDevice->ulBulkOutPipe =
- USBHCDPipeAllocSize(ulIndex, USBHCD_PIPE_BULK_OUT_DMA,
- pDevice->ulAddress,
- pEndpointDescriptor->wMaxPacketSize,
- 0);
- //
- // Configure the USB pipe as a Bulk OUT endpoint.
- //
- USBHCDPipeConfig(ulIndex, sUSBHMSCDevice->ulBulkOutPipe,
- pEndpointDescriptor->wMaxPacketSize,
- 0,
- (pEndpointDescriptor->bEndpointAddress &
- USB_EP_DESC_NUM_M));
- }
- }
- }
- //
- // If the callback exists, call it with an Open event.
- //
- if(sUSBHMSCDevice->pfnCallback != 0)
- {
- sUSBHMSCDevice->pfnCallback((unsigned int)sUSBHMSCDevice,
- MSC_EVENT_OPEN, 0);
- }
- //
- // Return the only instance of this device.
- //
- return(sUSBHMSCDevice);
- }
- //*****************************************************************************
- //
- //! This function is used to release an instance of the MSC driver.
- //!
- //! \param pvInstance is an instance pointer that needs to be released.
- //!
- //! This function will free up any resources in use by the MSC driver instance
- //! that is passed in. The \e pvInstance pointer should be a valid value that
- //! was returned from a call to USBMSCOpen().
- //!
- //! \return None.
- //
- //*****************************************************************************
- static void
- USBHMSCClose(void *pvInstance)
- {
- tUSBHMSCInstance *sUSBHMSCDevice;
- sUSBHMSCDevice = (tUSBHMSCInstance *)pvInstance;
-
- //
- // Do nothing if there is not a driver open.
- //
- if(sUSBHMSCDevice->pDevice == 0)
- {
- return;
- }
- //
- // Reset the device pointer.
- //
- sUSBHMSCDevice->pDevice = 0;
- //
- // Free the Bulk IN pipe.
- //
- if(sUSBHMSCDevice->ulBulkInPipe != 0)
- {
- USBHCDPipeFree(sUSBHMSCDevice->ulIndex, sUSBHMSCDevice->ulBulkInPipe);
- }
- //
- // Free the Bulk OUT pipe.
- //
- if(sUSBHMSCDevice->ulBulkOutPipe != 0)
- {
- USBHCDPipeFree(sUSBHMSCDevice->ulIndex, sUSBHMSCDevice->ulBulkOutPipe);
- }
- //
- // If the callback exists then call it.
- //
- if(sUSBHMSCDevice->pfnCallback != 0)
- {
- sUSBHMSCDevice->pfnCallback((unsigned int)sUSBHMSCDevice,
- MSC_EVENT_CLOSE, 0);
- }
- }
- //*****************************************************************************
- //
- //! This function retrieves the maximum number of the logical units on a
- //! mass storage device.
- //!
- //! \param ulAddress is the device address on the USB bus.
- //! \param ulInterface is the interface number on the device specified by the
- //! \e ulAddress parameter.
- //! \param pucMaxLUN is the byte value returned from the device for the
- //! device's maximum logical unit.
- //!
- //! The device will return one byte of data that contains the maximum LUN
- //! supported by the device. For example, if the device supports four LUNs
- //! then the LUNs would be numbered from 0 to 3 and the return value would be
- //! 3. If no LUN is associated with the device, the value returned shall be 0.
- //!
- //! \return None.
- //
- //*****************************************************************************
- static void
- USBHMSCGetMaxLUN(unsigned int ulIndex, unsigned int ulAddress,
- unsigned int ulInterface, unsigned char *pucMaxLUN)
- {
- tUSBRequest SetupPacket;
-
-
- //
- // This is a Class specific interface IN request.
- //
- SetupPacket.bmRequestType =
- USB_RTYPE_DIR_IN | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE;
- //
- // Request a the Max LUN for this interface.
- //
- SetupPacket.bRequest = USBREQ_GET_MAX_LUN;
- SetupPacket.wValue = 0;
- //
- // Indicate the interface to use.
- //
- SetupPacket.wIndex = (unsigned short)ulInterface;
- //
- // Only request a single byte of data.
- //
- SetupPacket.wLength = 1;
- //
- // Put the setup packet in the buffer and send the command.
- //
- if(USBHCDControlTransfer(ulIndex, &SetupPacket, ulAddress, pucMaxLUN, 1,
- MAX_PACKET_SIZE_EP0) != 1)
- {
- *pucMaxLUN = 0;
- }
- }
- //*****************************************************************************
- //
- //! This function checks if a drive is ready to be accessed.
- //!
- //! \param ulInstance is the device instance to use for this read.
- //!
- //! This function checks if the current device is ready to be accessed.
- //! It uses the \e ulInstance parameter to determine which device to check and
- //! will return zero when the device is ready. Any non-zero return code
- //! indicates that the device was not ready.
- //!
- //! \return This function will return zero if the device is ready and it will
- //! return a other value if the device is not ready or if an error occurred.
- //
- //*****************************************************************************
- int
- USBHMSCDriveReady(unsigned int ulInstance)
- {
- unsigned char ucMaxLUN, pBuffer[SCSI_INQUIRY_DATA_SZ];
- unsigned int ulSize;
- tUSBHMSCInstance *pMSCDevice;
- //
- // Get the instance pointer in a more usable form.
- //
- pMSCDevice = (tUSBHMSCInstance *)ulInstance;
- //
- // If there is no device present then return an error.
- //
- if(pMSCDevice->pDevice == 0)
- {
- return(-1);
- }
- //
- // Get the Maximum LUNs on this device.
- //
- USBHMSCGetMaxLUN(pMSCDevice->ulIndex, pMSCDevice->pDevice->ulAddress,
- pMSCDevice->pDevice->ulInterface, &ucMaxLUN);
- //
- // Save the Maximum number of LUNs on this device.
- //
- pMSCDevice->ulMaxLUN = ucMaxLUN;
- //
- // Issue a SCSI Inquiry to get basic information on the device
- //
- ulSize = SCSI_INQUIRY_DATA_SZ;
- if((USBHSCSIInquiry(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe,
- pBuffer, &ulSize) != SCSI_CMD_STATUS_PASS))
- {
- return(-1);
- }
- //
- // See if the drive is ready to use.
- //
- if(USBHSCSITestUnitReady(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe) != SCSI_CMD_STATUS_PASS)
- {
- //
- // Get the current sense data from the device to see why it failed
- // the Test Unit Ready command.
- //
- ulSize = SCSI_REQUEST_SENSE_SZ;
- USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize);
- }
-
- //
- // Send Request Sense agian, return if device returnss command fail
- //
- ulSize = SCSI_REQUEST_SENSE_SZ;
- if(USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize)
- != SCSI_CMD_STATUS_PASS)
- {
- return(-1);
- }
- if((pBuffer[SCSI_RS_SKEY] == SCSI_RS_KEY_UNIT_ATTN) &&
- (pBuffer[SCSI_RS_SKEY_AD_SKEY] == SCSI_RS_KEY_NOTPRSNT))
- {
- return(-1);
- }
- //
- // Get the size of the drive.
- //
- ulSize = SCSI_INQUIRY_DATA_SZ;
- if(USBHSCSIReadCapacity(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe,
- pBuffer, &ulSize) != SCSI_CMD_STATUS_PASS)
- {
- //
- // Get the current sense data from the device to see why it failed
- // the Read Capacity command.
- //
- ulSize = SCSI_REQUEST_SENSE_SZ;
- USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize);
- return(-1);
- }
- else
- {
- //
- // Read the block size out, value is stored big endian.
- //
- pMSCDevice->ulBlockSize =
- (pBuffer[7] | (pBuffer[6] << 8) | pBuffer[5] << 16 |
- (pBuffer[4] << 24));
- //
- // Read the block size out.
- //
- pMSCDevice->ulNumBlocks =
- (pBuffer[3] | (pBuffer[2] << 8) | pBuffer[1] << 16 |
- (pBuffer[0] << 24));
- }
-
- //
- // Check whether unit is ready again
- //
- if(USBHSCSITestUnitReady(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe) != SCSI_CMD_STATUS_PASS)
- {
- //
- // Get the current sense data from the device to see why it failed
- // the Test Unit Ready command.
- //
- ulSize = SCSI_REQUEST_SENSE_SZ;
- USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize);
- return(-1);
- }
- else
- {
- //
- // Success.
- //
- return(0);
- }
- }
- //*****************************************************************************
- //
- //! This function should be called before any devices are present to enable
- //! the mass storage device class driver.
- //!
- //! \param ulDrive is the drive number to open.
- //! \param pfnCallback is the driver callback for any mass storage events.
- //!
- //! This function is called to open an instance of a mass storage device. It
- //! should be called before any devices are connected to allow for proper
- //! notification of drive connection and disconnection. The \e ulDrive
- //! parameter is a zero based index of the drives present in the system.
- //! There are a constant number of drives, and this number should only
- //! be greater than 0 if there is a USB hub present in the system. The
- //! application should also provide the \e pfnCallback to be notified of mass
- //! storage related events like device enumeration and device removal.
- //!
- //! \return This function will return the driver instance to use for the other
- //! mass storage functions. If there is no driver available at the time of
- //! this call, this function will return zero.
- //
- //*****************************************************************************
- unsigned int
- USBHMSCDriveOpen(unsigned int ulIndex, unsigned int ulDrive,
- tUSBHMSCCallback pfnCallback)
- {
- //
- // Only the first drive is supported and only one callback is supported.
- //
- if( (g_USBHMSCDevice[ulDrive].pfnCallback))
- {
- return(0);
- }
- //
- // Save the callback.
- //
- g_USBHMSCDevice[ulDrive].pfnCallback = pfnCallback;
-
- g_USBHMSCDevice[ulDrive].ulIndex = ulIndex;
- //
- // Return the requested device instance.
- //
- return((unsigned int)&g_USBHMSCDevice[ulDrive]);
- }
- //*****************************************************************************
- //
- //! This function should be called to release a drive instance.
- //!
- //! \param ulInstance is the device instance that is to be released.
- //!
- //! This function is called when an MSC drive is to be released in preparation
- //! for shutdown or a switch to USB device mode, for example. Following this
- //! call, the drive is available for other clients who may open it again using
- //! a call to USBHMSCDriveOpen().
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBHMSCDriveClose(unsigned int ulInstance)
- {
- tUSBHMSCInstance *pMSCDevice;
- //
- // Get a pointer to the device instance data from the handle.
- //
- pMSCDevice = (tUSBHMSCInstance *)ulInstance;
- //
- // Close the drive (if it is already open)
- //
- USBHMSCClose((void *)pMSCDevice);
- //
- // Clear the callback indicating that the device is now closed.
- //
- pMSCDevice->pfnCallback = 0;
- }
- //*****************************************************************************
- //
- //! This function performs a block read to an MSC device.
- //!
- //! \param ulInstance is the device instance to use for this read.
- //! \param ulLBA is the logical block address to read on the device.
- //! \param pucData is a pointer to the returned data buffer.
- //! \param ulNumBlocks is the number of blocks to read from the device.
- //!
- //! This function will perform a block sized read from the device associated
- //! with the \e ulInstance parameter. The \e ulLBA parameter specifies the
- //! logical block address to read on the device. This function will only
- //! perform \e ulNumBlocks block sized reads. In most cases this is a read
- //! of 512 bytes of data. The \e *pucData buffer should be at least
- //! \e ulNumBlocks * 512 bytes in size.
- //!
- //! \return The function returns zero for success and any negative value
- //! indicates a failure.
- //
- //*****************************************************************************
- int
- USBHMSCBlockRead(unsigned int ulInstance, unsigned int ulLBA,
- unsigned char *pucData, unsigned int ulNumBlocks)
- {
- tUSBHMSCInstance *pMSCDevice;
- unsigned int ulSize;
- //
- // Get the instance pointer in a more usable form.
- //
- pMSCDevice = (tUSBHMSCInstance *)ulInstance;
- //
- // If there is no device present then return an error.
- //
- if(pMSCDevice->pDevice == 0)
- {
- return(-1);
- }
- //
- // Calculate the actual byte size of the read.
- //
- ulSize = pMSCDevice->ulBlockSize * ulNumBlocks;
- //
- // Perform the SCSI read command.
- //
- if(USBHSCSIRead10(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe, ulLBA, pucData, &ulSize,
- ulNumBlocks) != SCSI_CMD_STATUS_PASS)
- {
- return(-1);
- }
- //
- // Success.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! This function performs a block write to an MSC device.
- //!
- //! \param ulInstance is the device instance to use for this write.
- //! \param ulLBA is the logical block address to write on the device.
- //! \param pucData is a pointer to the data to write out.
- //! \param ulNumBlocks is the number of blocks to write to the device.
- //!
- //! This function will perform a block sized write to the device associated
- //! with the \e ulInstance parameter. The \e ulLBA parameter specifies the
- //! logical block address to write on the device. This function will only
- //! perform \e ulNumBlocks block sized writes. In most cases this is a write
- //! of 512 bytes of data. The \e *pucData buffer should contain at least
- //! \e ulNumBlocks * 512 bytes in size to prevent unwanted data being written
- //! to the device.
- //!
- //! \return The function returns zero for success and any negative value
- //! indicates a failure.
- //
- //*****************************************************************************
- int
- USBHMSCBlockWrite(unsigned int ulInstance, unsigned int ulLBA,
- unsigned char *pucData, unsigned int ulNumBlocks)
- {
- tUSBHMSCInstance *pMSCDevice;
- unsigned int ulSize;
- //
- // Get the instance pointer in a more usable form.
- //
- pMSCDevice = (tUSBHMSCInstance *)ulInstance;
- //
- // If there is no device present then return an error.
- //
- if(pMSCDevice->pDevice == 0)
- {
- return(-1);
- }
- //
- // Calculate the actual byte size of the write.
- //
- ulSize = pMSCDevice->ulBlockSize * ulNumBlocks;
- //
- // Perform the SCSI write command.
- //
- if(USBHSCSIWrite10(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
- pMSCDevice->ulBulkOutPipe, ulLBA, pucData, &ulSize,
- ulNumBlocks) != SCSI_CMD_STATUS_PASS)
- {
- return(-1);
- }
- //
- // Success.
- //
- return(0);
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|