reactos操作系统实现(105)

前端之家收集整理的这篇文章主要介绍了reactos操作系统实现(105)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

AtapiFindController函数主要用来查找ATAPI控制器,也就是IDE控制器。同时收集IDE控制器相关配置信息,比如磁盘的访问方式。

#001 ULONG

#002 NTAPI

#003 AtapiFindController(

#004 IN PVOID HwDeviceExtension,

#005 IN PVOID Context,

#006 IN PVOID BusInformation,

#007 IN PCHAR ArgumentString,

#008 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,

#009 OUT PBOOLEAN Again

#010 )

#011 /*++

#012

#013 Routine Description:

#014

#015 This function is called by the OS-specific port driver after

#016 the necessary storage has been allocated,to gather information

#017 about the adapter's configuration.

#018

#019 Arguments:

#020

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

#022 Context - Address of adapter count

#023 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.

#024 ConfigInfo - Configuration information structure describing HBA

#025 Again - Indicates search for adapters to continue

#026

#027 Return Value:

#028

#029 ULONG

#030

#031 --*/

#032

#033 {

#034 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;

#035 PULONG adapterCount = (PULONG)Context;

#036 PUCHAR ioSpace = NULL;

#037 ULONG i;

#038 ULONG irq;

#039 ULONG portBase;

#040 ULONG retryCount;

#041 PCI_SLOT_NUMBER slotData;

#042 PPCI_COMMON_CONFIG pciData;

#043 ULONG pciBuffer;

#044 BOOLEAN atapiOnly;

#045 UCHAR statusByte;

#046 BOOLEAN preConfig = FALSE;

#047 //

#048 // The following table specifies the ports to be checked when searching for

#049 // an IDE controller. A zero entry terminates the search.

#050 //

#051

IDE控制器的端口。

#052 CONST ULONG AdapterAddresses[5] = {0x1F0,0x170,0x1e8,0x168,0};

#053

#054 //

#055 // The following table specifies interrupt levels corresponding to the

#056 // port addresses in the prevIoUs table.

#057 //

#058

IDE控制器的中断号。

#059 CONST ULONG InterruptLevels[5] = {14,15,11,10,0};

#060

#061 if (!deviceExtension) {

#062 return SP_RETURN_ERROR;

#063 }

#064

#065 //

#066 // Check to see if this is a special configuration environment.

#067 //

#068

设置端口和中断都为0

#069 portBase = irq = 0;

#070 if (ArgumentString) {

#071

分析字符串中的中断号,并转换为数字表示。

#072 irq = AtapiParseArgumentString(ArgumentString,"Interrupt");

#073 if (irq ) {

#074

#075 //

#076 // Both parameters must be present to proceed

#077 //

#078

处理IDE控制器的基地址。

#079 portBase = AtapiParseArgumentString(ArgumentString,"BaseAddress");

如果端口为0,表示是非法的数据。

#080 if (!portBase) {

#081

#082 //

#083 // Try a default search for the part.

#084 //

#085

#086 irq = 0;

#087 }

#088 }

#089 }

#090

#091

#092

#093 //

#094 // Scan though the adapter address looking for adapters.

#095 //

如果访问范围不为空,说明这个PCI空间有设备。

#096 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {

获取这个PCI空间的IO空间。

#097 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,

#098 ConfigInfo->AdapterInterfaceType,

#099 ConfigInfo->SystemIoBusNumber,

#100 (*ConfigInfo->AccessRanges)[0].RangeStart,

#101 (*ConfigInfo->AccessRanges)[0].RangeLength,

#102 (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));

#103 *Again = FALSE;

#104 //

#105 // Since we have pre-configured information we only need to go through this loop once

#106 //

#107 preConfig = TRUE;

#108 portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);

#109

#110 }

#111

#112

#113

循环地查找四个IDE控制器。

#114 while (AdapterAddresses[*adapterCount] != 0) {

#115

#116 retryCount = 4;

#117

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

#119

#120 //

#121 // Zero device fields to ensure that if earlier devices were found,

#122 // but not claimed,the fields are cleared.

#123 //

#124

清空设备标志。

#125 deviceExtension->DeviceFlags[i] &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE);

#126 }

#127

#128 //

#129 // Get the system physical address for this IO range.

#130 //

#131

#132

#133 //

#134 // Check if configInfo has the default information

#135 // if not,we go and find ourselves

#136 //

#137

获取相应IDEIO空间。

