Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbhost_ms.c Source File

usbhost_ms.c

00001 /*
00002 **************************************************************************************************************
00003 *                                                 NXP USB Host Stack
00004 *
00005 *                                     (c) Copyright 2008, NXP SemiConductors
00006 *                                     (c) Copyright 2008, OnChip  Technologies LLC
00007 *                                                 All Rights Reserved
00008 *
00009 *                                                  www.nxp.com
00010 *                                               www.onchiptech.com
00011 *
00012 * File           : usbhost_ms.c
00013 * Programmer(s)  : Ravikanth.P
00014 * Version        :
00015 *
00016 **************************************************************************************************************
00017 */
00018 
00019 /*
00020 **************************************************************************************************************
00021 *                                       INCLUDE HEADER FILES
00022 **************************************************************************************************************
00023 */
00024 
00025 #include  "usbhost_ms.h"
00026 
00027 /*
00028 **************************************************************************************************************
00029 *                                         GLOBAL VARIABLES
00030 **************************************************************************************************************
00031 */
00032 
00033 USB_INT32U  MS_BlkSize;
00034 
00035 /*
00036 **************************************************************************************************************
00037 *                                      INITIALIZE MASS STORAGE INTERFACE
00038 *
00039 * Description: This function initializes the mass storage interface
00040 *
00041 * Arguments  : None
00042 *
00043 * Returns    : OK                     if Success
00044 *              ERR_INVALID_BOOTSIG    if Failed
00045 *
00046 **************************************************************************************************************
00047 */
00048 
00049 USB_INT32S MS_Init (USB_INT32U *blkSize, USB_INT32U *numBlks, USB_INT08U *inquiryResult)
00050 {
00051     USB_INT08U  retry;
00052     USB_INT32S  rc;
00053 
00054     MS_GetMaxLUN();                                                    /* Get maximum logical unit number   */
00055     retry  = 80;
00056     while(retry) {
00057         rc = MS_TestUnitReady();                                       /* Test whether the unit is ready    */
00058         if (rc == OK) {
00059             break;
00060         }
00061         MS_GetSenseInfo();                                             /* Get sense information             */
00062         retry--;
00063     }
00064     if (rc != OK) {
00065         PRINT_Err(rc);
00066         return (rc);
00067     }
00068     rc = MS_ReadCapacity(numBlks, blkSize);                         /* Read capacity of the disk         */
00069     MS_BlkSize = *blkSize;                      // Set global
00070     rc = MS_Inquire (inquiryResult);
00071     return (rc);
00072 }
00073 /*
00074 **************************************************************************************************************
00075 *                                         PARSE THE CONFIGURATION
00076 *
00077 * Description: This function is used to parse the configuration
00078 *
00079 * Arguments  : None
00080 *
00081 * Returns    : OK                     if Success
00082 *              ERR_INVALID_BOOTSIG    if Failed
00083 *
00084 **************************************************************************************************************
00085 */
00086 
00087 USB_INT32S  MS_ParseConfiguration (void)
00088 {
00089     volatile  USB_INT08U  *desc_ptr;
00090               USB_INT08U   ms_int_found;
00091 
00092 
00093     desc_ptr     = TDBuffer;
00094     ms_int_found = 0;
00095 
00096     if (desc_ptr[1] != USB_DESCRIPTOR_TYPE_CONFIGURATION) {    
00097         return (ERR_BAD_CONFIGURATION);
00098     }
00099     desc_ptr += desc_ptr[0];
00100 
00101     while (desc_ptr != TDBuffer + ReadLE16U(&TDBuffer[2])) {
00102 //  while (desc_ptr != TDBuffer + *((USB_INT16U *) &TDBuffer[2])) {
00103 
00104         switch (desc_ptr[1]) {
00105 
00106             case USB_DESCRIPTOR_TYPE_INTERFACE:                       /* If it is an interface descriptor   */
00107                  if (desc_ptr[5] == MASS_STORAGE_CLASS &&             /* check if the class is mass storage */
00108                      desc_ptr[6] == MASS_STORAGE_SUBCLASS_SCSI &&     /* check if the subclass is SCSI      */
00109                      desc_ptr[7] == MASS_STORAGE_PROTOCOL_BO) {       /* check if the protocol is Bulk only */
00110                      ms_int_found = 1;
00111                      desc_ptr    += desc_ptr[0];                      /* Move to next descriptor start      */
00112                  }
00113                  break;
00114 
00115             case USB_DESCRIPTOR_TYPE_ENDPOINT:                        /* If it is an endpoint descriptor    */
00116                  if ((desc_ptr[3] & 0x03) == 0x02) {                  /* If it is Bulk endpoint             */
00117                      if (desc_ptr[2] & 0x80) {                        /* If it is In endpoint               */
00118                          EDBulkIn->Control =  1                             |      /* USB address           */
00119                                               ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
00120                                               (2 << 11)                     |      /* direction             */
00121                                               (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
00122                          desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
00123                      } else {                                         /* If it is Out endpoint              */
00124                          EDBulkOut->Control = 1                             |      /* USB address           */
00125                                               ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
00126                                               (1 << 11)                     |      /* direction             */
00127                                               (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
00128                          desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
00129                      }
00130                  } else {                                             /* If it is not bulk end point        */
00131                      desc_ptr += desc_ptr[0];                         /* Move to next descriptor start      */
00132                  }
00133                  break;
00134 
00135             default:                                 /* If the descriptor is neither interface nor endpoint */
00136                  desc_ptr += desc_ptr[0];                             /* Move to next descriptor start      */
00137                  break;
00138         }
00139     }
00140     if (ms_int_found) {
00141         PRINT_Log("Mass Storage device connected\r\n");
00142         return (OK);
00143     } else {
00144         PRINT_Log("Not a Mass Storage device\r\n");
00145         return (ERR_NO_MS_INTERFACE);
00146     }
00147 }
00148 
00149 /*
00150 **************************************************************************************************************
00151 *                                         GET MAXIMUM LOGICAL UNIT
00152 *
00153 * Description: This function returns the maximum logical unit from the device
00154 *
00155 * Arguments  : None
00156 *
00157 * Returns    : OK                     if Success
00158 *              ERR_INVALID_BOOTSIG    if Failed
00159 *
00160 **************************************************************************************************************
00161 */
00162 
00163 USB_INT32S  MS_GetMaxLUN (void)
00164 {
00165     USB_INT32S  rc;
00166 
00167 
00168     rc = Host_CtrlRecv(USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE,
00169                        MS_GET_MAX_LUN_REQ,
00170                        0,
00171                        0,
00172                        1,
00173                        TDBuffer);
00174     return (rc); 
00175 }
00176 
00177 /*
00178 **************************************************************************************************************
00179 *                                          GET SENSE INFORMATION
00180 *
00181 * Description: This function is used to get sense information from the device
00182 *
00183 * Arguments  : None
00184 *
00185 * Returns    : OK       if Success
00186 *              ERROR    if Failed
00187 *
00188 **************************************************************************************************************
00189 */
00190 
00191 USB_INT32S  MS_GetSenseInfo (void)
00192 {
00193     USB_INT32S  rc;
00194 
00195 
00196     Fill_MSCommand(0, 0, 0, MS_DATA_DIR_IN, SCSI_CMD_REQUEST_SENSE, 6);
00197     rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
00198     if (rc == OK) {
00199         rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, 18);
00200         if (rc == OK) {
00201             rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
00202             if (rc == OK) {
00203                 if (TDBuffer[12] != 0) {
00204                     rc = ERR_MS_CMD_FAILED;
00205                 }
00206             }
00207         }
00208     }
00209     return (rc);
00210 }
00211 
00212 /*
00213 **************************************************************************************************************
00214 *                                           TEST UNIT READY
00215 *
00216 * Description: This function is used to test whether the unit is ready or not
00217 *
00218 * Arguments  : None
00219 *
00220 * Returns    : OK       if Success
00221 *              ERROR    if Failed
00222 *
00223 **************************************************************************************************************
00224 */
00225 
00226 USB_INT32S  MS_TestUnitReady (void)
00227 {
00228     USB_INT32S  rc;
00229 
00230 
00231     Fill_MSCommand(0, 0, 0, MS_DATA_DIR_NONE, SCSI_CMD_TEST_UNIT_READY, 6);
00232     rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
00233     if (rc == OK) {
00234         rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
00235         if (rc == OK) {        
00236             if (TDBuffer[12] != 0) {
00237                 rc = ERR_MS_CMD_FAILED;
00238             }
00239         }
00240     }
00241     return (rc);
00242 }
00243 
00244 /*
00245 **************************************************************************************************************
00246 *                                            READ CAPACITY
00247 *
00248 * Description: This function is used to read the capacity of the mass storage device
00249 *
00250 * Arguments  : None
00251 *
00252 * Returns    : OK       if Success
00253 *              ERROR    if Failed
00254 *
00255 **************************************************************************************************************
00256 */
00257 
00258 USB_INT32S MS_ReadCapacity (USB_INT32U *numBlks, USB_INT32U *blkSize)
00259 {
00260     USB_INT32S  rc;
00261 
00262 
00263     Fill_MSCommand(0, 0, 0, MS_DATA_DIR_IN, SCSI_CMD_READ_CAPACITY, 10);
00264     rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
00265     if (rc == OK) {
00266         rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, 8);
00267         if (rc == OK) {
00268             if (numBlks)
00269                 *numBlks = ReadBE32U(&TDBuffer[0]);
00270             if (blkSize)
00271                 *blkSize = ReadBE32U(&TDBuffer[4]);
00272             rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
00273             if (rc == OK) {
00274                 if (TDBuffer[12] != 0) {
00275                     rc = ERR_MS_CMD_FAILED;
00276                 }
00277             }
00278         }
00279     }
00280     return (rc);
00281 }
00282 
00283 
00284 
00285 USB_INT32S MS_Inquire (USB_INT08U *response)
00286 {
00287     USB_INT32S rc;
00288     USB_INT32U i;
00289 
00290     Fill_MSCommand(0, 0, 0, MS_DATA_DIR_IN, SCSI_CMD_INQUIRY, 6);
00291     rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
00292     if (rc == OK) {
00293         rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, INQUIRY_LENGTH);
00294         if (rc == OK) {
00295             if (response) {
00296                 for ( i = 0; i < INQUIRY_LENGTH; i++ )
00297                     *response++ = *TDBuffer++;
00298 #if 0
00299                 MemCpy (response, TDBuffer, INQUIRY_LENGTH);
00300                 StrNullTrailingSpace (response->vendorID, SCSI_INQUIRY_VENDORCHARS);
00301                 StrNullTrailingSpace (response->productID, SCSI_INQUIRY_PRODUCTCHARS);
00302                 StrNullTrailingSpace (response->productRev, SCSI_INQUIRY_REVCHARS);
00303 #endif
00304             }
00305             rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
00306             if (rc == OK) {
00307                 if (TDBuffer[12] != 0) {    // bCSWStatus byte
00308                     rc = ERR_MS_CMD_FAILED;
00309                 }
00310             }
00311         }
00312     }
00313     return (rc);
00314 }
00315 
00316 /*
00317 **************************************************************************************************************
00318 *                                         RECEIVE THE BULK DATA
00319 *
00320 * Description: This function is used to receive the bulk data
00321 *
00322 * Arguments  : None
00323 *
00324 * Returns    : OK                     if Success
00325 *              ERR_INVALID_BOOTSIG    if Failed
00326 *
00327 **************************************************************************************************************
00328 */
00329     
00330 USB_INT32S  MS_BulkRecv (          USB_INT32U   block_number,
00331                                    USB_INT16U   num_blocks,
00332                          volatile  USB_INT08U  *user_buffer)
00333 {
00334     USB_INT32S  rc;
00335     int i;
00336     volatile USB_INT08U *c = user_buffer;
00337     for (i=0;i<MS_BlkSize*num_blocks;i++)
00338         *c++ = 0;
00339 
00340 
00341     Fill_MSCommand(block_number, MS_BlkSize, num_blocks, MS_DATA_DIR_IN, SCSI_CMD_READ_10, 10);
00342 
00343     rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
00344     if (rc == OK) {
00345         rc = Host_ProcessTD(EDBulkIn, TD_IN, user_buffer, MS_BlkSize * num_blocks);
00346         if (rc == OK) {
00347             rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
00348             if (rc == OK) {
00349                 if (TDBuffer[12] != 0) {
00350                     rc = ERR_MS_CMD_FAILED;
00351                 }
00352             }
00353         }
00354     }
00355     return (rc);
00356 }
00357 
00358 /*
00359 **************************************************************************************************************
00360 *                                         SEND BULK DATA
00361 *
00362 * Description: This function is used to send the bulk data
00363 *
00364 * Arguments  : None
00365 *
00366 * Returns    : OK                     if Success
00367 *              ERR_INVALID_BOOTSIG    if Failed
00368 *
00369 **************************************************************************************************************
00370 */
00371 
00372 USB_INT32S  MS_BulkSend (          USB_INT32U   block_number,
00373                                    USB_INT16U   num_blocks,
00374                          volatile  USB_INT08U  *user_buffer)
00375 {
00376     USB_INT32S  rc;
00377 
00378 
00379     Fill_MSCommand(block_number, MS_BlkSize, num_blocks, MS_DATA_DIR_OUT, SCSI_CMD_WRITE_10, 10);
00380 
00381     rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
00382     if (rc == OK) {
00383         rc = Host_ProcessTD(EDBulkOut, TD_OUT, user_buffer, MS_BlkSize * num_blocks);
00384         if (rc == OK) {
00385             rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
00386             if (rc == OK) {
00387                 if (TDBuffer[12] != 0) {
00388                     rc = ERR_MS_CMD_FAILED;
00389                 }
00390             }
00391         }
00392     }
00393     return (rc);
00394 }
00395 
00396 /*
00397 **************************************************************************************************************
00398 *                                         FILL MASS STORAGE COMMAND
00399 *
00400 * Description: This function is used to fill the mass storage command
00401 *
00402 * Arguments  : None
00403 *
00404 * Returns    : OK                     if Success
00405 *              ERR_INVALID_BOOTSIG    if Failed
00406 *
00407 **************************************************************************************************************
00408 */
00409 
00410 void  Fill_MSCommand (USB_INT32U   block_number,
00411                       USB_INT32U   block_size,
00412                       USB_INT16U   num_blocks,
00413                       MS_DATA_DIR  direction,
00414                       USB_INT08U   scsi_cmd,
00415                       USB_INT08U   scsi_cmd_len)
00416 {
00417             USB_INT32U  data_len;
00418     static  USB_INT32U  tag_cnt = 0;
00419             USB_INT32U  cnt;
00420 
00421 
00422     for (cnt = 0; cnt < CBW_SIZE; cnt++) {
00423          TDBuffer[cnt] = 0;
00424     }
00425     switch(scsi_cmd) {
00426 
00427         case SCSI_CMD_TEST_UNIT_READY:
00428              data_len = 0;
00429              break;
00430         case SCSI_CMD_READ_CAPACITY:
00431              data_len = 8;
00432              break;
00433         case SCSI_CMD_REQUEST_SENSE:
00434              data_len = 18;
00435              break;
00436         case SCSI_CMD_INQUIRY:
00437              data_len = 36;
00438              break;
00439         default:
00440              data_len = block_size * num_blocks;
00441              break;
00442     }
00443     WriteLE32U(TDBuffer, CBW_SIGNATURE);
00444     WriteLE32U(&TDBuffer[4], tag_cnt);
00445     WriteLE32U(&TDBuffer[8], data_len);
00446     TDBuffer[12]     = (direction == MS_DATA_DIR_NONE) ? 0 : direction;
00447     TDBuffer[14]     = scsi_cmd_len;                                   /* Length of the CBW                 */
00448     TDBuffer[15]     = scsi_cmd;
00449     if ((scsi_cmd     == SCSI_CMD_REQUEST_SENSE)
00450      || (scsi_cmd     == SCSI_CMD_INQUIRY)) {
00451         TDBuffer[19] = (USB_INT08U)data_len;
00452     } else {
00453         WriteBE32U(&TDBuffer[17], block_number);
00454     }
00455     WriteBE16U(&TDBuffer[22], num_blocks);
00456 }