]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Sync USB modules with main trunk.
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 24 Jul 2007 09:54:50 +0000 (09:54 +0000)
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 24 Jul 2007 09:54:50 +0000 (09:54 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3423 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h
MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c
MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h

index 247021b40dbd796d70814f8b6a16fda0bb1a40b0..4df8e9ee7e55b8a39f70e5ac11b08301e4dd8f1a 100644 (file)
@@ -150,10 +150,14 @@ EhcDumpBuf (
   #define EHC_DEBUG(arg)                  EhcDebug    arg\r
   #define EHC_ERROR(arg)                  EhcError    arg\r
   #define EHC_DUMP_QH(arg)                EhcDumpQh   arg\r
+  #define EHC_DUMP_QTD(arg)               EhcDumpQtd  arg\r
+  #define EHC_DUMP_BUF(arg)               EhcDumpBuf  arg\r
 #else\r
   #define EHC_DEBUG(arg)\r
   #define EHC_ERROR(arg)\r
   #define EHC_DUMP_QH(arg)\r
+  #define EHC_DUMP_QTD(arg)\r
+  #define EHC_DUMP_BUF(arg)\r
 #endif\r
 \r
 #endif\r
index b13e4078b0b85c543cc6f5f560bc07a0dbe1f0e0..4c2dc86f06631b9ee7e6900c9dcbf7c87b9b2660 100644 (file)
@@ -771,6 +771,67 @@ EhciDelAllAsyncIntTransfers (
   }\r
 }\r
 \r
+STATIC\r
+EFI_STATUS\r
+EhcFlushAsyncIntMap (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  URB                 *Urb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Flush data from PCI controller specific address to mapped system \r
+  memory address.\r
+\r
+Arguments:\r
+\r
+  Ehc         - The EHCI device\r
+  Urb         - The URB to unmap\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS      - Success to flush data to mapped system memory\r
+  EFI_DEVICE_ERROR - Fail to flush data to mapped system memory\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  UINTN                         Len;\r
+  VOID                          *Map;\r
+\r
+  PciIo = Ehc->PciIo;\r
+  Len   = Urb->DataLen;\r
+\r
+  if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+    MapOp = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    MapOp = EfiPciIoOperationBusMasterRead;\r
+  }\r
+  \r
+  Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Urb->DataMap = NULL;\r
+\r
+  Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
+  if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);\r
+  Urb->DataMap  = Map;\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
 \r
 \r
 /**\r
@@ -873,6 +934,7 @@ EhcMoniteAsyncRequests (
   BOOLEAN                 Finished;\r
   UINT8                   *ProcBuf;\r
   URB                     *Urb;\r
+  EFI_STATUS              Status;\r
 \r
   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
   Ehc     = (USB2_HC_DEV *) Context;\r
@@ -890,6 +952,15 @@ EhcMoniteAsyncRequests (
       continue;\r
     }\r
 \r
+    //\r
+    // Flush any PCI posted write transactions from a PCI host \r
+    // bridge to system memory.\r
+    //\r
+    Status = EhcFlushAsyncIntMap (Ehc, Urb);\r
+    if (EFI_ERROR (Status)) {\r
+      EHC_ERROR (("EhcMoniteAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
+    }\r
+    \r
     //\r
     // Allocate a buffer then copy the transferred data for user.\r
     // If failed to allocate the buffer, update the URB for next\r
index 9fbaf6b417d628c85bf2b99328e794b2404e8cc6..0b5532ec5656af9f3f37d9c56f4c2012a0c4c898 100644 (file)
@@ -881,40 +881,71 @@ UsbEnumeratePort (
   // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.\r
   // ENABLE/RESET is used to reset port. SUSPEND isn't supported.\r
   //\r
-  Status = EFI_SUCCESS;\r
+  \r
+  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {     \r
 \r
-  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {\r
-    //\r
-    // If overcurrent condition is cleared, enable the port again\r
-    //\r
-    if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {\r
-      HubApi->SetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
+    if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {\r
+      //\r
+      // Both OverCurrent and OverCurrentChange set, means over current occurs, \r
+      // which probably is caused by short circuit. It has to wait system hardware\r
+      // to perform recovery.\r
+      //\r
+      USB_DEBUG (("UsbEnumeratePort: Critical Over Current\n", Port));\r
+      return EFI_DEVICE_ERROR;\r
+      \r
+    } else {\r
+      //\r
+      // Only OverCurrentChange set, means system has been recoveried from \r
+      // over current. As a result, all ports are nearly power-off, so\r
+      // it's necessary to detach and enumerate all ports again. \r
+      //\r
+      USB_DEBUG (("UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port)); \r
+      goto ON_ENUMERATE;\r
+      \r
     }\r
+  }\r
 \r
-  } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {\r
+  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {  \r
     //\r
-    // Device connected or disconnected. Either way, if there is\r
-    // already a device present in the bus, need to remove it.\r
+    // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart\r
+    // on 2.0 roothub does. When over-current has influence on 1.1 device, the port \r
+    // would be disabled, so it's also necessary to detach and enumerate again.\r
     //\r
-    Child = UsbFindChild (HubIf, Port);\r
-\r
-    if (Child != NULL) {\r
-      USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port));\r
-      UsbRemoveDevice (Child);\r
-    }\r
+    USB_DEBUG (("UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));\r
+    goto ON_ENUMERATE;\r
+  }\r
+  \r
+  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {\r
+    //\r
+    // Device connected or disconnected normally. \r
+    //\r
+    goto ON_ENUMERATE;\r
+  }\r
 \r
-    if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
-      //\r
-      // Now, new device connected, enumerate and configure the device\r
-      //\r
-      USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port));\r
-      Status = UsbEnumerateNewDev (HubIf, Port);\r
+ON_ENUMERATE:\r
 \r
-    } else {\r
-      USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port));\r
-    }\r
+  // \r
+  // In case there is already a device on this port logically, it's safety to remove\r
+  // and enumerate again.\r
+  //\r
+  Child = UsbFindChild (HubIf, Port);\r
+  \r
+  if (Child != NULL) {\r
+    USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port));\r
+    UsbRemoveDevice (Child);\r
   }\r
-\r
+  \r
+  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
+    //\r
+    // Now, new device connected, enumerate and configure the device \r
+    //\r
+    USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port));\r
+    Status = UsbEnumerateNewDev (HubIf, Port);\r
+  \r
+  } else {\r
+    USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port));\r
+  }\r
+  \r
   HubApi->ClearPortChange (HubIf, Port);\r
   return Status;\r
 }\r
index c5a0604fca71da2f99173229bc5927e9f494ac1e..096b10a831181dbb88f135d272dadcd6d7748519 100644 (file)
@@ -645,11 +645,16 @@ UsbIoGetEndpointDescriptor (
 \r
   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
 \r
-  if ((Descriptor == NULL) || (Index >= UsbIf->IfSetting->Desc.NumEndpoints)) {\r
+  if ((Descriptor == NULL) || (Index > 15)) {\r
     gBS->RestoreTPL (OldTpl);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
   CopyMem (\r
     Descriptor,\r
     &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r
@@ -813,6 +818,11 @@ UsbIoPortReset (
   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
   Dev    = UsbIf->Device;\r
 \r
+  if (UsbIf->IsHub == TRUE) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
   HubIf  = Dev->ParentIf;\r
   Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
 \r
@@ -875,7 +885,6 @@ EFI_USB_IO_PROTOCOL mUsbIoProtocol = {
   UsbIoPortReset\r
 };\r
 \r
-//@MT: EFI_DRIVER_ENTRY_POINT (UsbBusDriverEntryPoint)\r
 \r
 EFI_STATUS\r
 EFIAPI\r
index e9b0a2a72af92a70fc8c6be649fab0feef4f6fe0..e52d11532f7964d4521ef9d2f647b11f0db917fd 100644 (file)
@@ -26,6 +26,34 @@ Revision History
 #include "UsbMassImpl.h"\r
 \r
 \r
+EFI_TPL\r
+UsbGetCurrentTpl (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  return the current TPL, copied from the EDKII glue lib.\r
+\r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  Current TPL\r
+\r
+--*/\r
+{\r
+  EFI_TPL                 Tpl;\r
+\r
+  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  gBS->RestoreTPL (Tpl);\r
+\r
+  return Tpl;\r
+}\r
+\r
 /**\r
   Read an UINT32 from the buffer to avoid byte alignment problems, then\r
   convert that to the little endia. The USB mass storage bootability spec\r
@@ -140,7 +168,7 @@ UsbBootRequestSense (
                         );\r
   if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {\r
     DEBUG ((mUsbMscError, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));\r
-    return EFI_DEVICE_ERROR;\r
+    return Status;\r
   }\r
 \r
   //\r
@@ -151,6 +179,9 @@ UsbBootRequestSense (
   switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {\r
 \r
   case USB_BOOT_SENSE_NO_SENSE:\r
+    Status = EFI_NO_RESPONSE;\r
+    break;\r
+\r
   case USB_BOOT_SENSE_RECOVERED:\r
     //\r
     // Suppose hardware can handle this case, and recover later by itself\r
@@ -159,26 +190,12 @@ UsbBootRequestSense (
     break;\r
 \r
   case USB_BOOT_SENSE_NOT_READY:\r
-    switch (SenseData.ASC) {\r
-    case USB_BOOT_ASC_NO_MEDIA:\r
-      Status              = EFI_NO_MEDIA;\r
-      Media->MediaPresent = FALSE;\r
-      break;\r
-\r
-    case USB_BOOT_ASC_MEDIA_UPSIDE_DOWN:\r
-      Status              = EFI_DEVICE_ERROR;\r
-      Media->MediaPresent = FALSE;\r
-      break;\r
-\r
-    case USB_BOOT_ASC_NOT_READY:\r
-      if (SenseData.ASCQ == USB_BOOT_ASCQ_IN_PROGRESS ||\r
-          SenseData.ASCQ == USB_BOOT_ASCQ_DEVICE_BUSY) {\r
-        //\r
-        // Regular timeout, and need retry once more\r
-        //\r
-        DEBUG ((mUsbMscInfo, "UsbBootRequestSense: Not ready and need retry once more\n"));\r
-        Status = EFI_NOT_READY;\r
-      }\r
+    Status = EFI_DEVICE_ERROR;\r
+    if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) {\r
+          Media->MediaPresent = FALSE;\r
+          Status              = EFI_NO_MEDIA;\r
+    } else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) {\r
+      Status              = EFI_NOT_READY;\r
     }\r
     break;\r
 \r
@@ -189,14 +206,18 @@ UsbBootRequestSense (
   case USB_BOOT_SENSE_UNIT_ATTENTION:\r
     Status = EFI_DEVICE_ERROR;\r
     if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {\r
-      Status = EFI_MEDIA_CHANGED;\r
-      UsbMass->BlockIoMedia.MediaId++;\r
+      //\r
+      // If MediaChange, reset ReadOnly and new MediId\r
+      //\r
+      Status          = EFI_MEDIA_CHANGED;\r
+      Media->ReadOnly = FALSE;\r
+      Media->MediaId++;\r
     }\r
     break;\r
 \r
   case USB_BOOT_SNESE_DATA_PROTECT:\r
-    Status                          = EFI_WRITE_PROTECTED;\r
-    UsbMass->BlockIoMedia.ReadOnly  = TRUE;\r
+    Status          = EFI_WRITE_PROTECTED;\r
+    Media->ReadOnly = TRUE;\r
     break;\r
 \r
   default:\r
@@ -270,6 +291,9 @@ UsbBootExecCmd (
     return EFI_SUCCESS;\r
   }\r
 \r
+  DEBUG ((mUsbMscInfo, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n",\r
+          *(UINT8 *)Cmd ,Status));\r
+\r
   return UsbBootRequestSense (UsbMass);\r
 }\r
 \r
@@ -417,7 +441,7 @@ UsbBootInquiry (
              EfiUsbDataIn,\r
              &InquiryData,\r
              sizeof (USB_BOOT_INQUIRY_DATA),\r
-             USB_BOOT_INQUIRY_CMD_TIMEOUT\r
+             USB_BOOT_GENERAL_CMD_TIMEOUT\r
              );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -485,8 +509,12 @@ UsbBootReadCapacity (
   Media->LastBlock    = UsbBootGetUint32 (CapacityData.LastLba);\r
   Media->BlockSize    = UsbBootGetUint32 (CapacityData.BlockLen);\r
 \r
-  DEBUG ((mUsbMscInfo, "UsbBootReadCapacity Success LBA=%d BlockSize=%d\n",\r
-    Media->LastBlock, Media->BlockSize));\r
+  if (Media->BlockSize == 0) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  DEBUG ((mUsbMscInfo, "UsbBootReadCapacity Success LBA=%ld BlockSize=%d\n",\r
+          Media->LastBlock, Media->BlockSize));\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -503,47 +531,49 @@ UsbBootReadCapacity (
 \r
 **/\r
 EFI_STATUS\r
-UsbBootModeSense (\r
+UsbScsiModeSense (\r
   IN USB_MASS_DEVICE          *UsbMass\r
   )\r
 {\r
   EFI_STATUS                Status;\r
-  USB_BOOT_MODE_SENSE_CMD   ModeSenseCmd;\r
-  USB_BOOT_MODE_PARA_HEADER ModeParaHeader;\r
-  UINT8                     CommandSet;\r
+  USB_SCSI_MODE_SENSE6_CMD         ModeSenseCmd;\r
+  USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;\r
+  EFI_BLOCK_IO_MEDIA               *Media;\r
+\r
+  CopyMem (\r
+    &Media,\r
+    &(UsbMass->BlockIoMedia),\r
+    sizeof (EFI_BLOCK_IO_MEDIA)\r
+    );\r
 \r
-  ZeroMem (&ModeSenseCmd, sizeof (USB_BOOT_MODE_SENSE_CMD));\r
-  ZeroMem (&ModeParaHeader, sizeof (USB_BOOT_MODE_PARA_HEADER));\r
+  ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));\r
+  ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));\r
 \r
   //\r
-  // overuse Context Pointer, the first field of Bot or Cbi is EFI_USB_INTERFACE_DESCRIPTOR\r
+  // ModeSense6 command is defined in [SCSI2Spec-Page151]\r
   //\r