#138 if (preConfig == FALSE) {

#139

#140 if (portBase) {

#141 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,

#142 ConfigInfo->AdapterInterfaceType,

#143 ConfigInfo->SystemIoBusNumber,

#144 ScsiPortConvertUlongToPhysicalAddress(portBase),

#145 8,

#146 TRUE);

#147 } else {

#148 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,

#149 ConfigInfo->AdapterInterfaceType,

#150 ConfigInfo->SystemIoBusNumber,

#151 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]),

#152 8,

#153 TRUE);

#154 }

#155

#156 }// ConfigInfo check

#157 //

#158 // Update the adapter count.

#159 //

#160

处理下一个IDE控制器。

#161 (*adapterCount)++;

#162

#163 //

#164 // Check if ioSpace accessible.

#165 //

#166

如果没有读取IO空间成功,就尝试读取下一个。

#167 if (!ioSpace) {

#168 continue;

#169 }

#170

#171 retryIdentifier:

#172

#173 //

#174 // Select master.

#175 //

#176

处理主控制器。

选择IDE主控制器命令。

#177 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect,0xA0);

#178

#179 //

#180 // Check if card at this address.

#181 //

#182

如果这里是一个IDE控制器,往柱面寄存器写入一个字节。

#183 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow,0xAA);

#184

#185 //

#186 // Check if indentifier can be read back.

#187 //

#188

再读取柱面寄存器的字节,如果不等于写入的,说明有问题。然后进入循环读取命令端口是否写入成功,如果尝试多次都不成功,说明这个不是IDE控制器。

#189 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {

#190

#191 DebugPrint((2,

#192 "AtapiFindController: Identifier read back from Master (%x)/n",

#193 statusByte));

#194

#195 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2)ioSpace)->AlternateStatus);

#196

#197 if (statusByte & IDE_STATUS_BUSY) {

#198

#199 i = 0;

#200

#201 //

#202 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that

#203 // warm boots don't clear.

#204 //

#205

#206 do {

#207 ScsiPortStallExecution(1000);

#208 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1)ioSpace)->Command);

#209 DebugPrint((3,

#210 "AtapiFindController: First access to status %x/n",

#211 statusByte));

#212 } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10);

#213

#214 if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) {

#215 goto retryIdentifier;

#216 }

#217 }

#218

选从IDE控制器。

#219 //

#220 // Select slave.

#221 //

#222

#223 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect,0xB0);

#224

#225 //

#226 // See if slave is present.

#227 //

#228

如果这里是一个IDE控制器,往柱面寄存器写入一个字节。

#229 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow,0xAA);

#230

再读取柱面寄存器的字节,如果不等于写入的,说明有问题。然后进入循环读取命令端口是否写入成功,如果尝试多次都不成功,说明这个不是IDE控制器。

#231 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {

#232

#233 DebugPrint((2,

#234 "AtapiFindController: Identifier read back from Slave (%x)/n",

#235 statusByte));

#236

#237 //

#238 //

#239 // No controller at this base address.

#240 //

#241

#242 ScsiPortFreeDeviceBase(HwDeviceExtension,

#243 ioSpace);

#244

#245 continue;

#246 }

#247 }

#248

保存IDE控制器的IO地址。

#249 //

#250 // Record base IO address.

#251 //

#252

#253 deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace);

#254

#255 //

#256 // Fill in the access array information only if default params are not in there.

#257 //

#258 if (preConfig == FALSE) {

#259

#260 //

#261 // An adapter has been found request another call,only if we didn't get preconfigured info.

#262 //

#263 *Again = TRUE;

#264

#265 if (portBase) {

#266 (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase);

#267 } else {

#268 (*ConfigInfo->AccessRanges)[0].RangeStart =

#269 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]);

#270 }

#271

#272 (*ConfigInfo->AccessRanges)[0].RangeLength = 8;

#273 (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;

#274

保存这个IDE控制器的中断号。

#275 //

#276 // Indicate the interrupt level corresponding to this IO range.

#277 //

#278

#279 if (irq) {

#280 ConfigInfo->BusInterruptLevel = irq;

#281 } else {

#282 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1];

#283 }

#284

#285 if (ConfigInfo->AdapterInterfaceType == MicroChannel) {

#286 ConfigInfo->InterruptMode = LevelSensitive;

#287 } else {

#288 ConfigInfo->InterruptMode = Latched;

