usbhmsc.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. //*****************************************************************************
  2. //
  3. // usbhmsc.c - USB MSC host driver.
  4. //
  5. // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
  6. // Software License Agreement
  7. //
  8. // Texas Instruments (TI) is supplying this software for use solely and
  9. // exclusively on TI's microcontroller products. The software is owned by
  10. // TI and/or its suppliers, and is protected under applicable copyright
  11. // laws. You may not combine this software with "viral" open-source
  12. // software in order to form a larger program.
  13. //
  14. // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  15. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  16. // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  17. // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  18. // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  19. // DAMAGES, FOR ANY REASON WHATSOEVER.
  20. //
  21. // This is part of AM1808 StarterWare USB Library, resused from revision 6288 of the
  22. // stellaris USB Library
  23. //
  24. //*****************************************************************************
  25. #include "hw_types.h"
  26. #include "usb.h"
  27. #include "usblib.h"
  28. #include "usbmsc.h"
  29. #include "usbhost.h"
  30. #include "usbhmsc.h"
  31. #include "usbhscsi.h"
  32. //*****************************************************************************
  33. //
  34. //! \addtogroup usblib_host_class
  35. //! @{
  36. //
  37. //*****************************************************************************
  38. //*****************************************************************************
  39. //
  40. // Forward declarations for the driver open and close calls.
  41. //
  42. //*****************************************************************************
  43. static void *USBHMSCOpen(tUSBHostDevice *pDevice, unsigned int ulDeviceNum);
  44. static void USBHMSCClose(void *pvInstance);
  45. extern tUSBHCD g_sUSBHCD[];
  46. //*****************************************************************************
  47. //
  48. // The array of USB MSC host drivers.
  49. //
  50. //*****************************************************************************
  51. tUSBHMSCInstance g_USBHMSCDevice[USB_NUM_INSTANCE];
  52. //*****************************************************************************
  53. //
  54. //! This constant global structure defines the Mass Storage Class Driver that
  55. //! is provided with the USB library.
  56. //
  57. //*****************************************************************************
  58. const tUSBHostClassDriver g_USBHostMSCClassDriver =
  59. {
  60. USB_CLASS_MASS_STORAGE,
  61. USBHMSCOpen,
  62. USBHMSCClose,
  63. 0
  64. };
  65. //*****************************************************************************
  66. //
  67. //! This function is used to open an instance of the MSC driver.
  68. //!
  69. //! \param pDevice is a pointer to the device information structure.
  70. //!
  71. //! This function will attempt to open an instance of the MSC driver based on
  72. //! the information contained in the pDevice structure. This call can fail if
  73. //! there are not sufficient resources to open the device. The function will
  74. //! return a value that should be passed back into USBMSCClose() when the
  75. //! driver is no longer needed.
  76. //!
  77. //! \return The function will return a pointer to a MSC driver instance.
  78. //
  79. //*****************************************************************************
  80. static void *
  81. USBHMSCOpen(tUSBHostDevice *pDevice, unsigned int ulInstance)
  82. {
  83. int iIdx;
  84. tEndpointDescriptor *pEndpointDescriptor;
  85. tInterfaceDescriptor *pInterface;
  86. tUSBHMSCInstance *sUSBHMSCDevice;
  87. sUSBHMSCDevice = (tUSBHMSCInstance *)ulInstance;
  88. unsigned int ulIndex = sUSBHMSCDevice->ulIndex;
  89. //
  90. // Don't allow the device to be opened without closing first.
  91. //
  92. if(sUSBHMSCDevice->pDevice)
  93. {
  94. return(0);
  95. }
  96. //
  97. // Save the device pointer.
  98. //
  99. sUSBHMSCDevice->pDevice = pDevice;
  100. //
  101. // Get the interface descriptor.
  102. //
  103. pInterface = USBDescGetInterface(pDevice->pConfigDescriptor, 0, 0);
  104. //
  105. // Loop through the endpoints of the device.
  106. //
  107. for(iIdx = 0; iIdx < 3; iIdx++)
  108. {
  109. //
  110. // Get the first endpoint descriptor.
  111. //
  112. pEndpointDescriptor =
  113. USBDescGetInterfaceEndpoint(pInterface, iIdx,
  114. pDevice->ulConfigDescriptorSize);
  115. //
  116. // If no more endpoints then break out.
  117. //
  118. if(pEndpointDescriptor == 0)
  119. {
  120. break;
  121. }
  122. //
  123. // See if this is a bulk endpoint.
  124. //
  125. if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
  126. USB_EP_ATTR_BULK)
  127. {
  128. //
  129. // See if this is bulk IN or bulk OUT.
  130. //
  131. if(pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
  132. {
  133. //
  134. // Allocate the USB Pipe for this Bulk IN endpoint.
  135. //
  136. sUSBHMSCDevice->ulBulkInPipe =
  137. USBHCDPipeAllocSize(ulIndex, USBHCD_PIPE_BULK_IN_DMA,
  138. pDevice->ulAddress,
  139. pEndpointDescriptor->wMaxPacketSize,
  140. 0);
  141. //
  142. // Configure the USB pipe as a Bulk IN endpoint.
  143. //
  144. USBHCDPipeConfig(ulIndex, sUSBHMSCDevice->ulBulkInPipe,
  145. pEndpointDescriptor->wMaxPacketSize,
  146. 0,
  147. (pEndpointDescriptor->bEndpointAddress &
  148. USB_EP_DESC_NUM_M));
  149. }
  150. else
  151. {
  152. //
  153. // Allocate the USB Pipe for this Bulk OUT endpoint.
  154. //
  155. sUSBHMSCDevice->ulBulkOutPipe =
  156. USBHCDPipeAllocSize(ulIndex, USBHCD_PIPE_BULK_OUT_DMA,
  157. pDevice->ulAddress,
  158. pEndpointDescriptor->wMaxPacketSize,
  159. 0);
  160. //
  161. // Configure the USB pipe as a Bulk OUT endpoint.
  162. //
  163. USBHCDPipeConfig(ulIndex, sUSBHMSCDevice->ulBulkOutPipe,
  164. pEndpointDescriptor->wMaxPacketSize,
  165. 0,
  166. (pEndpointDescriptor->bEndpointAddress &
  167. USB_EP_DESC_NUM_M));
  168. }
  169. }
  170. }
  171. //
  172. // If the callback exists, call it with an Open event.
  173. //
  174. if(sUSBHMSCDevice->pfnCallback != 0)
  175. {
  176. sUSBHMSCDevice->pfnCallback((unsigned int)sUSBHMSCDevice,
  177. MSC_EVENT_OPEN, 0);
  178. }
  179. //
  180. // Return the only instance of this device.
  181. //
  182. return(sUSBHMSCDevice);
  183. }
  184. //*****************************************************************************
  185. //
  186. //! This function is used to release an instance of the MSC driver.
  187. //!
  188. //! \param pvInstance is an instance pointer that needs to be released.
  189. //!
  190. //! This function will free up any resources in use by the MSC driver instance
  191. //! that is passed in. The \e pvInstance pointer should be a valid value that
  192. //! was returned from a call to USBMSCOpen().
  193. //!
  194. //! \return None.
  195. //
  196. //*****************************************************************************
  197. static void
  198. USBHMSCClose(void *pvInstance)
  199. {
  200. tUSBHMSCInstance *sUSBHMSCDevice;
  201. sUSBHMSCDevice = (tUSBHMSCInstance *)pvInstance;
  202. //
  203. // Do nothing if there is not a driver open.
  204. //
  205. if(sUSBHMSCDevice->pDevice == 0)
  206. {
  207. return;
  208. }
  209. //
  210. // Reset the device pointer.
  211. //
  212. sUSBHMSCDevice->pDevice = 0;
  213. //
  214. // Free the Bulk IN pipe.
  215. //
  216. if(sUSBHMSCDevice->ulBulkInPipe != 0)
  217. {
  218. USBHCDPipeFree(sUSBHMSCDevice->ulIndex, sUSBHMSCDevice->ulBulkInPipe);
  219. }
  220. //
  221. // Free the Bulk OUT pipe.
  222. //
  223. if(sUSBHMSCDevice->ulBulkOutPipe != 0)
  224. {
  225. USBHCDPipeFree(sUSBHMSCDevice->ulIndex, sUSBHMSCDevice->ulBulkOutPipe);
  226. }
  227. //
  228. // If the callback exists then call it.
  229. //
  230. if(sUSBHMSCDevice->pfnCallback != 0)
  231. {
  232. sUSBHMSCDevice->pfnCallback((unsigned int)sUSBHMSCDevice,
  233. MSC_EVENT_CLOSE, 0);
  234. }
  235. }
  236. //*****************************************************************************
  237. //
  238. //! This function retrieves the maximum number of the logical units on a
  239. //! mass storage device.
  240. //!
  241. //! \param ulAddress is the device address on the USB bus.
  242. //! \param ulInterface is the interface number on the device specified by the
  243. //! \e ulAddress parameter.
  244. //! \param pucMaxLUN is the byte value returned from the device for the
  245. //! device's maximum logical unit.
  246. //!
  247. //! The device will return one byte of data that contains the maximum LUN
  248. //! supported by the device. For example, if the device supports four LUNs
  249. //! then the LUNs would be numbered from 0 to 3 and the return value would be
  250. //! 3. If no LUN is associated with the device, the value returned shall be 0.
  251. //!
  252. //! \return None.
  253. //
  254. //*****************************************************************************
  255. static void
  256. USBHMSCGetMaxLUN(unsigned int ulIndex, unsigned int ulAddress,
  257. unsigned int ulInterface, unsigned char *pucMaxLUN)
  258. {
  259. tUSBRequest SetupPacket;
  260. //
  261. // This is a Class specific interface IN request.
  262. //
  263. SetupPacket.bmRequestType =
  264. USB_RTYPE_DIR_IN | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE;
  265. //
  266. // Request a the Max LUN for this interface.
  267. //
  268. SetupPacket.bRequest = USBREQ_GET_MAX_LUN;
  269. SetupPacket.wValue = 0;
  270. //
  271. // Indicate the interface to use.
  272. //
  273. SetupPacket.wIndex = (unsigned short)ulInterface;
  274. //
  275. // Only request a single byte of data.
  276. //
  277. SetupPacket.wLength = 1;
  278. //
  279. // Put the setup packet in the buffer and send the command.
  280. //
  281. if(USBHCDControlTransfer(ulIndex, &SetupPacket, ulAddress, pucMaxLUN, 1,
  282. MAX_PACKET_SIZE_EP0) != 1)
  283. {
  284. *pucMaxLUN = 0;
  285. }
  286. }
  287. //*****************************************************************************
  288. //
  289. //! This function checks if a drive is ready to be accessed.
  290. //!
  291. //! \param ulInstance is the device instance to use for this read.
  292. //!
  293. //! This function checks if the current device is ready to be accessed.
  294. //! It uses the \e ulInstance parameter to determine which device to check and
  295. //! will return zero when the device is ready. Any non-zero return code
  296. //! indicates that the device was not ready.
  297. //!
  298. //! \return This function will return zero if the device is ready and it will
  299. //! return a other value if the device is not ready or if an error occurred.
  300. //
  301. //*****************************************************************************
  302. int
  303. USBHMSCDriveReady(unsigned int ulInstance)
  304. {
  305. unsigned char ucMaxLUN, pBuffer[SCSI_INQUIRY_DATA_SZ];
  306. unsigned int ulSize;
  307. tUSBHMSCInstance *pMSCDevice;
  308. //
  309. // Get the instance pointer in a more usable form.
  310. //
  311. pMSCDevice = (tUSBHMSCInstance *)ulInstance;
  312. //
  313. // If there is no device present then return an error.
  314. //
  315. if(pMSCDevice->pDevice == 0)
  316. {
  317. return(-1);
  318. }
  319. //
  320. // Get the Maximum LUNs on this device.
  321. //
  322. USBHMSCGetMaxLUN(pMSCDevice->ulIndex, pMSCDevice->pDevice->ulAddress,
  323. pMSCDevice->pDevice->ulInterface, &ucMaxLUN);
  324. //
  325. // Save the Maximum number of LUNs on this device.
  326. //
  327. pMSCDevice->ulMaxLUN = ucMaxLUN;
  328. //
  329. // Issue a SCSI Inquiry to get basic information on the device
  330. //
  331. ulSize = SCSI_INQUIRY_DATA_SZ;
  332. if((USBHSCSIInquiry(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  333. pMSCDevice->ulBulkOutPipe,
  334. pBuffer, &ulSize) != SCSI_CMD_STATUS_PASS))
  335. {
  336. return(-1);
  337. }
  338. //
  339. // See if the drive is ready to use.
  340. //
  341. if(USBHSCSITestUnitReady(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  342. pMSCDevice->ulBulkOutPipe) != SCSI_CMD_STATUS_PASS)
  343. {
  344. //
  345. // Get the current sense data from the device to see why it failed
  346. // the Test Unit Ready command.
  347. //
  348. ulSize = SCSI_REQUEST_SENSE_SZ;
  349. USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  350. pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize);
  351. }
  352. //
  353. // Send Request Sense agian, return if device returnss command fail
  354. //
  355. ulSize = SCSI_REQUEST_SENSE_SZ;
  356. if(USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  357. pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize)
  358. != SCSI_CMD_STATUS_PASS)
  359. {
  360. return(-1);
  361. }
  362. if((pBuffer[SCSI_RS_SKEY] == SCSI_RS_KEY_UNIT_ATTN) &&
  363. (pBuffer[SCSI_RS_SKEY_AD_SKEY] == SCSI_RS_KEY_NOTPRSNT))
  364. {
  365. return(-1);
  366. }
  367. //
  368. // Get the size of the drive.
  369. //
  370. ulSize = SCSI_INQUIRY_DATA_SZ;
  371. if(USBHSCSIReadCapacity(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  372. pMSCDevice->ulBulkOutPipe,
  373. pBuffer, &ulSize) != SCSI_CMD_STATUS_PASS)
  374. {
  375. //
  376. // Get the current sense data from the device to see why it failed
  377. // the Read Capacity command.
  378. //
  379. ulSize = SCSI_REQUEST_SENSE_SZ;
  380. USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  381. pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize);
  382. return(-1);
  383. }
  384. else
  385. {
  386. //
  387. // Read the block size out, value is stored big endian.
  388. //
  389. pMSCDevice->ulBlockSize =
  390. (pBuffer[7] | (pBuffer[6] << 8) | pBuffer[5] << 16 |
  391. (pBuffer[4] << 24));
  392. //
  393. // Read the block size out.
  394. //
  395. pMSCDevice->ulNumBlocks =
  396. (pBuffer[3] | (pBuffer[2] << 8) | pBuffer[1] << 16 |
  397. (pBuffer[0] << 24));
  398. }
  399. //
  400. // Check whether unit is ready again
  401. //
  402. if(USBHSCSITestUnitReady(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  403. pMSCDevice->ulBulkOutPipe) != SCSI_CMD_STATUS_PASS)
  404. {
  405. //
  406. // Get the current sense data from the device to see why it failed
  407. // the Test Unit Ready command.
  408. //
  409. ulSize = SCSI_REQUEST_SENSE_SZ;
  410. USBHSCSIRequestSense(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  411. pMSCDevice->ulBulkOutPipe, pBuffer, &ulSize);
  412. return(-1);
  413. }
  414. else
  415. {
  416. //
  417. // Success.
  418. //
  419. return(0);
  420. }
  421. }
  422. //*****************************************************************************
  423. //
  424. //! This function should be called before any devices are present to enable
  425. //! the mass storage device class driver.
  426. //!
  427. //! \param ulDrive is the drive number to open.
  428. //! \param pfnCallback is the driver callback for any mass storage events.
  429. //!
  430. //! This function is called to open an instance of a mass storage device. It
  431. //! should be called before any devices are connected to allow for proper
  432. //! notification of drive connection and disconnection. The \e ulDrive
  433. //! parameter is a zero based index of the drives present in the system.
  434. //! There are a constant number of drives, and this number should only
  435. //! be greater than 0 if there is a USB hub present in the system. The
  436. //! application should also provide the \e pfnCallback to be notified of mass
  437. //! storage related events like device enumeration and device removal.
  438. //!
  439. //! \return This function will return the driver instance to use for the other
  440. //! mass storage functions. If there is no driver available at the time of
  441. //! this call, this function will return zero.
  442. //
  443. //*****************************************************************************
  444. unsigned int
  445. USBHMSCDriveOpen(unsigned int ulIndex, unsigned int ulDrive,
  446. tUSBHMSCCallback pfnCallback)
  447. {
  448. //
  449. // Only the first drive is supported and only one callback is supported.
  450. //
  451. if( (g_USBHMSCDevice[ulDrive].pfnCallback))
  452. {
  453. return(0);
  454. }
  455. //
  456. // Save the callback.
  457. //
  458. g_USBHMSCDevice[ulDrive].pfnCallback = pfnCallback;
  459. g_USBHMSCDevice[ulDrive].ulIndex = ulIndex;
  460. //
  461. // Return the requested device instance.
  462. //
  463. return((unsigned int)&g_USBHMSCDevice[ulDrive]);
  464. }
  465. //*****************************************************************************
  466. //
  467. //! This function should be called to release a drive instance.
  468. //!
  469. //! \param ulInstance is the device instance that is to be released.
  470. //!
  471. //! This function is called when an MSC drive is to be released in preparation
  472. //! for shutdown or a switch to USB device mode, for example. Following this
  473. //! call, the drive is available for other clients who may open it again using
  474. //! a call to USBHMSCDriveOpen().
  475. //!
  476. //! \return None.
  477. //
  478. //*****************************************************************************
  479. void
  480. USBHMSCDriveClose(unsigned int ulInstance)
  481. {
  482. tUSBHMSCInstance *pMSCDevice;
  483. //
  484. // Get a pointer to the device instance data from the handle.
  485. //
  486. pMSCDevice = (tUSBHMSCInstance *)ulInstance;
  487. //
  488. // Close the drive (if it is already open)
  489. //
  490. USBHMSCClose((void *)pMSCDevice);
  491. //
  492. // Clear the callback indicating that the device is now closed.
  493. //
  494. pMSCDevice->pfnCallback = 0;
  495. }
  496. //*****************************************************************************
  497. //
  498. //! This function performs a block read to an MSC device.
  499. //!
  500. //! \param ulInstance is the device instance to use for this read.
  501. //! \param ulLBA is the logical block address to read on the device.
  502. //! \param pucData is a pointer to the returned data buffer.
  503. //! \param ulNumBlocks is the number of blocks to read from the device.
  504. //!
  505. //! This function will perform a block sized read from the device associated
  506. //! with the \e ulInstance parameter. The \e ulLBA parameter specifies the
  507. //! logical block address to read on the device. This function will only
  508. //! perform \e ulNumBlocks block sized reads. In most cases this is a read
  509. //! of 512 bytes of data. The \e *pucData buffer should be at least
  510. //! \e ulNumBlocks * 512 bytes in size.
  511. //!
  512. //! \return The function returns zero for success and any negative value
  513. //! indicates a failure.
  514. //
  515. //*****************************************************************************
  516. int
  517. USBHMSCBlockRead(unsigned int ulInstance, unsigned int ulLBA,
  518. unsigned char *pucData, unsigned int ulNumBlocks)
  519. {
  520. tUSBHMSCInstance *pMSCDevice;
  521. unsigned int ulSize;
  522. //
  523. // Get the instance pointer in a more usable form.
  524. //
  525. pMSCDevice = (tUSBHMSCInstance *)ulInstance;
  526. //
  527. // If there is no device present then return an error.
  528. //
  529. if(pMSCDevice->pDevice == 0)
  530. {
  531. return(-1);
  532. }
  533. //
  534. // Calculate the actual byte size of the read.
  535. //
  536. ulSize = pMSCDevice->ulBlockSize * ulNumBlocks;
  537. //
  538. // Perform the SCSI read command.
  539. //
  540. if(USBHSCSIRead10(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  541. pMSCDevice->ulBulkOutPipe, ulLBA, pucData, &ulSize,
  542. ulNumBlocks) != SCSI_CMD_STATUS_PASS)
  543. {
  544. return(-1);
  545. }
  546. //
  547. // Success.
  548. //
  549. return(0);
  550. }
  551. //*****************************************************************************
  552. //
  553. //! This function performs a block write to an MSC device.
  554. //!
  555. //! \param ulInstance is the device instance to use for this write.
  556. //! \param ulLBA is the logical block address to write on the device.
  557. //! \param pucData is a pointer to the data to write out.
  558. //! \param ulNumBlocks is the number of blocks to write to the device.
  559. //!
  560. //! This function will perform a block sized write to the device associated
  561. //! with the \e ulInstance parameter. The \e ulLBA parameter specifies the
  562. //! logical block address to write on the device. This function will only
  563. //! perform \e ulNumBlocks block sized writes. In most cases this is a write
  564. //! of 512 bytes of data. The \e *pucData buffer should contain at least
  565. //! \e ulNumBlocks * 512 bytes in size to prevent unwanted data being written
  566. //! to the device.
  567. //!
  568. //! \return The function returns zero for success and any negative value
  569. //! indicates a failure.
  570. //
  571. //*****************************************************************************
  572. int
  573. USBHMSCBlockWrite(unsigned int ulInstance, unsigned int ulLBA,
  574. unsigned char *pucData, unsigned int ulNumBlocks)
  575. {
  576. tUSBHMSCInstance *pMSCDevice;
  577. unsigned int ulSize;
  578. //
  579. // Get the instance pointer in a more usable form.
  580. //
  581. pMSCDevice = (tUSBHMSCInstance *)ulInstance;
  582. //
  583. // If there is no device present then return an error.
  584. //
  585. if(pMSCDevice->pDevice == 0)
  586. {
  587. return(-1);
  588. }
  589. //
  590. // Calculate the actual byte size of the write.
  591. //
  592. ulSize = pMSCDevice->ulBlockSize * ulNumBlocks;
  593. //
  594. // Perform the SCSI write command.
  595. //
  596. if(USBHSCSIWrite10(pMSCDevice->ulIndex, pMSCDevice->ulBulkInPipe,
  597. pMSCDevice->ulBulkOutPipe, ulLBA, pucData, &ulSize,
  598. ulNumBlocks) != SCSI_CMD_STATUS_PASS)
  599. {
  600. return(-1);
  601. }
  602. //
  603. // Success.
  604. //
  605. return(0);
  606. }
  607. //*****************************************************************************
  608. //
  609. // Close the Doxygen group.
  610. //! @}
  611. //
  612. //*****************************************************************************