-  CommandSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
-\r
-  if (CommandSet == USB_MASS_STORE_SCSI) {\r
-    //\r
-    // Not UFI Command Set, no ModeSense Command\r
-    //\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  ModeSenseCmd.OpCode         = USB_BOOT_MODE_SENSE10_OPCODE;\r
-  ModeSenseCmd.PageCode       = 0x3f;\r
-  ModeSenseCmd.ParaListLenLsb = (UINT8) sizeof (USB_BOOT_MODE_PARA_HEADER);\r
+  ModeSenseCmd.OpCode         = USB_SCSI_MODE_SENSE6_OPCODE;\r
+  ModeSenseCmd.Lun            = USB_BOOT_LUN (UsbMass->Lun);\r
+  ModeSenseCmd.PageCode       = 0x3F;\r
+  ModeSenseCmd.AllocateLen    = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);\r
 \r
   Status = UsbBootExecCmdWithRetry (\r
              UsbMass,\r
              &ModeSenseCmd,\r
-             sizeof (USB_BOOT_MODE_SENSE_CMD),\r
+             sizeof (USB_SCSI_MODE_SENSE6_CMD),\r
              EfiUsbDataIn,\r
              &ModeParaHeader,\r
-             sizeof (USB_BOOT_MODE_PARA_HEADER),\r
+             sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),\r
              USB_BOOT_GENERAL_CMD_TIMEOUT\r
              );\r
+\r
   //\r
-  // Did nothing with the Header here\r
-  // But probably should\r
+  // ModeSense(6) is used to get the information of WriteProtected. While only some of\r
+  // devices support this command, so have a try here.\r
   //\r
+  if (!EFI_ERROR (Status)) {\r
+    Media->ReadOnly = (ModeParaHeader.DevicePara & 0x80) ? TRUE : FALSE;\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -570,6 +600,15 @@ UsbBootGetParams (
 {\r
   EFI_BLOCK_IO_MEDIA          *Media;\r
   EFI_STATUS                  Status;\r
+  UINT8                       CmdSet;\r
+\r
+  CopyMem (\r
+    &Media,\r
+    &(UsbMass->BlockIoMedia),\r
+    sizeof (EFI_BLOCK_IO_MEDIA)\r
+    );\r
+\r
+  CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
 \r
   Status = UsbBootInquiry (UsbMass);\r
   if (EFI_ERROR (Status)) {\r
@@ -577,29 +616,30 @@ UsbBootGetParams (
     return Status;\r
   }\r
 \r
-  Media = &(UsbMass->BlockIoMedia);\r
   //\r
   // Don't use the Removable bit in inquirydata to test whether the media\r
   // is removable because many flash disks wrongly set this bit.\r
   //\r
   if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {\r
     //\r
-    // CD-Rom or Optical device\r
+    // CD-Rom device and Non-CD optical device\r
     //\r
     UsbMass->OpticalStorage = TRUE;\r
     //\r
     // Default value 2048 Bytes, in case no media present at first time\r
     //\r
     Media->BlockSize        = 0x0800;\r
-  } else {\r
+  }\r
+\r
+  if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {\r
     //\r
-    // Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd\r
+    // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,\r
+    // which is from [MassStorageBootabilitySpec-Page7].\r
+    // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI\r
+    // could get the information of WriteProtected.\r
+    // Since not all device support this command, so skip if fail.\r
     //\r
-    Status = UsbBootModeSense (UsbMass);\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootModeSense (%r)\n", Status));\r
-      return Status;\r
-    }\r
+    UsbScsiModeSense (UsbMass);\r
   }\r
 \r
   return UsbBootReadCapacity (UsbMass);\r
@@ -623,6 +663,8 @@ UsbBootDetectMedia (
 {\r
   EFI_BLOCK_IO_MEDIA        OldMedia;\r
   EFI_BLOCK_IO_MEDIA        *Media;\r
+  UINT8                     CmdSet;\r
+  EFI_TPL                   OldTpl;\r
   EFI_STATUS                Status;\r
 \r
   Media    = &UsbMass->BlockIoMedia;\r
@@ -633,54 +675,80 @@ UsbBootDetectMedia (
     sizeof (EFI_BLOCK_IO_MEDIA)\r
     );\r
 \r
-  //\r
-  // First test whether the device is ready and get status\r
-  // If media changed or ready, need read the device's capacity\r
-  //\r
+  CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
+\r
   Status = UsbBootIsUnitReady (UsbMass);\r
-  if ((Status == EFI_SUCCESS && Media->MediaPresent) ||\r
-      (Status == EFI_MEDIA_CHANGED)) {\r
-    if ((UsbMass->Pdt != USB_PDT_CDROM) &&\r
-        (UsbMass->Pdt != USB_PDT_OPTICAL)) {\r
-      //\r
-      // Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd\r
-      //\r
-      UsbBootModeSense (UsbMass);\r
-    }\r
-    DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need Read Capacity\n"));\r
-    Status = UsbBootReadCapacity (UsbMass);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((mUsbMscError, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));\r
+    goto ON_ERROR;\r
   }\r
+\r
+  if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {\r
+    //\r
+    // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,\r
+    // which is from [MassStorageBootabilitySpec-Page7].\r
+    // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI\r
+    // could get the information of WriteProtected.\r
+    // Since not all device support this command, so skip if fail.\r
+    //\r
+    UsbScsiModeSense (UsbMass);\r
+  }\r
+\r
+  Status = UsbBootReadCapacity (UsbMass);\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    DEBUG ((mUsbMscError, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));\r
+    goto ON_ERROR;\r
   }\r
 \r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
   //\r
   // Detect whether it is necessary to reinstall the BlockIO\r
   //\r
+  // MediaId may change in RequestSense for MediaChanged\r
+  // MediaPresent may change in RequestSense for NoMedia\r
+  // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged\r
+  // MediaPresent/BlockSize/LastBlock may change in ReadCapacity\r
+  //\r
   if ((Media->MediaId != OldMedia.MediaId) ||\r
       (Media->MediaPresent != OldMedia.MediaPresent) ||\r
       (Media->ReadOnly != OldMedia.ReadOnly) ||\r
       (Media->BlockSize != OldMedia.BlockSize) ||\r
       (Media->LastBlock != OldMedia.LastBlock)) {\r
-    DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need reinstall BlockIoProtocol\n"));\r
-    Media->MediaId++;\r
+\r
+    OldTpl = UsbGetCurrentTpl ();\r
+    DEBUG ((mUsbMscError, "UsbBootDetectMedia: TPL before reinstall BlockIoProtocol is %d\n", OldTpl));\r
+\r
+    gBS->RestoreTPL (TPL_CALLBACK);\r
+\r
     gBS->ReinstallProtocolInterface (\r
            UsbMass->Controller,\r
            &gEfiBlockIoProtocolGuid,\r
            &UsbMass->BlockIo,\r
            &UsbMass->BlockIo\r
            );\r
+\r
+    DEBUG ((mUsbMscError, "UsbBootDetectMedia: TPL after reinstall is %d\n", UsbGetCurrentTpl()));\r
+    ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
+\r
+    gBS->RaiseTPL (OldTpl);\r
+\r
     //\r
-    // Check whether media present or media changed or write protected\r
+    // Update MediaId after reinstall BLOCK_IO_PROTOCOL\r
     //\r
-    if (Media->MediaPresent == FALSE) {\r
-      Status = EFI_NO_MEDIA;\r
-    }\r
-    if (Media->MediaId != OldMedia.MediaId) {\r
-      Status = EFI_MEDIA_CHANGED;\r
+    if (Media->MediaPresent != OldMedia.MediaPresent) {\r
+      if (Media->MediaPresent == TRUE) {\r
+        Media->MediaId = 1;\r
+      } else {\r
+        Media->MediaId = 0;\r
+      }\r
     }\r
-    if (Media->ReadOnly != OldMedia.ReadOnly) {\r
-      Status = EFI_WRITE_PROTECTED;\r
+\r
+    if ((Media->ReadOnly != OldMedia.ReadOnly) ||\r
+        (Media->BlockSize != OldMedia.BlockSize) ||\r
+        (Media->LastBlock != OldMedia.LastBlock)) {\r
+      Media->MediaId++;\r
     }\r
   }\r
 \r
@@ -728,13 +796,9 @@ UsbBootReadBlocks (
     ByteSize  = (UINT32)Count * BlockSize;\r
 \r
     //\r
-    // Optical device need longer timeout than other device\r
+    // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
     //\r
-    if (UsbMass->OpticalStorage == TRUE) {\r
-      Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;\r
-    } else {\r
-      Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;\r
-    }\r
+    Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
 \r
     //\r
     // Fill in the command then execute\r
@@ -808,13 +872,9 @@ UsbBootWriteBlocks (
     ByteSize  = (UINT32)Count * BlockSize;\r
 \r
     //\r
-    // Optical device need longer timeout than other device\r
+    // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
     //\r
-    if (UsbMass->OpticalStorage == TRUE) {\r
-      Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;\r
-    } else {\r
-      Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;\r
-    }\r
+    Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
 \r
     //\r
     // Fill in the write10 command block\r
index dc4b43faae0f8764dcc54a0a4ba005c919a50e43..bfef2609ad32d7090ea9cd858a00058900113b4f 100644 (file)
@@ -39,12 +39,14 @@ enum {
   USB_BOOT_INQUIRY_OPCODE         = 0x12,\r
   USB_BOOT_REQUEST_SENSE_OPCODE   = 0x03,\r
 \r
-  USB_BOOT_MODE_SENSE10_OPCODE    = 0x5a,\r
+  USB_BOOT_MODE_SENSE10_OPCODE    = 0x5A,\r
   USB_BOOT_READ_CAPACITY_OPCODE   = 0x25,\r
   USB_BOOT_TEST_UNIT_READY_OPCODE = 0x00,\r
   USB_BOOT_READ10_OPCODE          = 0x28,\r
-  USB_BOOT_WRITE10_OPCODE         = 0x2a,\r
+  USB_BOOT_WRITE10_OPCODE         = 0x2A,\r
 \r
+  USB_SCSI_MODE_SENSE6_OPCODE     = 0x1A,\r
+  \r
   //\r
   // The Sense Key part of the sense data. Sense data has three levels:\r
   // Sense key, Additional Sense Code and Additional Sense Code Qualifier\r
@@ -64,13 +66,9 @@ enum {
   USB_BOOT_SENSE_MISCOMPARE       = 0x0E, // Source data mis-match while verfying.\r
 \r
   USB_BOOT_ASC_NOT_READY          = 0x04,\r
-  USB_BOOT_ASC_MEDIA_UPSIDE_DOWN  = 0x06,\r
   USB_BOOT_ASC_NO_MEDIA           = 0x3A,\r
   USB_BOOT_ASC_MEDIA_CHANGE       = 0x28,\r
 \r
-  USB_BOOT_ASCQ_IN_PROGRESS       = 0x01,\r
-  USB_BOOT_ASCQ_DEVICE_BUSY       = 0xFF,\r
-\r
   //\r
   // Other parameters\r
   //\r
@@ -90,11 +88,13 @@ enum {
   //\r
   // Boot Transfer timeout\r
   //\r
-  USB_BOOT_GENERAL_BLOCK_TIMEOUT  = 200 * USB_MASS_STALL_1_MS,\r
-  USB_BOOT_OPTICAL_BLOCK_TIMEOUT  = 1 * USB_MASS_STALL_1_S,\r
-  USB_BOOT_GENERAL_CMD_TIMEOUT    = 1 * USB_MASS_STALL_1_S,\r
-  USB_BOOT_INQUIRY_CMD_TIMEOUT    = 3 * USB_MASS_STALL_1_S,\r
-\r
+  // USB2.0 Spec define the up-limit timeout 5s for all command. USB floppy, \r
+  // USB CD-Rom and iPod devices are much slower than USB key when reponse \r
+  // most of commands, So we set 5s as timeout here.\r
+  // \r
+  //\r
+  USB_BOOT_GENERAL_CMD_TIMEOUT    = 5 * USB_MASS_STALL_1_S,\r
+  \r
   //\r
   // Supported PDT codes, or Peripheral Device Type\r
   //\r
@@ -159,7 +159,7 @@ typedef struct {
   UINT8             ParaListLenLsb;\r
   UINT8             Reserved1;\r
   UINT8             Pad[2];\r
-} USB_BOOT_MODE_SENSE_CMD;\r
+} USB_BOOT_MODE_SENSE10_CMD;\r
 \r
 typedef struct {\r
   UINT8             ModeDataLenMsb;\r
@@ -167,7 +167,7 @@ typedef struct {
   UINT8             Reserved0[4];\r
   UINT8             BlkDesLenMsb;\r
   UINT8             BlkDesLenLsb;\r
-} USB_BOOT_MODE_PARA_HEADER;\r
+} USB_BOOT_MODE_SENSE10_PARA_HEADER;\r
 \r
 typedef struct {\r
   UINT8             OpCode;\r
@@ -209,6 +209,22 @@ typedef struct {
   UINT8             ASCQ;           // Additional Sense Code Qualifier\r
   UINT8             Reserverd2[4];\r
 } USB_BOOT_REQUEST_SENSE_DATA;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;\r
+  UINT8             PageCode;\r
+  UINT8             Reserved0;\r
+  UINT8             AllocateLen;\r
+  UINT8             Control;\r
+} USB_SCSI_MODE_SENSE6_CMD;\r
+\r
+typedef struct {\r
+  UINT8             ModeDataLen;\r
+ UINT8             MediumType;\r
+  UINT8             DevicePara;\r
+  UINT8             BlkDesLen;\r
+} USB_SCSI_MODE_SENSE6_PARA_HEADER;\r
 #pragma pack()\r
 \r
 //\r