#289 }

#290 }

#291 //

#292 // Get the system physical address for the second IO range.

#293 //

#294

#295

#296 if (portBase) {

#297 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,

#298 ConfigInfo->AdapterInterfaceType,

#299 ConfigInfo->SystemIoBusNumber,

#300 ScsiPortConvertUlongToPhysicalAddress(portBase + 0x206),

#301 1,

#302 TRUE);

#303 } else {

#304 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,

#305 ConfigInfo->AdapterInterfaceType,

#306 ConfigInfo->SystemIoBusNumber,

#307 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206),

#308 1,

#309 TRUE);

#310 }

#311

#312 deviceExtension->BaseIoAddress2[0] = (PIDE_REGISTERS_2)(ioSpace);

#313

#314 deviceExtension->NumberChannels = 1;

#315

#316 ConfigInfo->NumberOfBuses = 1;

#317 ConfigInfo->MaximumNumberOfTargets = 2;

#318

#319 //

#320 // Indicate maximum transfer length is 64k.

#321 //

#322

#323 ConfigInfo->MaximumTransferLength = 0x10000;

#324

#325 DebugPrint((1,

#326 "AtapiFindController: Found IDE at %x/n",

#327 deviceExtension->BaseIoAddress1[0]));

#328

#329

#330 //

#331 // For Daytona,the atdisk driver gets the first shot at the

#332 // primary and secondary controllers.

#333 //

#334

#335 if (preConfig == FALSE) {

#336

#337

#338 if (*adapterCount - 1 < 2) {

#339

#340 //

#341 // Determine whether this driver is being initialized by the

#342 // system or as a crash dump driver.

#343 //

#344

#345 if (ArgumentString) {

#346

#347 if (AtapiParseArgumentString(ArgumentString,"dump") == 1) {

#348 DebugPrint((3,

#349 "AtapiFindController: Crash dump/n"));

#350 atapiOnly = FALSE;

#351 deviceExtension->DriverMustPoll = TRUE;

#352 } else {

#353 DebugPrint((3,

#354 "AtapiFindController: Atapi Only/n"));

#355 atapiOnly = TRUE;

#356 deviceExtension->DriverMustPoll = FALSE;

#357 }

#358 } else {

#359

#360 DebugPrint((3,

#361 "AtapiFindController: Atapi Only/n"));

#362 atapiOnly = TRUE;

#363 deviceExtension->DriverMustPoll = FALSE;

#364 }

#365

#366 } else {

#367 atapiOnly = FALSE;

#368 }

#369

#370 //

#371 // If this is a PCI machine,pick up all devices.

#372 //

#373

如果是PCI的机器里,就保存所有IDE设备。

#374

#375 pciData = (PPCI_COMMON_CONFIG)&pciBuffer;

#376

#377 slotData.u.bits.DeviceNumber = 0;

#378 slotData.u.bits.FunctionNumber = 0;

#379

#380 if (ScsiPortGetBusData(deviceExtension,

#381 PCIConfiguration,

#382 0, // BusNumber

#383 slotData.u.AsULONG,

#384 pciData,

#385 sizeof(ULONG))) {

#386

#387 atapiOnly = FALSE;

#388

#389 //

#390 // Wait on doing this,until a reliable method

#391 // of determining support is found.

#392 //

#393

#394 #if 0

#395 deviceExtension->DWordio = TRUE;

#396 #endif

#397

#398 } else {

#399 deviceExtension->DWordio = FALSE;

#400 }

#401

#402 } else {

#403

#404 atapiOnly = FALSE;

#405 deviceExtension->DriverMustPoll = FALSE;

#406

#407 }// preConfig check

#408

#409 //

#410 // Save the Interrupe Mode for later use

#411 //

#412 deviceExtension->InterruptMode = ConfigInfo->InterruptMode;

#413

#414 //

#415 // Search for devices on this controller.

#416 //

#417

查找IDE控制器上所有设备。

#418 if (FindDevices(HwDeviceExtension,

#419 atapiOnly,

#420 0)) {

#421

#422 //

#423 // Claim primary or secondary ATA IO range.

#424 //

#425

#426 if (portBase) {

#427 switch (portBase) {

如果配置这个IO,说明它是主控制器。

#428 case 0x170:

#429 ConfigInfo->AtdiskSecondaryClaimed = TRUE;

#430 deviceExtension->PrimaryAddress = FALSE;

#431 break;

