reactos操作系统实现(107)

IssueIdentify函数主要是发送IDENTIFY命令给一个ATAPI设备,并且获取这个设备相关信息,比如磁头的个数。

#001  BOOLEAN

#002  NTAPI

#003  IssueIdentify(

#004      IN PVOID HwDeviceExtension,

#005      IN ULONG DeviceNumber,

#006      IN ULONG Channel,

#007      IN UCHAR Command

#008      )

#009 

#010  /*++

#011 

#012  Routine Description:

#013 

#014      Issue IDENTIFY command to a device.

#015 

#016  Arguments:

#017 

#018      HwDeviceExtension - HBA miniport driver's adapter data storage

#019      DeviceNumber - Indicates which device.

#020      Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.

#021 

#022  Return Value:

#023 

#024      TRUE if all goes well.

#025 

#026  --*/

#027 

#028  {

 

获取IDE控制器的IO基地址。

#029      PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;

#030      PIDE_REGISTERS_1     baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel] ;

#031      PIDE_REGISTERS_2     baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];

#032      ULONG                waitCount = 20000;

#033      ULONG                i,j;

#034      UCHAR                statusByte;

#035      UCHAR                signatureLow,

#036                           signatureHigh;

#037 

#038      //

#039      // Select device 0 or 1.

#040      //

#041 

 

选择设备0,或者设备1

#042      ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,

#043                             (UCHAR)((DeviceNumber << 4) | 0xA0));

#044 

#045      //

#046      // Check that the status register makes sense.

#047      //

#048 

 

获取选择设备的状态。

#049      GetBaseStatus(baseIoAddress1, statusByte);

#050 

 

如果发送命令不是IDENTIFY,就不进入处理。

#051      if (Command == IDE_COMMAND_IDENTIFY) {

#052 

#053          //

#054          // Mask status byte ERROR bits.

#055          //

#056 

 

获取错误状态位。

#057          statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);

#058 

#059          DebugPrint((1,

#060                      "IssueIdentify: Checking for IDE. Status (%x)/n",

#061                      statusByte));

#062 

#063          //

#064          // Check if register value is reasonable.

#065          //

#066 

 

如果IDE控制器不空闲,就不复位它。

#067          if (statusByte != IDE_STATUS_IDLE) {

#068 

#069              //

#070              // Reset the controller.

#071              //

#072 

 

复位IDE控制器。

#073              AtapiSoftReset(baseIoAddress1,DeviceNumber);

#074 

 

重新选择控制器。

#075              ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,

#076                                     (UCHAR)((DeviceNumber << 4) | 0xA0));

#077 

 

获取执行命令完成。

#078              WaitOnBusy(baseIoAddress2,statusByte);

#079 

 

读取ATAPI标识,如果还是ATAPI就返回出错。

#080              signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);

#081              signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);

#082 

#083              if (signatureLow == 0x14 && signatureHigh == 0xEB) {

#084 

#085                  //

#086                  // Device is Atapi.

#087                  //

#088 

#089                  return FALSE;

#090              }

#091 

 

发送IDE_DC_RESET_CONTROLLER命令。

#092              DebugPrint((1,

#093                          "IssueIdentify: Resetting controller./n"));

#094 

#095              ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );

#096              ScsiPortStallExecution(500 * 1000);

#097              ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);

#098 

#099 

#100              // We really should wait up to 31 seconds

#101              // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!

#102              // (30 seconds for device 1)

 

IDE控制器准备好。

#103              do {

#104 

#105                  //

#106                  // Wait for Busy to drop.

#107                  //

#108 

#109                  ScsiPortStallExecution(100);

#110                  GetStatus(baseIoAddress2, statusByte);

#111 

#112              } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);

#113 

#114              ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,

#115                                     (UCHAR)((DeviceNumber << 4) | 0xA0));

#116 

#117              //

#118              // Another check for signature, to deal with one model Atapi that doesn't assert signature after

#119              // a soft reset.

#120              //

#121 

 

如果读取IDE标识,还是ATAPI就返回出错。

#122              signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);

#123              signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);

#124 

#125              if (signatureLow == 0x14 && signatureHigh == 0xEB) {

#126 

#127                  //

#128                  // Device is Atapi.

#129                  //

#130 

#131                  return FALSE;

#132              }

#133 

#134              statusByte &= ~IDE_STATUS_INDEX;

#135 

 

如果读取不成功,还是忙等,那么说明这个控制器有问题返回。

#136              if (statusByte != IDE_STATUS_IDLE) {

#137 

#138                  //

#139                  // Give up on this.

#140                  //

#141 

#142                  return FALSE;

#143              }

#144 

#145          }

#146 

#147      } else {

#148 

#149          DebugPrint((1,

#150                      "IssueIdentify: Checking for ATAPI. Status (%x)/n",

#151                      statusByte));

#152 

#153      }

#154 

#155      //

#156      // Load CylinderHigh and CylinderLow with number bytes to transfer.

#157      //

#158 

#159      ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8));

#160      ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,  (0x200 & 0xFF));

#161 

 

 

#162      for (j = 0; j < 2; j++) {

#163 

#164          //

#165          // Send IDENTIFY command.

#166          //

#167 

#168          WaitOnBusy(baseIoAddress2,statusByte);

#169 

 

发送一个IDENTIFY命令。

#170          ScsiPortWritePortUchar(&baseIoAddress1->Command, Command);

#171 

#172          //

#173          // Wait for DRQ.

#174          //

#175 

 

DRQ状态出现。

#176          for (i = 0; i < 4; i++) {

#177 

#178              WaitForDrq(baseIoAddress2, statusByte);

#179 

 

如果出现DRQ状态,说明回应数据已经准备好。

#180              if (statusByte & IDE_STATUS_DRQ) {

#181 

#182                  //

#183                  // Read status to acknowledge any interrupts generated.

#184                  //

#185 

#186                  GetBaseStatus(baseIoAddress1, statusByte);

#187 

#188                  //

#189                  // One last check for Atapi.

#190                  //

#191 

#192 

 

如果读取还是ATAPI标识,说明出错。

#193                  signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);

#194                  signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);

#195 

#196                  if (signatureLow == 0x14 && signatureHigh == 0xEB) {

#197 

#198                      //

#199                      // Device is Atapi.

#200                      //

#201 

#202                      return FALSE;

#203                  }

#204 

#205                  break;

#206              }

#207 

 

如果读取还是ATAPI标识,说明出错。

#208              if (Command == IDE_COMMAND_IDENTIFY) {

#209 

#210                  //

#211                  // Check the signature. If DRQ didn't come up it's likely Atapi.

#212                  //

#213 

#214                  signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);

#215                  signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);

#216 

#217                  if (signatureLow == 0x14 && signatureHigh == 0xEB) {

#218 

#219                      //

#220                      // Device is Atapi.

#221                      //

#222 

#223                      return FALSE;

#224                  }

#225              }

#226 

#227              WaitOnBusy(baseIoAddress2,statusByte);

#228          }

#229 

 

进行第二次尝试复位。

#230          if (i == 4 && j == 0) {

#231 

#232              //

#233              // Device didn't respond correctly. It will be given one more chances.

#234              //

#235 

#236              DebugPrint((1,

#237                          "IssueIdentify: DRQ never asserted (%x). Error reg (%x)/n",

#238                          statusByte,

#239                           ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1)));

#240 

#241              AtapiSoftReset(baseIoAddress1,DeviceNumber);

#242 

#243              GetStatus(baseIoAddress2,statusByte);

#244 

#245              DebugPrint((1,

#246                         "IssueIdentify: Status after soft reset (%x)/n",

#247                         statusByte));

#248 

#249          } else {

#250 

#251              break;

#252 

#253          }

#254      }

#255 

#256      //

#257      // Check for error on really stupid master devices that assert random

#258      // patterns of bits in the status register at the slave address.

#259      //

#260 

 

如果状态出错,说明不认识这个命令。

#261      if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {

#262          return FALSE;

#263      }

#264 

#265      DebugPrint((1,

#266                 "IssueIdentify: Status before read words %x/n",

#267                 statusByte));

#268 

#269      //

#270      // Suck out 256 words. After waiting for one model that asserts busy

#271      // after receiving the Packet Identify command.

#272      //

#273 

 

等准备好数据。

#274      WaitOnBusy(baseIoAddress2,statusByte);

#275 

#276      if (!(statusByte & IDE_STATUS_DRQ)) {

#277          return FALSE;

#278      }

#279 

 

IDEIDE_COMMAND_IDENTIFY命令返回的512个字节。

#280      ReadBuffer(baseIoAddress1,

#281                 (PUSHORT)&deviceExtension->FullIdentifyData,

#282                 256);

#283 

#284      //

#285      // Check out a few capabilities / limitations of the device.

#286      //

#287 

 

检查IDE控制器兼容性。

#288      if (deviceExtension->FullIdentifyData.SpecialFunctionsEnabled & 1) {

#289 

#290          //

#291          // Determine if this drive supports the MSN functions.

#292          //

#293 

 

查看是否支持可移动特性。

#294          DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d/n",

#295                      Channel * 2 + DeviceNumber,

#296                      deviceExtension->FullIdentifyData.SpecialFunctionsEnabled));

#297 

#298 

#299          deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE;

#300      }

#301 

 

设置最大块传送参数。

#302      if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {

#303 

#304          //

#305          // Determine max. block transfer for this device.

#306          //

#307 

#308          deviceExtension->MaximumBlockXfer[(Channel * 2) + DeviceNumber] =

#309              (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF);

#310      }

#311 

#312      ScsiPortMoveMemory(&deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber],&deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2));

#313 

#314      if (deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0x20 &&

#315          Command != IDE_COMMAND_IDENTIFY) {

#316 

#317          //

#318          // This device interrupts with the assertion of DRQ after receiving

#319          // Atapi Packet Command

#320          //

#321 

#322          deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_INT_DRQ;

#323  

#324          DebugPrint((2,

#325                      "IssueIdentify: Device interrupts on assertion of DRQ./n"));

#326 

#327      } else {

#328 

#329          DebugPrint((2,

#330                      "IssueIdentify: Device does not interrupt on assertion of DRQ./n"));

#331      }

 

判断这个是否磁带设备。

#332 

#333      if (((deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0xF00) == 0x100) &&

#334          Command != IDE_COMMAND_IDENTIFY) {

#335 

#336          //

#337          // This is a tape.

#338          //

#339 

 

这是一个TAPE设备。

#340          deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_TAPE_DEVICE;

#341 

#342          DebugPrint((2,

#343                      "IssueIdentify: Device is a tape drive./n"));

#344 

#345      } else {

#346 

#347          DebugPrint((2,

#348                      "IssueIdentify: Device is not a tape drive./n"));

#349      }

#350 

#351      //

#352      // Work around for some IDE and one model Atapi that will present more than

#353      // 256 bytes for the Identify data.

#354      //

#355 

#356      WaitOnBusy(baseIoAddress2,statusByte);

#357 

 

读取超过256个字节IDE传送的数据。

#358      for (i = 0; i < 0x10000; i++) {

#359 

#360          GetStatus(baseIoAddress2,statusByte);

#361 

#362          if (statusByte & IDE_STATUS_DRQ) {

#363 

#364              //

#365              // Suck out any remaining bytes and throw away.

#366              //

#367 

#368              ScsiPortReadPortUshort(&baseIoAddress1->Data);

#369 

#370          } else {

#371 

#372              break;

#373 

#374          }

#375      }

#376 

#377      DebugPrint((3,

#378                 "IssueIdentify: Status after read words (%x)/n",

#379                 statusByte));

#380 

#381      return TRUE;

#382 

#383  } // end IssueIdentify()

你可能感兴趣的:(IO,command,J#,ide,UP,360)