text: //+-------------------------------------------------------------------------
  //
  //  Microsoft Windows
  //
  //  Copyright (C) Microsoft Corporation, 1997 - 1999
  //
  //  File:       timing.c
  //
  //--------------------------------------------------------------------------
  
  #include "intel.h"
  
  //
  // PiixTiming[Master Timing Mode][Slave Timing Mode]
  //    
  PIIX_SPECIAL_TIMING_REGISTER PiixSpecialTiming[PiixMode_MaxMode] =
  {
      {
      PIIX_TIMING_DMA_TIMING_ENABLE(0) | 
      PIIX_TIMING_PREFETCH_AND_POSTING_ENABLE(0) |
      PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(0) |
      PIIX_TIMING_FAST_TIMING_BANK_ENABLE(0)
      },                                                  // not present
  
      {
      PIIX_TIMING_DMA_TIMING_ENABLE(0) | 
      PIIX_TIMING_PREFETCH_AND_POSTING_ENABLE(0) |
      PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(0) |    
      PIIX_TIMING_FAST_TIMING_BANK_ENABLE(0)
      },                                                  // piix timing mode 0
  
      {
      PIIX_TIMING_DMA_TIMING_ENABLE(0) |
      PIIX_TIMING_PREFETCH_AND_POSTING_ENABLE(0) |
      PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(0) |    
      PIIX_TIMING_FAST_TIMING_BANK_ENABLE(1)
      },                                                  // piix timing mode 2
  
      {
      PIIX_TIMING_DMA_TIMING_ENABLE(0) |
      PIIX_TIMING_PREFETCH_AND_POSTING_ENABLE(0) |
      PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(1) |    
      PIIX_TIMING_FAST_TIMING_BANK_ENABLE(1)
      },                                                  // piix timing mode 3
  
      {
      PIIX_TIMING_DMA_TIMING_ENABLE(0) |
      PIIX_TIMING_PREFETCH_AND_POSTING_ENABLE(0) |
      PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(1) |
      PIIX_TIMING_FAST_TIMING_BANK_ENABLE(1)
      }                                                   // piix timing mode 4
  };
  
  UCHAR PiixIoReadySamplePointClockSetting[PiixMode_MaxMode] =
  {
      0,
      0,
      1,
      2,
      2
  };
  
  UCHAR PiixRecoveryTimeClockSetting[PiixMode_MaxMode] =
  {
      0,
      0,
      0,
      1,
      3
  };
  
  NTSTATUS
  PiixIdeUdmaModesSupported (
      IN IDENTIFY_DATA    IdentifyData,
      IN OUT PULONG       BestXferMode,
      IN OUT PULONG       CurrentMode
      )
  {
      ULONG bestXferMode =0;
      ULONG currentMode = 0;
  
      if (IdentifyData.TranslationFieldsValid & (1 << 2)) {
  
          if (IdentifyData.UltraDMASupport) {
  
              GetHighestTransferMode( IdentifyData.UltraDMASupport,
                                         bestXferMode);
              *BestXferMode = bestXferMode;
          }
  
          if (IdentifyData.UltraDMAActive) {
  
              GetHighestTransferMode( IdentifyData.UltraDMAActive,
                                         currentMode);
              *CurrentMode = currentMode;
          }
      }
  
      return STATUS_SUCCESS;
  }
  
  NTSTATUS
  PiixIdeTransferModeSelect (
      IN     PDEVICE_EXTENSION            DeviceExtension,
      IN OUT PPCIIDE_TRANSFER_MODE_SELECT TransferModeSelect
      )
  {
      NTSTATUS status;
      ULONG driveBestXferMode[MAX_IDE_DEVICE];
      PIIX_TIMING_REGISTER piixTimingReg;
      PIIX3_SLAVE_TIMING_REGISTER piixSlaveTimingReg;
      PIIX4_UDMA_CONTROL_REGISTER piix4UdmaControlReg;
      PIIX4_UDMA_TIMING_REGISTER piix4UdmaTimingReg;
      ICH_IO_CONFIG_REGISTER ioConfigReg;
      USHORT dataMask;
      ULONG i;
  
  
      //
      // Store the identify data for later use.
      //
      for (i=0;i<MAX_IDE_DEVICE;i++) {
          DeviceExtension->IdentifyData[i]=TransferModeSelect->IdentifyData[i];
      }
      status = PiixIdepTransferModeSelect (
                   DeviceExtension,
                   TransferModeSelect,
                   driveBestXferMode,
                   &piixTimingReg,
                   &piixSlaveTimingReg,
                   &piix4UdmaControlReg,
                   &piix4UdmaTimingReg,
                   &ioConfigReg
                   );
  
      if (NT_SUCCESS(status)) {
  
  #if DBG
  
      {
          PIIX_TIMING_REGISTER piixOldTimingReg[2];
          PIIX3_SLAVE_TIMING_REGISTER piixOldSlaveTimingReg;
          PIIX4_UDMA_CONTROL_REGISTER piix4OldUdmaControlReg;
          PIIX4_UDMA_TIMING_REGISTER piix4OldUdmaTimingReg;
          ICH_IO_CONFIG_REGISTER oldIoConfigReg;
          ULONG channel;
  
  #define BitSet(Data, Mask, NewData)     Data = ((Data & ~Mask) | (Mask & NewData));
  
          piixOldSlaveTimingReg.AsUChar = 0;
          piix4OldUdmaControlReg.AsUChar = 0;
          piix4OldUdmaTimingReg.AsUChar = 0;
  
          channel = TransferModeSelect->Channel;
  
          PciIdeXGetBusData (
              DeviceExtension,
              piixOldTimingReg, 
              FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, Timing),
              sizeof (piixOldTimingReg)
              );
  
          PciIdeXDebugPrint ((1, 
                       "Old PIIX Timing Register Value (IDETIM = 0x%x", 
                       piixOldTimingReg[channel].AsUShort));
  
          if (!IS_PIIX(DeviceExtension->DeviceId)) {
  
              PciIdeXGetBusData (
                  DeviceExtension,
                  &piixOldSlaveTimingReg, 
                  FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, SlaveTiming),
                  sizeof (piixOldSlaveTimingReg)
                  );
  
              PciIdeXDebugPrint ((1, 
                           " SIDETIM (0x%x)", 
                           piixOldSlaveTimingReg.AsUChar));
          }
  
          if (IS_UDMA_CONTROLLER(DeviceExtension->DeviceId)) {
  
              PciIdeXGetBusData (
                  DeviceExtension,
                  &piix4OldUdmaControlReg, 
                  FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, UdmaControl),
                  sizeof (piix4OldUdmaControlReg)
                  );
  
              PciIdeXDebugPrint ((1, 
                           " SDMACTL (0x%x)", 
                           piix4OldUdmaControlReg.AsUChar));
  
              PciIdeXGetBusData (
                  DeviceExtension,
                  &piix4OldUdmaTimingReg, 
                  FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, UdmaTiming[channel]),
                  sizeof (piix4OldUdmaTimingReg)
                  );
  
              PciIdeXDebugPrint ((1, 
                           " SDMATIM (0x%x)", 
                           piix4OldUdmaTimingReg.AsUChar));
          }
  
          if (IS_ICH_(DeviceExtension->DeviceId) || 
              IS_ICH0(DeviceExtension->DeviceId)) {
  
              PciIdeXGetBusData (
                  DeviceExtension,
                  &oldIoConfigReg, 
                  FIELD_OFFSET(ICH_PCI_CONFIG_DATA, IoConfig),
                  sizeof (oldIoConfigReg)
                  );
  
              PciIdeXDebugPrint ((1, 
                           " I/O Control (0x%x)", 
                           oldIoConfigReg.AsUShort));
          }
                                
          PciIdeXDebugPrint ((1, "\n"));
  
          if (channel == 0) {
  
              BitSet (piixOldSlaveTimingReg.AsUChar, 0x0f, piixSlaveTimingReg.AsUChar);
              BitSet (piix4OldUdmaControlReg.AsUChar, 0x03, piix4UdmaControlReg.AsUChar);
                                 
          } else {
  
              BitSet (piixOldSlaveTimingReg.AsUChar, 0xf0, piixSlaveTimingReg.AsUChar);
              BitSet (piix4OldUdmaControlReg.AsUChar, 0x0c, piix4UdmaControlReg.AsUChar);
          }
          BitSet (oldIoConfigReg.AsUShort, 0x0f, ioConfigReg.AsUShort);
                       
          PciIdeXDebugPrint ((1, 
                       "New PIIX/ICH Timing Register Value (IDETIM = 0x%x, SIDETIM (0x%x), SDMACTL (0x%x), SDMATIM (0x%x), IOCTRL (0x%x)\n", 
                       piixTimingReg.AsUShort, 
                       piixOldSlaveTimingReg.AsUChar,
                       piix4OldUdmaControlReg.AsUChar,
                       piix4UdmaTimingReg.AsUChar,
                       oldIoConfigReg.AsUShort
                       ));
      }
  
  #endif // DBG
  
  
  #ifndef PIIX_TIMING_REGISTER_SUPPORT
      status = STATUS_UNSUCCESSFUL;
      goto GetOut;
  #endif 
  
  
          dataMask = 0xffff;
          status = PciIdeXSetBusData (
                       DeviceExtension,
                       &piixTimingReg, 
                       &dataMask,
                       FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, Timing) + 
                           sizeof(piixTimingReg) * 
                           TransferModeSelect->Channel,
                       sizeof (piixTimingReg)
                       );
          if (!NT_SUCCESS(status)) {
              goto GetOut;
          }
  
  
          if (!IS_PIIX(DeviceExtension->DeviceId)) {
  
              dataMask = TransferModeSelect->Channel == 0 ? 0x0f : 0xf0;
              status = PciIdeXSetBusData (
                           DeviceExtension,
                           &piixSlaveTimingReg, 
                           &dataMask,
                           FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, SlaveTiming),
                           sizeof (piixSlaveTimingReg)
                           );
      
              if (!NT_SUCCESS(status)) {
      
                  ASSERT(!"Unable to set pci config data\n");
                  goto GetOut;
              }
          }
          
          if (IS_UDMA_CONTROLLER(DeviceExtension->DeviceId)) {
  
              //
              // UDMA Control Register
              //
              dataMask = TransferModeSelect->Channel == 0 ? 0x03 : 0x0c;
              status = PciIdeXSetBusData (
                           DeviceExtension,
                           &piix4UdmaControlReg, 
                           &dataMask,
                           FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, UdmaControl),
                           sizeof (piix4UdmaControlReg)
                           );
      
              if (!NT_SUCCESS(status)) {
      
                  ASSERT(!"Unable to set pci config data\n");
                  goto GetOut;
              }
              
              //
              // UDMA Timing Register
              //
              dataMask = 0xff;
              status = PciIdeXSetBusData (
                           DeviceExtension,
                           &piix4UdmaTimingReg, 
                           &dataMask,
                           FIELD_OFFSET(PIIX4_PCI_CONFIG_DATA, UdmaTiming) +
                               sizeof(piix4UdmaTimingReg) * 
                               TransferModeSelect->Channel,
                           sizeof (piix4UdmaTimingReg)
                           );
      
              if (!NT_SUCCESS(status)) {
      
                  ASSERT(!"Unable to set pci config data\n");
                  goto GetOut;
              }
          }
          
          if (IS_ICH_(DeviceExtension->DeviceId) || 
              IS_ICH0(DeviceExtension->DeviceId) ||
              IS_ICH2(DeviceExtension->DeviceId)) {
  
              //
              // UDMA Control Register
              //
              dataMask = TransferModeSelect->Channel == 0 ? 0x0403 : 0x040c;
              status = PciIdeXSetBusData (
                           DeviceExtension,
                           &ioConfigReg, 
                           &dataMask,
                           FIELD_OFFSET(ICH_PCI_CONFIG_DATA, IoConfig),
                           sizeof (ioConfigReg)
                           );
      
              if (!NT_SUCCESS(status)) {
      
                  ASSERT(!"Unable to set pci config data\n");
                  goto GetOut;
              }
          }
      }
  
  GetOut:
  
      if (NT_SUCCESS(status)) {
  
          for (i = 0; i < MAX_IDE_DEVICE; i++) {
              TransferModeSelect->DeviceTransferModeSelected[i] = 
                  driveBestXferMode[i];
          }
      }
  
      return status;
  }
  
       
  NTSTATUS
  PiixIdepTransferModeSelect (
      IN PDEVICE_EXTENSION DeviceExtension,
      IN PPCIIDE_TRANSFER_MODE_SELECT TransferModeSelect,
      OUT ULONG DriveBestXferMode[MAX_IDE_DEVICE],
      OUT PPIIX_TIMING_REGISTER PiixTimingReg,
      OUT PPIIX3_SLAVE_TIMING_REGISTER PiixSlaveTimingReg,
      OUT PPIIX4_UDMA_CONTROL_REGISTER Piix4UdmaControlReg,
      OUT PPIIX4_UDMA_TIMING_REGISTER Piix4UdmaTimingReg,
      OUT PICH_IO_CONFIG_REGISTER IoConfigReg
      )
  {
      ULONG i;
      ULONG xferMode;
      ULONG channel;
      NTSTATUS status;
      UCHAR ispClockSetting;
      UCHAR recoveryClockSetting;
      PIIX_TIMING_MODE piixTimingMode;
      PIIX_SPECIAL_TIMING_REGISTER piixSpecialTiming;
  
      ULONG driveBestXferMode[MAX_IDE_DEVICE];
      PIIX_TIMING_REGISTER piixTimingReg;
      PIIX3_SLAVE_TIMING_REGISTER piixSlaveTimingReg;
      PIIX4_UDMA_CONTROL_REGISTER piix4UdmaControlReg;
      PIIX4_UDMA_TIMING_REGISTER piix4UdmaTimingReg;
      ICH_IO_CONFIG_REGISTER ioConfigReg;
  
      ULONG transferModeSupported;
      PULONG transferModeTimingTable;
  
      channel = TransferModeSelect->Channel;
  
      piixTimingReg.AsUShort = 0;
      piixSlaveTimingReg.AsUChar = 0;
  
      transferModeTimingTable=TransferModeSelect->TransferModeTimingTable;
      ASSERT(transferModeTimingTable);
  
      for (i = 0; i < MAX_IDE_DEVICE; i++) {
  
          ULONG enableUdma66 = TransferModeSelect->EnableUDMA66;
  
          driveBestXferMode[i] = 0;
  
          if (TransferModeSelect->DevicePresent[i] == FALSE) {
  
              continue;
          }
  #if 1
          //
          // UDMA transfer mode
          //
          transferModeSupported=TransferModeSelect->DeviceTransferModeSupported[i];
  
          //
          // only upto udma 5 is supported
          //
          transferModeSupported &= 0x1ffff;
  
          //
          // translate drive reported udma settings to drive's best udma mode
          // UDMA_MASK masks out udma mode >2 if cableReady or enableUdma is not set for a
          // controller that supports modes > udma2. enableUdma flag is ignored for Udma100
          // controllers
          //                                                                               
          UDMA_MASK(DeviceExtension->UdmaController, DeviceExtension->CableReady[channel][i],
                    enableUdma66, transferModeSupported);
  
          GetHighestDMATransferMode(transferModeSupported, xferMode);
  
          if (xferMode >= UDMA0) {
  
              driveBestXferMode[i] = 1 << xferMode;
          }
  
          //
          // DMA transfer mode
          //
  
          //
          // Get the highest DMA mode (exclude UDMA)
          //
          transferModeSupported = TransferModeSelect->
                                      DeviceTransferModeSupported[i] & (MWDMA_SUPPORT | SWDMA_SUPPORT);
          GetHighestDMATransferMode(transferModeSupported, xferMode);
  
          //
          // if xfermode is mwdma2 or 1, select mwdma2 , 1 or swdma2 depending on the cycle time
          //
          if (xferMode >= MWDMA1) {
  
              while (xferMode >= SWDMA2) {
                  //
                  // MWDMA0 is not supported
                  //
                  if (xferMode == MWDMA0) {
                      xferMode--;
                      continue;
                  }
                  if (TransferModeSelect->BestMwDmaCycleTime[i] <= transferModeTimingTable[xferMode]) {
                      driveBestXferMode[i] |= (1 << xferMode);
                      break;
                  }
                  xferMode--;
              }
  
          } else if (xferMode == SWDMA2) {
  
              if (TransferModeSelect->BestSwDmaCycleTime[i] <= transferModeTimingTable[xferMode]) {
  
                  driveBestXferMode[i] |= SWDMA_MODE2;
  
              } //else use PIO
  
          }
          //
          // Don't use SWDMA0 and SWDMA1
          // 
  
          //
          // PIO transfer mode
          //
          transferModeSupported=TransferModeSelect->DeviceTransferModeSupported[i];
          GetHighestPIOTransferMode(transferModeSupported, xferMode);
  
          //
          // if PIO2 is the highest PIO mode supported, don't check the
          // bestPIOTiming reported by the device.
          //
          if (xferMode == PIO2) {
  
              driveBestXferMode[i] |= (1 << xferMode);
  
          } else {
              //
              // PIO1 is not supported
              //
              while (xferMode > PIO1) {
  
                  if (TransferModeSelect->BestPioCycleTime[i] <= transferModeTimingTable[xferMode]) {
  
                      driveBestXferMode[i] |= (1 << xferMode);
                      break;
  
                  }
                  xferMode--;
              }
  
              //
              // default to PIO0
              //
              if (xferMode <= PIO1) {
                  driveBestXferMode[i] |= (1 << PIO0);
              }
          }
  
  #endif
      }
      //
      // use the slower mode if we have a old piix and two devices on the channel
      // 
      if (IS_PIIX(DeviceExtension->DeviceId)) {
  
          if (TransferModeSelect->DevicePresent[0] && TransferModeSelect->DevicePresent[1]) {
  
              ULONG mode;
      
              if ((driveBestXferMode[0] & PIO_SUPPORT) <=
                  (driveBestXferMode[1] & PIO_SUPPORT)) {
      
                  mode = driveBestXferMode[0] & PIO_SUPPORT;
      
              } else {
      
                  mode = driveBestXferMode[1] & PIO_SUPPORT;
              }
      
              if ((driveBestXferMode[0] & SWDMA_SUPPORT) <=
                  (driveBestXferMode[1] & SWDMA_SUPPORT)) {
      
                  mode |= driveBestXferMode[0] & SWDMA_SUPPORT;
      
              } else {
      
                  mode |= driveBestXferMode[1] & SWDMA_SUPPORT;
              }
      
              if ((driveBestXferMode[0] & MWDMA_SUPPORT) <=
                  (driveBestXferMode[1] & MWDMA_SUPPORT)) {
      
                  mode |= driveBestXferMode[0] & MWDMA_SUPPORT;
      
              } else {
      
                  mode |= driveBestXferMode[1] & MWDMA_SUPPORT;
              }
      
              if ((driveBestXferMode[0] & UDMA_SUPPORT) <=
                  (driveBestXferMode[1] & UDMA_SUPPORT)) {
      
                  mode |= driveBestXferMode[0] & UDMA_SUPPORT;
      
              } else {
      
                  mode |= driveBestXferMode[1] & UDMA_SUPPORT;
              }
      
              driveBestXferMode[0] = driveBestXferMode[1] = mode;
          }
      }
  
      //
      // translate device ATA timing mode to piix timing mode
      //
      for (i = 0; i < MAX_IDE_DEVICE; i++) {
  
          piixSpecialTiming.AsUChar = 0;
  
          if (TransferModeSelect->DevicePresent[i] == FALSE) {
  
              piixTimingMode = PiixMode_NotPresent;
  
          } else {
  
              //
              // default
              //
              piixTimingMode = PiixMode_Mode0;
  
              if (!(driveBestXferMode[i] & DMA_SUPPORT)) {
      
                  //
                  // pio only device
                  //
      
                  if (driveBestXferMode[i] & PIO_MODE0) {
      
                      piixTimingMode = PiixMode_Mode0;
  
                  } else if (driveBestXferMode[i] & PIO_MODE2) {
  
                      piixTimingMode = PiixMode_Mode2;
  
                      if (TransferModeSelect->IoReadySupported[i]) {
  
                          piixSpecialTiming.AsUChar |= PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(1);
                      }
  
                  } else if (driveBestXferMode[i] & PIO_MODE3) {
  
                      piixTimingMode = PiixMode_Mode3;
  
                  } else if (driveBestXferMode[i] & PIO_MODE4) {
  
                      piixTimingMode = PiixMode_Mode4;
  
                  } else {
  
                      ASSERT(FALSE);
                  }
  
              } else if (driveBestXferMode[i] & SWDMA_MODE2) {
  
                  piixTimingMode = PiixMode_Mode2;
  
                  if (driveBestXferMode[i] & PIO_MODE0) {
  
                      piixSpecialTiming.AsUChar |= PIIX_TIMING_DMA_TIMING_ENABLE(1);
                  }
  
                  if (TransferModeSelect->IoReadySupported[i]) {
  
                      piixSpecialTiming.AsUChar |= PIIX_TIMING_IOREADY_SAMPLE_POINT_ENABLE(1);
                  }
  
              } else if (driveBestXferMode[i] & MWDMA_MODE1) {
      
                  piixTimingMode = PiixMode_Mode3;
  
                  if (driveBestXferMode[i] & (PIO_MODE0 | PIO_MODE2)) {
  
                      piixSpecialTiming.AsUChar |= PIIX_TIMING_DMA_TIMING_ENABLE(1);
                  }
  
              } else if (driveBestXferMode[i] & MWDMA_MODE2) {
      
                  if (driveBestXferMode[i] & PIO_MODE3) {
  
                      piixTimingMode = PiixMode_Mode3;
  
                  } else {
  
                      piixTimingMode = PiixMode_Mode4;
                  }
  
                  if (driveBestXferMode[i] & (PIO_MODE0 | PIO_MODE2)) {
  
                      piixSpecialTiming.AsUChar |= PIIX_TIMING_DMA_TIMING_ENABLE(1);
                  }
              }
  
              if (TransferModeSelect->FixedDisk[i]) {
  
                  piixSpecialTiming.AsUChar |= PIIX_TIMING_PREFETCH_AND_POSTING_ENABLE(1);
              }
          }
  
          piixSpecialTiming.AsUChar |= PiixSpecialTiming[piixTimingMode].AsUChar;
  
          if (i == 0) {
  
              //
              // master device
              //
              piixTimingReg.b.IoReadySamplePoint = PiixIoReadySamplePointClockSetting[piixTimingMode];
              piixTimingReg.b.RecoveryTime = PiixRecoveryTimeClockSetting[piixTimingMode];
  
              piixTimingReg.b.n.Device0SpecialTiming = piixSpecialTiming.AsUChar & 0xf;
  
          } else {
  
              //
              // slave device
              //
              if (channel == 0) {
  
                  piixSlaveTimingReg.b.Channel0IoReadySamplePoint = PiixIoReadySamplePointClockSetting[piixTimingMode];
                  piixSlaveTimingReg.b.Channel0RecoveryTime = PiixRecoveryTimeClockSetting[piixTimingMode];
  
              } else {
  
                  piixSlaveTimingReg.b.Channel1IoReadySamplePoint = PiixIoReadySamplePointClockSetting[piixTimingMode];
                  piixSlaveTimingReg.b.Channel1RecoveryTime = PiixRecoveryTimeClockSetting[piixTimingMode];
              }
  
              piixTimingReg.b.n.Device1SpecialTiming = piixSpecialTiming.AsUChar & 0xf;
          }
      }
  
      if (!IS_PIIX(DeviceExtension->DeviceId)) {
  
          //
          // enable the timing setting for the slave
          //
          piixTimingReg.b.SlaveTimingEnable = 1;        
  
      } else {
  
          piixSlaveTimingReg.AsUChar = 0;
      }
  
      //
      // make sure the channel is enabled
      //
      piixTimingReg.b.ChannelEnable = 1;
  
      //
      // setup up udma
      //
  
      piix4UdmaControlReg.AsUChar = 0;
      piix4UdmaTimingReg.AsUChar = 0;
      ioConfigReg.AsUShort = 0;
      ioConfigReg.b.WriteBufferPingPongEnable = 1;
  
      for (i = 0; i < MAX_IDE_DEVICE; i++) {
  
          if (driveBestXferMode[i] & UDMA_SUPPORT) {
  
              UCHAR udmaTiming;
  
              if (driveBestXferMode[i] & UDMA_MODE5) {
              
                  udmaTiming = ICH2_UDMA_MODE5_TIMING;
                     
              } else if (driveBestXferMode[i] & UDMA_MODE4) {
              
                  udmaTiming = ICH_UDMA_MODE4_TIMING;
                     
              } else if (driveBestXferMode[i] & UDMA_MODE3) {
                                           
                  udmaTiming = ICH_UDMA_MODE3_TIMING;
                                           
              } else if (driveBestXferMode[i] & UDMA_MODE2) {
  
                  udmaTiming = PIIX4_UDMA_MODE2_TIMING;
  
              } else if (driveBestXferMode[i] & UDMA_MODE1) {
  
                  udmaTiming = PIIX4_UDMA_MODE1_TIMING;
  
              } else if (driveBestXferMode[i] & UDMA_MODE0) {
  
                  udmaTiming = PIIX4_UDMA_MODE0_TIMING;
  
              } else {
  
                  ASSERT (!"intelide: Unknown UDMA MODE\n");
  
                  //
                  // we will use udma mode 5
                  //
                  udmaTiming = ICH2_UDMA_MODE5_TIMING;
              }
  
              if (i == 0) {
  
                  if (channel == 0) {
      
                      //
                      // primary master
                      //                                                            
                      piix4UdmaControlReg.b.Channel0Drive0UdmaEnable = 1;
  
                      if (driveBestXferMode[i] & UDMA66_SUPPORT) {
                      
                          ioConfigReg.b.PrimaryMasterBaseClock = 1;
                      }
  
                      if (driveBestXferMode[i] & UDMA100_SUPPORT) {
                      
                          ioConfigReg.b.FastPrimaryMasterBaseClock = 1;
                      }
  
                  } else {
  
                      //
                      // secondary master
                      //                                                            
                      piix4UdmaControlReg.b.Channel1Drive0UdmaEnable = 1;
                      
                      if (driveBestXferMode[i] & UDMA66_SUPPORT) {
                      
                          ioConfigReg.b.SecondaryMasterBaseClock = 1;
                      }
  
                      if (driveBestXferMode[i] & UDMA100_SUPPORT) {
                      
                          ioConfigReg.b.FastSecondaryMasterBaseClock = 1;
                      }
                  }
  
                  piix4UdmaTimingReg.b.Drive0CycleTime = udmaTiming;
  
              } else {
  
                  ASSERT(i==1);
  
                  if (channel == 0) {
      
                      //
                      // primary slave
                      //                                                    
                      piix4UdmaControlReg.b.Channel0Drive1UdmaEnable = 1;
  
                      if (driveBestXferMode[i] & UDMA66_SUPPORT) {
                      
                          ioConfigReg.b.PrimarySlaveBaseClock = 1;
                      }
  
                      if (driveBestXferMode[i] & UDMA100_SUPPORT) {
                      
                          ioConfigReg.b.FastPrimarySlaveBaseClock = 1;
                      }
                                                 
                  } else {
  
                      //
                      // secondary slave
                      //                                                    
                      piix4UdmaControlReg.b.Channel1Drive1UdmaEnable = 1;
                      
                      if (driveBestXferMode[i] & UDMA66_SUPPORT) {
                      
                          ioConfigReg.b.SecondarySlaveBaseClock = 1;
                      }
                      if (driveBestXferMode[i] & UDMA100_SUPPORT) {
                      
                          ioConfigReg.b.FastSecondarySlaveBaseClock = 1;
                      }
                  }
  
                  piix4UdmaTimingReg.b.Drive1CycleTime = udmaTiming;
              }
  
              //
              // if the drive support UDMA, use UDMA
              // turn off other DMA mode
              //
              driveBestXferMode[i] &= ~(MWDMA_SUPPORT | SWDMA_SUPPORT);
          }
      }
  
      //
      // setup the return data
      //
      for (i = 0; i < MAX_IDE_DEVICE; i++) {
          DriveBestXferMode[i] = driveBestXferMode[i];
      }
  
      *PiixTimingReg       = piixTimingReg;
      *PiixSlaveTimingReg  = piixSlaveTimingReg;
      *Piix4UdmaControlReg = piix4UdmaControlReg;
      *Piix4UdmaTimingReg  = piix4UdmaTimingReg;
      *IoConfigReg         = ioConfigReg;
  
      return STATUS_SUCCESS;
  }
  
  