如果配置这个IO,说明它是从控制器。

#432 case 0x1f0:

#433 ConfigInfo->AtdiskPrimaryClaimed = TRUE;

#434 deviceExtension->PrimaryAddress = TRUE;

#435 break;

#436 default:

#437 break;

#438 }

#439 } else {

#440 if (*adapterCount == 1) {

#441 ConfigInfo->AtdiskPrimaryClaimed = TRUE;

#442 deviceExtension->PrimaryAddress = TRUE;

#443 } else if (*adapterCount == 2) {

#444 ConfigInfo->AtdiskSecondaryClaimed = TRUE;

#445 deviceExtension->PrimaryAddress = FALSE;

#446 }

#447 }

#448

这里返回成功找到的IDE控制器和IDE设备。

#449 return(SP_RETURN_FOUND);

#450 }

#451 }

#452

下面是返回什么都没有找到的结果。

#453 //

#454 // The entire table has been searched and no adapters have been found.

#455 // There is no need to call again and the device base can now be freed.

#456 // Clear the adapter count for the next bus.

#457 //

#458

#459 *Again = FALSE;

#460 *(adapterCount) = 0;

#461

#462 return(SP_RETURN_NOT_FOUND);

#463

#464 } // end AtapiFindController()

HBA的全称为Host Bus Adapter,即主机总线适配器。

a、总线适配器是个什么东西呢?

我们首先要了解一下主机的结构,一台计算机内部多半由两条总线串在起来(当然实际情况会有不同,这里只讨论常见的,简单的情况),一条总线叫系统总线,一条叫I/O总线。系统总线上接了cpuMEmorycache什么的,I/O总线上接的就是外围设备,现如今最常见的就是PCI总线了。这两条总线之间用桥接的芯片或者说电路连接起来。举个形象的例子,就好比一个城市里,有两条主干道,一条属于行政区,一条属于商业区,中间有个环岛,将两条主干道连接到了一起,系统总线就好比行政区里的主干道,而I/O总线就好比商业区的主干道。系统总线和I/O总线的带宽的单位都是以Gbyte来记,但是显而易见的是,行政区的主干道和商业区的主干道相比的话,前者肯定更“核心”,更宽,更顺畅,设计的要求也高。

我们知道,在向公仆部门要求服务的时候,是要有一些接口的部门和程序的,而桥接芯片的作用就是连接和协调两条总线的工作的。

虽然I/O总线的速度和系统总线的带宽相比要低很多,但是好歹也是以G来计量的,而我们知道外围设备的速度,往往只有几百兆,甚至几十k而已,怎么协调工作呢?好比卖煎饼果子摊子不能直接戳到城市主干道上,怎么办?好办,在主干道边上开个2000平米的小吃城,把摊子都收进去好了。那么主机总线适配器的作用也就是这个,我们就是要把外设组织起来,连接到I/O总线上去!HBA就是指HostI/O BUS直接的一个适配器,也好比一个水管工常说的“双通”。

b、常见的HBA有哪些呢?

比如显卡,网卡,scsi卡,1394卡等等。我要拿出来说的就是FCHBAATA&IDE。我们通常说的什么EmulexLP9002,什么QlogicQLA2340都是FCHBA卡,就是将Fibre Channel的设备和IO总线连接起来的适配器。ATA也是一种适配器技术,我们PC主板上的ATA接口,就是一个磁盘适配器的对外接口,要强调的就是,ATA说的是适配器技术,IDE是说得存储外设技术,比如我们可以说IDE硬盘,IDE光驱,说ATA接口,但是说IDE接口,ATA硬盘就不时那么合适了,虽然很多情况下,大家都习惯把他们混在一起说。

描述HBA的时候,有几个主要的规范要说一下

> 一个承上,就是说,HBAIOBUS怎么连,我们经常说的PCI接口卡,就是指这个HBA卡是要插在PCI BUS上的PCI slot上的,但是现在的计算机上,不仅仅只有PCI总线而已,大家碰到的时候留意。

>一个启下,就是说HBA要和外设怎么连,这样的规范就很多了。

>再说HBA本身,比如带宽,比如运行机制(protocol),独立处理能力等等

Tips:有时候我们看到的一块卡,看到的实际是一个物理的卡,有的时候实际上是多个Adapter,好比一家机构,挂多个牌子,有的时候,一块卡有两条通道,好比一家公司,有两套人马。

猜你在找的React相关文章