SAMV71 Xplained Ultra Software Package 1.5

uhi_msc.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 /**
00030  * \file
00031  *
00032  * \brief USB host Mass Storage Class interface.
00033  *
00034  */
00035 /*
00036  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
00037  */
00038 
00039 #include "conf_usb_host.h"
00040 #include "USBHDriver.h"
00041 #include "USBH.h"
00042 #include "uhi_msc.h"
00043 #include <string.h>
00044 
00045 #ifdef USB_HOST_HUB_SUPPORT
00046     // TODO
00047     #  error USB HUB support is not implemented on UHI MSC
00048 #endif
00049 
00050 #ifndef UHI_MSC_NOTIFY_NEW_LUN_EXT
00051     #define UHI_MSC_NOTIFY_NEW_LUN_EXT
00052 #endif
00053 
00054 /**
00055  * \ingroup uhi_msc_group
00056  * \defgroup uhi_msc_group_internal Implementation of UHI Mass Storage Class
00057  *
00058  * Class internal implementation
00059  * @{
00060  */
00061 
00062 //! Timeout on SCSI commands
00063 #define  UHI_MSC_SCSI_TIMEOUT 20000
00064 
00065 /**
00066  * \name Internal defines and variables to manage MSC unit
00067  */
00068 //@{
00069 
00070 //! Flag to secure the UHI MSC resources
00071 static volatile bool b_uhi_msc_free = true;
00072 
00073 //! USB MSC device information
00074 typedef struct {
00075     USBH_device_t *dev;
00076     USBHS_Ep_t ep_in;
00077     USBHS_Ep_t ep_out;
00078     uint8_t iface_num;
00079     uint8_t nb_lun;
00080     uhi_msc_lun_t *lun;
00081 } uhi_msc_dev_t;
00082 
00083 //! Information about the enumerated USB MSC device
00084 static uhi_msc_dev_t uhi_msc_dev = {
00085     .dev = NULL,
00086     .lun = NULL,
00087     .nb_lun = 0,
00088 };
00089 
00090 //! Current USB MSC device selected by the UHI MSC
00091 //@{
00092 #ifdef USB_HOST_HUB_SUPPORT
00093     static uhi_msc_dev_t *uhi_msc_dev_sel;
00094 #else
00095     #define uhi_msc_dev_sel (&uhi_msc_dev)
00096 #endif
00097 //@}
00098 
00099 //! Current LUN selected in USB MSC device by the UHI MSC
00100 //@{
00101 static uhi_msc_lun_t *uhi_msc_lun_sel;
00102 #define uhi_msc_lun_num_sel uhi_msc_cbw.bCBWLUN
00103 //@}
00104 
00105 //! Temporary structures used to read LUN information via a SCSI command
00106 //@{
00107 static SBCReadCapacity10Data uhi_msc_capacity;
00108 static SBCInquiryData uhi_msc_inquiry;
00109 static SBCRequestSenseData uhi_msc_sense;
00110 static struct {
00111     SBCModeParameterHeader6 header;
00112     SBCInformationalExceptionsControl sense_data;
00113 } uhi_msc_sense6;
00114 //@}
00115 
00116 //! Callback type used by SCSI sense command
00117 typedef void (*uhi_msc_scsi_sense_callback_t) (void);
00118 
00119 //! Internal callbacks
00120 //@{
00121 static uhi_msc_scsi_callback_t uhi_msc_scsi_sub_callback;
00122 static uhi_msc_scsi_callback_t uhi_msc_scsi_callback;
00123 static uhi_msc_scsi_sense_callback_t uhi_msc_scsi_sense_callback;
00124 //@}
00125 //@}
00126 
00127 /**
00128  * \name Variables to manage SCSI requests
00129  */
00130 //@{
00131 //! Structure to send a CBW packet
00132 static MSCbw uhi_msc_cbw =
00133 {.dCBWSignature = MSD_CBW_SIGNATURE };
00134 
00135 //! Structure to receive a CSW packet
00136 static MSCsw uhi_msc_csw;
00137 
00138 //! Structure to sent or received DATA packet
00139 static uint8_t *uhi_msc_data;
00140 //@}
00141 
00142 /**
00143  * \name Internal routines
00144  */
00145 //@{
00146 
00147 /**
00148  * \name Routines to initialize the MSC devices
00149  */
00150 //@{
00151 static void uhi_msc_enable_step1(void);
00152 static void uhi_msc_enable_step2(
00153     USBHS_Add_t add,
00154     USBH_XfrStatus_t status,
00155     uint16_t payload_trans);
00156 static void uhi_msc_enable_step3(void);
00157 static void uhi_msc_enable_step4(bool b_success);
00158 static void uhi_msc_enable_step5(bool b_success);
00159 //@}
00160 
00161 /**
00162  * \name SCSI commands
00163  */
00164 //@{
00165 static bool uhi_msc_select_lun(uint8_t lun);
00166 static void uhi_msc_scsi_inquiry(uhi_msc_scsi_callback_t callback);
00167 static void uhi_msc_scsi_inquiry_done(bool b_cbw_succes);
00168 static void uhi_msc_scsi_test_unit_ready_done(bool b_cbw_succes);
00169 static void uhi_msc_scsi_test_unit_ready_sense(void);
00170 static void uhi_msc_scsi_read_capacity(uhi_msc_scsi_callback_t callback);
00171 static void uhi_msc_scsi_read_capacity_done(bool b_cbw_succes);
00172 static void uhi_msc_scsi_read_capacity_sense(void);
00173 static void uhi_msc_scsi_mode_sense6(uhi_msc_scsi_callback_t callback);
00174 static void uhi_msc_scsi_mode_sense6_done(bool b_cbw_succes);
00175 static void uhi_msc_scsi_read_10_done(bool b_cbw_succes);
00176 static void uhi_msc_scsi_write_10_done(bool b_cbw_succes);
00177 static void uhi_msc_scsi_request_sense(uhi_msc_scsi_sense_callback_t callback);
00178 static void uhi_msc_scsi_request_sense_done(bool b_cbw_succes);
00179 //@}
00180 
00181 /**
00182  * \name SCSI protocol sub routines
00183  */
00184 //@{
00185 static void uhi_msc_scsi(uhi_msc_scsi_callback_t callback, uint8_t *payload);
00186 static void uhi_msc_cbw_sent(
00187     USBHS_Add_t add,
00188     USBHS_Ep_t ep,
00189     USBH_XfrStatus_t status,
00190     uint32_t nb_transfered);
00191 static void uhi_msc_data_transfered(
00192     USBHS_Add_t add,
00193     USBHS_Ep_t ep,
00194     USBH_XfrStatus_t status,
00195     uint32_t nb_transfered);
00196 static void uhi_msc_csw_wait(void);
00197 static void uhi_msc_csw_received(
00198     USBHS_Add_t add,
00199     USBHS_Ep_t ep,
00200     USBH_XfrStatus_t status,
00201     uint32_t nb_transfered);
00202 static void uhi_msc_cbw_rst_stall(
00203     USBHS_Add_t add,
00204     USBH_XfrStatus_t status,
00205     uint16_t payload_trans);
00206 static void uhi_msc_data_csw_rst_stall(
00207     USBHS_Add_t add,
00208     USBH_XfrStatus_t status,
00209     uint16_t payload_trans);
00210 static void uhi_msc_transfer(USBHS_Ep_t endp,
00211                              uint8_t *payload,
00212                              uint16_t payload_size,
00213                              uhd_callback_trans_t callback_end);
00214 static void uhi_msc_reset_endpoint(
00215     USBHS_Ep_t endp, uhd_callback_setup_end_t callback);
00216 //@}
00217 
00218 //@}
00219 
00220 
00221 /**
00222  * \name Interface used by UHC module
00223  */
00224 //@{
00225 
00226 USBH_enum_status_t uhi_msc_install(USBH_device_t *dev)
00227 {
00228     bool b_iface_supported;
00229     uint16_t conf_desc_lgt;
00230     USBInterfaceDescriptor *ptr_iface;
00231 
00232     if (uhi_msc_dev.dev != NULL) {
00233         return UHC_ENUM_SOFTWARE_LIMIT; // Device already allocated
00234     }
00235 
00236     conf_desc_lgt = dev->conf_desc->wTotalLength;
00237     ptr_iface = (USBInterfaceDescriptor *) dev->conf_desc;
00238     b_iface_supported = false;
00239 
00240     while (conf_desc_lgt) {
00241         switch (ptr_iface->bDescriptorType) {
00242 
00243         case USBGenericDescriptor_INTERFACE:
00244             if ((ptr_iface->bInterfaceClass   == MSInterfaceDescriptor_CLASS)
00245                 && (ptr_iface->bInterfaceSubClass == MSD_SUBCLASS_SCSI)
00246                 && (ptr_iface->bInterfaceProtocol == MSD_PROTOCOL_BULK_ONLY)) {
00247                 // USB HID Mouse interface found
00248                 b_iface_supported = true;
00249                 uhi_msc_dev_sel->iface_num = ptr_iface->bInterfaceNumber;
00250                 uhi_msc_dev.ep_in = 0;
00251                 uhi_msc_dev.ep_out = 0;
00252             } else {
00253                 // Stop allocation endpoint(s)
00254                 b_iface_supported = false;
00255             }
00256 
00257             break;
00258 
00259         case USBGenericDescriptor_ENDPOINT:
00260 
00261             //  Allocate the endpoint
00262             if (!b_iface_supported)
00263                 break;
00264 
00265             USBEndpointDescriptor *ptr_ep = (USBEndpointDescriptor *) ptr_iface;
00266 
00267             if (ptr_ep->bmAttributes != USBEndpointDescriptor_BULK) {
00268                 // A bad endpoint interrupt may be present on no compliance U-disk
00269                 break;
00270             }
00271 
00272             if (!USBH_HAL_ConfigurePipe(dev->address, ptr_ep)) {
00273                 return UHC_ENUM_HARDWARE_LIMIT; // Endpoint allocation fail
00274             }
00275 
00276             if (ptr_ep->bEndpointAddress & USB_EP_DIR_IN)
00277                 uhi_msc_dev.ep_in = ptr_ep->bEndpointAddress;
00278             else
00279                 uhi_msc_dev.ep_out = ptr_ep->bEndpointAddress;
00280 
00281             if (uhi_msc_dev.ep_out && uhi_msc_dev.ep_in) {
00282                 // All endpoints allocated
00283                 uhi_msc_dev.dev = dev;
00284                 uhi_msc_dev.nb_lun = 0;
00285                 return UHC_ENUM_SUCCESS;
00286             }
00287 
00288             break;
00289 
00290         }
00291 
00292         assert(conf_desc_lgt >= ptr_iface->bLength);
00293         conf_desc_lgt -= ptr_iface->bLength;
00294         ptr_iface = (USBInterfaceDescriptor *)((uint8_t *)ptr_iface +
00295                                                ptr_iface->bLength);
00296     }
00297 
00298     return UHC_ENUM_UNSUPPORTED; // No interface supported
00299 }
00300 
00301 void uhi_msc_enable(USBH_device_t *dev)
00302 {
00303     if (uhi_msc_dev.dev != dev) {
00304         return; // No interface to enable
00305     }
00306 
00307     // ** Process to enable device **
00308     // Setup request - Get Number of LUN
00309     // For each LUN {
00310     //   MSC request - Inquiry
00311     //   MSC request - Read capacity*
00312     // }
00313     // *It is required by specific U-disk which does not respect USB MSC norm.
00314 
00315 #ifdef USB_HOST_HUB_SUPPORT
00316     uhi_msc_dev_sel = &uhi_msc_dev[];
00317 
00318     if (!b_uhi_msc_free) {
00319         // Install must be postponed
00320     }
00321 
00322 #else
00323     assert(uhi_msc_dev.dev != NULL);
00324 #endif
00325     b_uhi_msc_free = false;
00326     uhi_msc_enable_step1();
00327 }
00328 
00329 void uhi_msc_uninstall(USBH_device_t *dev)
00330 {
00331     if (uhi_msc_dev.dev != dev) {
00332         return; // Device not enabled in this interface
00333     }
00334 
00335     uhi_msc_dev.dev = NULL;
00336 
00337     if (uhi_msc_dev_sel->lun != NULL)
00338         free(uhi_msc_dev_sel->lun);
00339 
00340     UHI_MSC_CHANGE(dev, false);
00341 }
00342 
00343 //@}
00344 
00345 /**
00346  * \name Routines to initialize the MSC devices
00347  */
00348 //@{
00349 
00350 /**
00351  * \brief Step 1 of the initialization of a USB MSC device
00352  * Sends the setup request GET_MAX_LUN.
00353  */
00354 static void uhi_msc_enable_step1(void)
00355 {
00356     // Default value is 0, because the Get LUN number request
00357     // can be stalled if the device have only 1 LUN
00358     uhi_msc_dev_sel->nb_lun = 0;
00359 
00360     // Request Get LUN number
00361     USBGenericRequest req;
00362     req.bmRequestType = USB_REQ_RECIP_INTERFACE | USB_REQ_TYPE_CLASS |
00363                         USB_REQ_DIR_IN;
00364     req.bRequest = MSD_GET_MAX_LUN;
00365     req.wValue = 0;
00366     req.wIndex = uhi_msc_dev_sel->iface_num;
00367     req.wLength = 1;
00368     USBH_HAL_SetupReq(uhi_msc_dev_sel->dev->address,
00369                       &req,
00370                       &(uhi_msc_dev_sel->nb_lun),
00371                       1,
00372                       NULL,
00373                       uhi_msc_enable_step2);
00374 }
00375 
00376 /**
00377  * \brief Step 2 of the initialization of a USB MSC device
00378  * Decode the setup request GET_MAX_LUN and allocs LUN structures.
00379  *
00380  * \param add           USB address of the setup request
00381  * \param status        Transfer status
00382  * \param payload_trans Number of data transfered during DATA phase
00383  */
00384 static void uhi_msc_enable_step2(
00385     USBHS_Add_t add,
00386     USBH_XfrStatus_t status,
00387     uint16_t payload_trans)
00388 {
00389     UNUSED(add);
00390 
00391     // Compute number of LUN
00392     if (status == UHD_TRANS_NOERROR) {
00393         if (payload_trans) {
00394             // The received value is the maximum index
00395             uhi_msc_dev_sel->nb_lun++;
00396         } else
00397             uhi_msc_dev_sel->nb_lun = 1;
00398     } else if (status == UHD_TRANS_STALL)
00399         uhi_msc_dev_sel->nb_lun = 1;
00400     else {
00401         // Error set no LUN
00402         b_uhi_msc_free = true;
00403         return;
00404     }
00405 
00406     // Alloc LUN structures
00407     uhi_msc_dev_sel->lun = malloc(uhi_msc_dev_sel->nb_lun * sizeof(uhi_msc_lun_t));
00408 
00409     if (uhi_msc_dev_sel->lun == NULL) {
00410         assert(false);
00411         b_uhi_msc_free = true;
00412         return;
00413     }
00414 
00415     // Initialize each LUN
00416     uhi_msc_lun_num_sel = ((uint8_t)-1) & 0xF;
00417     uhi_msc_enable_step3();
00418 }
00419 
00420 /**
00421  * \brief Step 3 of the initialization of a USB MSC device
00422  * Selects the next LUN.
00423  * Sends the SCSI INQUIRY request on the LUN.
00424  */
00425 static void uhi_msc_enable_step3(void)
00426 {
00427     if (!uhi_msc_select_lun(++uhi_msc_lun_num_sel)) {
00428         // End of enable MSC interface
00429         b_uhi_msc_free = true;
00430         UHI_MSC_CHANGE(uhi_msc_dev.dev, true);
00431         return;
00432     }
00433 
00434     uhi_msc_lun_sel->status = LUN_NOT_PRESENT;
00435     uhi_msc_scsi_inquiry(uhi_msc_enable_step4);
00436 }
00437 
00438 /**
00439  * \brief Step 4 of the initialization of a USB MSC device
00440  * Sends the SCSI READ CAPACITY request on the current LUN.
00441  *
00442  * \param b_success true, if the scsi command is successful
00443  */
00444 static void uhi_msc_enable_step4(bool b_success)
00445 {
00446     if (!b_success) {
00447         uhi_msc_enable_step3();
00448         return;
00449     }
00450 
00451     uhi_msc_scsi_read_capacity(uhi_msc_enable_step5);
00452 }
00453 
00454 /**
00455  * \brief Step 5 of the initialization of a USB MSC device
00456  * Go to the initialization of the next LUN.
00457  *
00458  * \param b_success true, if the scsi command is successful
00459  */
00460 static void uhi_msc_enable_step5(bool b_success)
00461 {
00462     UNUSED(b_success);
00463     // Initialize next LUN
00464     uhi_msc_enable_step3();
00465 }
00466 
00467 //@}
00468 
00469 /**
00470  * \name External SCSI commands
00471  */
00472 //@{
00473 bool uhi_msc_is_available(void)
00474 {
00475     return b_uhi_msc_free;
00476 }
00477 
00478 uint8_t uhi_msc_get_lun(void)
00479 {
00480     if (uhi_msc_dev.dev == NULL)
00481         return 0;
00482 
00483     return uhi_msc_dev.nb_lun;
00484 }
00485 
00486 uhi_msc_lun_t *uhi_msc_get_lun_desc(uint8_t lun)
00487 {
00488     if (lun >= uhi_msc_dev.nb_lun)
00489         return NULL;
00490 
00491     return &uhi_msc_dev.lun[lun];
00492 }
00493 
00494 bool uhi_msc_scsi_test_unit_ready(uint8_t lun, uhi_msc_scsi_callback_t callback)
00495 {
00496     if (!uhi_msc_select_lun(lun))
00497         return false;
00498 
00499     uhi_msc_scsi_callback = callback;
00500 
00501     // Prepare specific value of CBW packet
00502     uhi_msc_cbw.dCBWDataTransferLength = 0;
00503     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_DEVICE;
00504     uhi_msc_cbw.bCBWCBLength = 6;
00505     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00506     uhi_msc_cbw.pCommand[0] = SBC_TEST_UNIT_READY;
00507 
00508     uhi_msc_scsi(uhi_msc_scsi_test_unit_ready_done, NULL);
00509     return true;
00510 }
00511 
00512 bool uhi_msc_scsi_read_10(uint8_t lun, uint32_t addr, uint8_t *ram,
00513                           uint8_t nb_sector, uhi_msc_scsi_callback_t callback)
00514 {
00515     uint32_t addrTmp = addr;
00516     uint32_t *pBlockLen = (uint32_t *)
00517                           &uhi_msc_lun_sel->capacity.pLogicalBlockLength[0];
00518 
00519     if (!uhi_msc_select_lun(lun))
00520         return false;
00521 
00522     uhi_msc_scsi_callback = callback;
00523 
00524     // Prepare specific value of CBW packet
00525     uhi_msc_cbw.dCBWDataTransferLength =
00526         (*pBlockLen) * nb_sector;
00527     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_HOST;
00528     uhi_msc_cbw.bCBWCBLength = 10;
00529     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00530 
00531     /**pCommand++ = SBC_WRITE10;
00532     memcpy(pCommand, &addr, sizeof(addr));*/
00533     // CBWCB0 - Operation Code
00534     uhi_msc_cbw.pCommand[0] = SBC_READ_10;
00535 
00536     // CBWCB1 - RDPROTECT, DPO, FUA, Obsolete (0x00) (done by previous memset())
00537 
00538     addrTmp = CPU_TO_BE32(addr);
00539     // CBWCB2 to 5 - Logical Block Address (BE16)
00540     memcpy(&uhi_msc_cbw.pCommand[2], &addrTmp, sizeof(addr));
00541 
00542     // CBWCW6 - Reserved (0x00) (done by previous memset())
00543     // CBWCW7 to 8 - Transfer Length
00544     // uhi_msc_cbw.pCommand[7] = 0x00; // MSB (done by previous memset())
00545     uhi_msc_cbw.pCommand[8] = nb_sector; // LSB
00546 
00547     // CBWCW9 - Control (0x00) (done by previous memset())
00548     uhi_msc_scsi(uhi_msc_scsi_read_10_done, ram);
00549     return true;
00550 }
00551 
00552 bool uhi_msc_scsi_write_10(uint8_t lun, uint32_t addr, const uint8_t *ram,
00553                            uint8_t nb_sector, uhi_msc_scsi_callback_t callback)
00554 {
00555     uint32_t addrTmp = addr;
00556     uint32_t *pBlockLen = (uint32_t *)
00557                           &uhi_msc_lun_sel->capacity.pLogicalBlockLength[0];
00558 
00559     if (!uhi_msc_select_lun(lun))
00560         return false;
00561 
00562     uhi_msc_scsi_callback = callback;
00563 
00564     // Prepare specific value of CBW packet
00565     uhi_msc_cbw.dCBWDataTransferLength =
00566         (*pBlockLen) * nb_sector;
00567     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_DEVICE;
00568     uhi_msc_cbw.bCBWCBLength = 10;
00569     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00570 
00571     // CBWCB0 - Operation Code
00572     uhi_msc_cbw.pCommand[0] = SBC_WRITE_10;
00573 
00574     addrTmp = CPU_TO_BE32(addr);
00575     // CBWCB1 - RDPROTECT, DPO, FUA, Obsolete (0x00) (done by previous memset())
00576 
00577     // CBWCB2 to 5 - Logical Block Address (BE16)
00578     memcpy(&uhi_msc_cbw.pCommand[2], &addrTmp, sizeof(addr));
00579 
00580     // CBWCW6 - Reserved (0x00) (done by previous memset())
00581 
00582     // CBWCW7 to 8 - Transfer Length
00583     // uhi_msc_cbw.pCommand[7] = 0x00; // MSB (done by previous memset())
00584     uhi_msc_cbw.pCommand[8] = nb_sector; // LSB
00585 
00586     // CBWCW9 - Control (0x00) (done by previous memset())
00587     uhi_msc_scsi(uhi_msc_scsi_write_10_done, (uint8_t *) ram);
00588     return true;
00589 }
00590 
00591 //@}
00592 
00593 
00594 /**
00595  * \name Internal SCSI commands and sub routines
00596  */
00597 //@{
00598 
00599 /**
00600  * \brief Selects a LUN
00601  *
00602  * \param lun   LUN number to select
00603  *
00604  * \return  true, if the LUN number is correct
00605  */
00606 static bool uhi_msc_select_lun(uint8_t lun)
00607 {
00608     if (lun >= uhi_msc_dev_sel->nb_lun)
00609         return false;
00610 
00611     uhi_msc_lun_num_sel = lun;
00612     uhi_msc_lun_sel = &uhi_msc_dev_sel->lun[lun];
00613     return true;
00614 }
00615 
00616 /**
00617  * \brief Sends the CBW packet of the scsi INQUIRY command
00618  *
00619  * \param callback  Callback to call at the end of scsi command
00620  */
00621 static void uhi_msc_scsi_inquiry(uhi_msc_scsi_callback_t callback)
00622 {
00623     uhi_msc_scsi_callback = callback;
00624 
00625     // Prepare specific value of CBW packet
00626     uhi_msc_cbw.dCBWDataTransferLength = sizeof(SBCInquiryData);
00627     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_HOST;
00628     uhi_msc_cbw.bCBWCBLength = 6;
00629     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00630     uhi_msc_cbw.pCommand[0] = SBC_INQUIRY;
00631     uhi_msc_cbw.pCommand[4] = sizeof(SBCInquiryData);
00632     uhi_msc_scsi(uhi_msc_scsi_inquiry_done, (uint8_t *) & uhi_msc_inquiry);
00633 }
00634 
00635 /**
00636  * \brief Call the callback at the end of scsi INQUIRY command
00637  *
00638  * \param b_cbw_succes true, if the scsi command is successful
00639  */
00640 static void uhi_msc_scsi_inquiry_done(bool b_cbw_succes)
00641 {
00642     if ((!b_cbw_succes) || uhi_msc_csw.dCSWDataResidue) {
00643         uhi_msc_scsi_callback(false);
00644         return;
00645     }
00646 
00647     // Inquiry successful
00648     uhi_msc_scsi_callback(true);
00649 }
00650 
00651 /**
00652  * \brief Decodes the result of scsi TEST UNIT READY command
00653  * Launches READ CAPACITY command, if a new LUN has been detected.
00654  *
00655  * \param b_cbw_succes true, if the scsi command is successful
00656  */
00657 static void uhi_msc_scsi_test_unit_ready_done(bool b_cbw_succes)
00658 {
00659     if (!b_cbw_succes) {
00660         uhi_msc_lun_sel->status = LUN_FAIL;
00661         uhi_msc_scsi_callback(false);
00662         return;
00663     }
00664 
00665     // Test unit ready successful
00666     if (uhi_msc_csw.bCSWStatus != MSD_CSW_COMMAND_PASSED) {
00667         uhi_msc_lun_sel->status = LUN_FAIL; // By default
00668         // LUN is not ready
00669         // Read a sense code
00670         uhi_msc_scsi_request_sense(uhi_msc_scsi_test_unit_ready_sense);
00671         return;
00672     }
00673 
00674     if (uhi_msc_lun_sel->status != LUN_GOOD) {
00675         // It is a new LUN
00676         if (uhi_msc_lun_sel->status == LUN_BUSY) {
00677             // To initialize the new LUN read capacity and write protection flag
00678             uhi_msc_lun_sel->status = LUN_GOOD;
00679             uhi_msc_scsi_read_capacity(uhi_msc_scsi_callback);
00680             return;
00681         }
00682 
00683         // The USB device has not returned a BUSY
00684         // to notify the LUN change to high level,
00685         // then add the notify
00686         uhi_msc_lun_sel->status = LUN_BUSY;
00687     }
00688 
00689     uhi_msc_scsi_callback(true);
00690 }
00691 
00692 /**
00693  * \brief Decodes the scsi sense code after an error on TEST UNIT READY command
00694  */
00695 static void uhi_msc_scsi_test_unit_ready_sense(void)
00696 {
00697     uint16_t sense_key = uhi_msc_sense.bSenseKey;
00698     uint16_t add_sense = (uint16_t)uhi_msc_sense.bAdditionalSenseCode << 8
00699                          | uhi_msc_sense.bAdditionalSenseCodeQualifier;
00700 
00701     // Decode data sense
00702     if ((uhi_msc_sense.bResponseCode
00703          & SBC_SENSE_RESPONSE_CODE_MASK) == SBC_SENSE_DATA_FIXED_CURRENT) {
00704         // Valid data
00705         if ((sense_key == SBC_SENSE_KEY_NOT_READY)
00706             && (add_sense == (SBC_ASC_MEDIUM_NOT_PRESENT << 8)))
00707             uhi_msc_lun_sel->status = LUN_NOT_PRESENT;
00708 
00709         if ((sense_key == SBC_SENSE_KEY_UNIT_ATTENTION)
00710             && (add_sense == (SBC_ASC_NOT_READY_TO_READY_CHANGE << 8)))
00711             uhi_msc_lun_sel->status = LUN_BUSY;
00712     }
00713 
00714     uhi_msc_scsi_callback(true);
00715 }
00716 
00717 /**
00718  * \brief Sends the CBW packet of the scsi READ CAPACITY command
00719  *
00720  * \param callback  Callback to call at the end of scsi command
00721  */
00722 static void uhi_msc_scsi_read_capacity(uhi_msc_scsi_callback_t callback)
00723 {
00724     uhi_msc_scsi_callback = callback;
00725 
00726     // Prepare specific value of CBW packet
00727     uhi_msc_cbw.dCBWDataTransferLength = sizeof(SBCReadCapacity10Data);
00728     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_HOST;
00729     uhi_msc_cbw.bCBWCBLength = 10;
00730     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00731     uhi_msc_cbw.pCommand[0] = SBC_READ_CAPACITY_10;
00732     uhi_msc_scsi(uhi_msc_scsi_read_capacity_done, (uint8_t *)&uhi_msc_capacity);
00733 }
00734 
00735 /**
00736  * \brief Decodes the result of scsi READ CAPACITY command
00737  * Launches MODE SENSE 6 command.
00738  *
00739  * \param b_cbw_succes true, if the scsi command is successful
00740  */
00741 static void uhi_msc_scsi_read_capacity_done(bool b_cbw_succes)
00742 {
00743     uint32_t *pBlockLen, *pBlockAddr;
00744     pBlockLen = (uint32_t *)&uhi_msc_lun_sel->capacity.pLogicalBlockLength[0];
00745     pBlockAddr = (uint32_t *)&uhi_msc_lun_sel->capacity.pLogicalBlockAddress[0];
00746 
00747     if ((!b_cbw_succes) || (uhi_msc_csw.bCSWStatus != MSD_CSW_COMMAND_PASSED)
00748         || uhi_msc_csw.dCSWDataResidue) {
00749         // Read capacity has failed
00750         uhi_msc_lun_sel->status = LUN_FAIL;
00751 
00752         // (WA-Udisk) Read request sense
00753         uhi_msc_scsi_request_sense(uhi_msc_scsi_read_capacity_sense);
00754         return;
00755     }
00756 
00757     // Format capacity data
00758     *pBlockLen = be32_to_cpu(*((uint32_t *)
00759                                 &uhi_msc_capacity.pLogicalBlockLength[0]));
00760     *pBlockAddr = be32_to_cpu(*((uint32_t *)
00761                                  &uhi_msc_capacity.pLogicalBlockAddress[0]));
00762 
00763     // Now, read flag write protection
00764     uhi_msc_scsi_mode_sense6(uhi_msc_scsi_callback);
00765 }
00766 
00767 /**
00768  * \brief Decodes the scsi sense code after a scsi READ CAPACITY command failed
00769  */
00770 static void uhi_msc_scsi_read_capacity_sense(void)
00771 {
00772     uhi_msc_scsi_callback(false);
00773 }
00774 
00775 /**
00776  * \brief Sends the CBW packet of the scsi MODE SENSE 6 command
00777  * This function returns the write-protected mode.
00778  * Field optional provided only by the LUN with a write protection feature.
00779  *
00780  * \param callback  Callback to call at the end of scsi command
00781  */
00782 static void uhi_msc_scsi_mode_sense6(uhi_msc_scsi_callback_t callback)
00783 {
00784     uhi_msc_scsi_callback = callback;
00785 
00786     // Prepare specific value of CBW packet
00787     uhi_msc_cbw.dCBWDataTransferLength = sizeof(uhi_msc_sense6);
00788     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_HOST;
00789     uhi_msc_cbw.bCBWCBLength = 6;
00790     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00791     uhi_msc_cbw.pCommand[0] = SBC_MODE_SENSE_6;
00792     uhi_msc_cbw.pCommand[2] = SBC_PAGE_INFORMATIONAL_EXCEPTIONS_CONTROL;
00793     uhi_msc_cbw.pCommand[4] = sizeof(uhi_msc_sense6);
00794     uhi_msc_scsi(uhi_msc_scsi_mode_sense6_done,
00795                  (uint8_t *) & uhi_msc_sense6);
00796 }
00797 
00798 /**
00799  * \brief Decodes the result of scsi MODE SENSE 6 command
00800  *
00801  * \param b_cbw_succes true, if the scsi command is successful
00802  */
00803 static void uhi_msc_scsi_mode_sense6_done(bool b_cbw_succes)
00804 {
00805     if ((!b_cbw_succes) || (uhi_msc_csw.bCSWStatus != MSD_CSW_COMMAND_PASSED)
00806         || (uhi_msc_csw.dCSWDataResidue < 4)) {
00807         // Sense6 command is not supported,
00808         // The device must be not write protected.
00809         uhi_msc_lun_sel->b_write_protected = false;
00810         uhi_msc_scsi_callback(true);
00811         return;
00812     }
00813 
00814     // Decode field
00815     uhi_msc_lun_sel->b_write_protected =
00816         (uhi_msc_sense6.header.isWP);
00817     uhi_msc_scsi_callback(true);
00818 }
00819 
00820 /**
00821  * \brief Decodes the result of scsi READ 10 command
00822  *
00823  * \param b_cbw_succes true, if the scsi command is successful
00824  */
00825 static void uhi_msc_scsi_read_10_done(bool b_cbw_succes)
00826 {
00827     if ((!b_cbw_succes) || (uhi_msc_csw.bCSWStatus != MSD_CSW_COMMAND_PASSED)
00828         || uhi_msc_csw.dCSWDataResidue) {
00829         // Read10 has failed
00830         uhi_msc_lun_sel->status = LUN_FAIL;
00831         uhi_msc_scsi_callback(false);
00832         return;
00833     }
00834 
00835     uhi_msc_scsi_callback(true);
00836 }
00837 
00838 /**
00839  * \brief Decodes the result of scsi WRITE 10 command
00840  *
00841  * \param b_cbw_succes true, if the scsi command is successful
00842  */
00843 static void uhi_msc_scsi_write_10_done(bool b_cbw_succes)
00844 {
00845     if ((!b_cbw_succes) || (uhi_msc_csw.bCSWStatus != MSD_CSW_COMMAND_PASSED)
00846         || uhi_msc_csw.dCSWDataResidue) {
00847         // Write10 has failed
00848         uhi_msc_lun_sel->status = LUN_FAIL;
00849         uhi_msc_scsi_callback(false);
00850         return;
00851     }
00852 
00853     uhi_msc_scsi_callback(true);
00854 }
00855 
00856 /**
00857  * \brief Sends the CBW packet of the scsi REQUESRT SENSE command
00858  * Called by TEST UNIT READY and READ CAPACITY command in case of error.
00859  *
00860  * \param callback  Callback to call at the end of scsi command
00861  */
00862 static void uhi_msc_scsi_request_sense(uhi_msc_scsi_sense_callback_t callback)
00863 {
00864     uhi_msc_scsi_sense_callback = callback;
00865 
00866     // Prepare specific value of CBW packet
00867     uhi_msc_cbw.dCBWDataTransferLength = sizeof(SBCRequestSenseData);
00868     uhi_msc_cbw.bmCBWFlags = MSD_CBW_DEVICE_TO_HOST;
00869     uhi_msc_cbw.bCBWCBLength = 6;
00870     memset(uhi_msc_cbw.pCommand, 0, sizeof(uhi_msc_cbw.pCommand));
00871     uhi_msc_cbw.pCommand[0] = SBC_REQUEST_SENSE;
00872     uhi_msc_cbw.pCommand[4] = sizeof(SBCRequestSenseData);
00873 
00874     uhi_msc_scsi(uhi_msc_scsi_request_sense_done, (uint8_t *)&uhi_msc_sense);
00875 }
00876 
00877 /**
00878  * \brief Decodes the result of scsi REQUEST SENSE command
00879  *
00880  * \param b_cbw_succes true, if the scsi command is successful
00881  */
00882 static void uhi_msc_scsi_request_sense_done(bool b_cbw_succes)
00883 {
00884     if ((!b_cbw_succes) || uhi_msc_csw.dCSWDataResidue) {
00885         uhi_msc_scsi_callback(false);
00886         return;
00887     }
00888 
00889     // Request sense successful
00890     uhi_msc_scsi_sense_callback();
00891 }
00892 
00893 //@}
00894 
00895 /**
00896  * \name Internal SCSI protocol routines
00897  */
00898 //@{
00899 
00900 /**
00901  * \brief Sends the CBW packet
00902  *
00903  * \param callback  Callback to call at the end of scsi protocol
00904  * \param payload   Pointer on the data to transfer (Optional)
00905  */
00906 static void uhi_msc_scsi(uhi_msc_scsi_callback_t callback, uint8_t *payload)
00907 {
00908     // Save context
00909     uhi_msc_scsi_sub_callback = callback;
00910     uhi_msc_data = payload;
00911 
00912     // Prepare CBW
00913     uhi_msc_cbw.dCBWTag++;
00914     uhi_msc_cbw.dCBWDataTransferLength =
00915         (uhi_msc_cbw.dCBWDataTransferLength);
00916     // CBWCB0 - Operation Code
00917     // CBWCB1 - Obsolete, EVPD = 0
00918     // CBWCB2 - Page Code = 0
00919     // CBWCB3 - MSB(Allocation Length)
00920     // CBWCB4 - LSB(Allocation Length)
00921     // CBWCW5 - Control = 0
00922 
00923     // Start transfer of CBW packet on bulk endpoint OUT
00924     uhi_msc_transfer(uhi_msc_dev_sel->ep_out, (uint8_t *) &uhi_msc_cbw,
00925                      sizeof(uhi_msc_cbw), uhi_msc_cbw_sent);
00926 }
00927 
00928 /**
00929  * \brief Checks the CBW packet transfer and launch the next step
00930  * The next step can be a DATA phase or a CSW packet.
00931  *
00932  * \param add           USB address used by the transfer
00933  * \param status        Transfer status
00934  * \param nb_transfered Number of data transfered
00935  */
00936 static void uhi_msc_cbw_sent(
00937     USBHS_Add_t add,
00938     USBHS_Ep_t ep,
00939     USBH_XfrStatus_t status,
00940     uint32_t nb_transfered)
00941 {
00942     USBHS_Ep_t endp;
00943     UNUSED(add);
00944     UNUSED(ep);
00945     UNUSED(nb_transfered);
00946 
00947     // Checks the result of CBW transfer
00948     if (status != UHD_TRANS_NOERROR) {
00949         if (status == UHD_TRANS_STALL) {
00950             uhi_msc_reset_endpoint(uhi_msc_dev_sel->ep_out,
00951                                    uhi_msc_cbw_rst_stall);
00952             return;
00953         }
00954 
00955         uhi_msc_scsi_sub_callback(false);
00956         return;
00957     }
00958 
00959     assert(nb_transfered == sizeof(uhi_msc_cbw));
00960     uhi_msc_cbw.dCBWDataTransferLength =
00961         (uhi_msc_cbw.dCBWDataTransferLength);
00962     // Here CBW is success
00963 
00964     if (!uhi_msc_cbw.dCBWDataTransferLength) {
00965         // Start CSW phase
00966         uhi_msc_csw_wait();
00967         return;
00968     }
00969 
00970     // Start DATA phase
00971     if (uhi_msc_cbw.bmCBWFlags & MSD_CBW_DEVICE_TO_HOST)
00972         endp = uhi_msc_dev_sel->ep_in;
00973     else
00974         endp = uhi_msc_dev_sel->ep_out;
00975 
00976     uhi_msc_transfer(endp, uhi_msc_data, uhi_msc_cbw.dCBWDataTransferLength,
00977                      uhi_msc_data_transfered);
00978 }
00979 
00980 /**
00981  * \brief Checks the DATA phase transfer and launch the next step
00982  * The next step can be a CSW packet or a endpoint reset in case of STALL.
00983  *
00984  * \param add           USB address used by the transfer
00985  * \param status        Transfer status
00986  * \param nb_transfered Number of data transfered
00987  */
00988 static void uhi_msc_data_transfered(
00989     USBHS_Add_t add,
00990     USBHS_Ep_t ep,
00991     USBH_XfrStatus_t status,
00992     uint32_t nb_transfered)
00993 {
00994     USBHS_Ep_t endp;
00995     UNUSED(add);
00996     UNUSED(ep);
00997     UNUSED(nb_transfered);
00998 
00999     if (status != UHD_TRANS_NOERROR) {
01000         if (status == UHD_TRANS_STALL) {
01001             if (uhi_msc_cbw.bmCBWFlags & MSD_CBW_DEVICE_TO_HOST)
01002                 endp = uhi_msc_dev_sel->ep_in;
01003             else
01004                 endp = uhi_msc_dev_sel->ep_out;
01005 
01006             uhi_msc_reset_endpoint(endp, uhi_msc_data_csw_rst_stall);
01007             return;
01008         }
01009 
01010         uhi_msc_scsi_sub_callback(false);
01011         return;
01012     }
01013 
01014     // DATA phase complete
01015 
01016     // Start CSW phase
01017     uhi_msc_csw_wait();
01018     return;
01019 }
01020 
01021 /**
01022  * \brief Start the transfer of the CSW packet
01023  */
01024 static void uhi_msc_csw_wait(void)
01025 {
01026     // Start transfer of CSW packet on bulk endpoint IN
01027     uhi_msc_transfer(uhi_msc_dev_sel->ep_in, (uint8_t *) & uhi_msc_csw,
01028                      sizeof(uhi_msc_csw), uhi_msc_csw_received);
01029 }
01030 
01031 /**
01032  * \brief Checks the CSW packet transfer
01033  *
01034  * \param add           USB address used by the transfer
01035  * \param status        Transfer status
01036  * \param nb_transfered Number of data transfered
01037  */
01038 static void uhi_msc_csw_received(
01039     USBHS_Add_t add,
01040     USBHS_Ep_t ep,
01041     USBH_XfrStatus_t status,
01042     uint32_t nb_transfered)
01043 {
01044     UNUSED(add);
01045     UNUSED(ep);
01046 
01047     if (status != UHD_TRANS_NOERROR) {
01048         if (status == UHD_TRANS_STALL) {
01049             uhi_msc_reset_endpoint(uhi_msc_dev_sel->ep_in,
01050                                    uhi_msc_data_csw_rst_stall);
01051             return;
01052         }
01053 
01054         uhi_msc_scsi_sub_callback(false);
01055         return;
01056     }
01057 
01058     if ((nb_transfered != sizeof(uhi_msc_csw))
01059         || (uhi_msc_csw.dCSWTag != uhi_msc_cbw.dCBWTag)
01060         || (uhi_msc_csw.dCSWSignature != MSD_CSW_SIGNATURE)) {
01061         // Error in CSW fields
01062         uhi_msc_scsi_sub_callback(false);
01063         return;
01064     }
01065 
01066     // CSW is success
01067     uhi_msc_csw.dCSWDataResidue = uhi_msc_csw.dCSWDataResidue;
01068     uhi_msc_scsi_sub_callback(true);
01069 }
01070 
01071 /**
01072  * \brief Manages the end of setup request RESET ENDPOINT after a CBW packet
01073  *
01074  * \param add           USB address of the setup request
01075  * \param status        Transfer status
01076  * \param payload_trans Number of data transfered during DATA phase
01077  */
01078 static void uhi_msc_cbw_rst_stall(
01079     USBHS_Add_t add,
01080     USBH_XfrStatus_t status,
01081     uint16_t payload_trans)
01082 {
01083     UNUSED(add);
01084     UNUSED(status);
01085     UNUSED(payload_trans);
01086     uhi_msc_scsi_sub_callback(false);
01087 }
01088 
01089 /**
01090  * \brief Manages the end of RESET ENDPOINT request after a DATA or CSW packet
01091  *
01092  * \param add           USB address of the setup request
01093  * \param status        Transfer status
01094  * \param payload_trans Number of data transfered during DATA phase
01095  */
01096 static void uhi_msc_data_csw_rst_stall(
01097     USBHS_Add_t add,
01098     USBH_XfrStatus_t status,
01099     uint16_t payload_trans)
01100 {
01101     UNUSED(add);
01102     UNUSED(payload_trans);
01103 
01104     if (status != UHD_TRANS_NOERROR) {
01105         uhi_msc_scsi_sub_callback(false);
01106         return;
01107     }
01108 
01109     // DATA stalled but CSW must be received after clear of STALL
01110     uhi_msc_csw_wait();
01111 }
01112 
01113 /**
01114  * \brief Start a transfer on an endpoint of current USB MSC device
01115  * Used to send a CBW packet, DATA packet, or a CSW packet.
01116  *
01117  * \param endp          Endpoint to use for this transfer
01118  * \param payload       Pointer on the data to transfer
01119  * \param payload_size  Size of the data to transfer
01120  * \param callback_end  Callback to call at the end of transfer
01121  */
01122 static void uhi_msc_transfer(USBHS_Ep_t endp,
01123                              uint8_t *payload,
01124                              uint16_t payload_size,
01125                              uhd_callback_trans_t callback_end)
01126 {
01127     if (!USBH_HAL_RunEndpoint(uhi_msc_dev_sel->dev->address,
01128                               endp, false, payload, payload_size,
01129                               UHI_MSC_SCSI_TIMEOUT, callback_end))
01130         uhi_msc_scsi_sub_callback(false);
01131 }
01132 
01133 /**
01134  * \brief Sends a setup request RESET ENDPOINT
01135  * Used after a STALL received during a scsi command.
01136  *
01137  * \param endp          Endpoint to reset
01138  * \param callback_end  Callback to call at the end of request
01139  */
01140 static void uhi_msc_reset_endpoint(
01141     USBHS_Ep_t endp, uhd_callback_setup_end_t callback)
01142 {
01143     // Setup Request to reset endpoint
01144     USBGenericRequest req;
01145 
01146     req.bmRequestType = USB_REQ_RECIP_ENDPOINT
01147                         | USB_REQ_TYPE_STANDARD | USB_REQ_DIR_OUT;
01148     req.bRequest = USB_REQ_CLEAR_FEATURE;
01149     req.wValue = USB_EP_FEATURE_HALT;
01150     req.wIndex = endp;
01151     req.wLength = 0;
01152 
01153     if (!USBH_HAL_SetupReq(uhi_msc_dev_sel->dev->address,
01154                            &req, NULL, 0, NULL, callback))
01155         callback(uhi_msc_dev_sel->dev->address, UHD_TRANS_DISCONNECT, 0);
01156 }
01157 
01158 //@}
01159 
01160 //@}
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines