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
读IDE的IDE_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() (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |