现在的位置: 首页 > 综合 > 正文

reactos操作系统实现(109)

2013年10月05日 ⁄ 综合 ⁄ 共 15045字 ⁄ 字号 评论关闭

AtapiInterrupt函数是实现ATAPI的中断功能,主要根据SRB来判断是读取数据还是写入数据,然后对IDE设备读取或写入数据,还需要处理很多出错的情况。具体实现代码如下:

#001  BOOLEAN

#002  NTAPI

#003  AtapiInterrupt(

#004      IN PVOID
HwDeviceExtension

#005      )

#006 

#007  /*++

#008 

#009  Routine Description:

#010 

#011      This is the interrupt
service routine for ATAPI IDE miniport driver.

#012 

#013  Arguments:

#014 

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

#016 

#017  Return Value:

#018 

#019      TRUE if expecting an
interrupt.

#020 

#021  --*/

#022 

#023  {

 

获取IDE的扩展对象结构。

#024      PHW_DEVICE_EXTENSION
deviceExtension = HwDeviceExtension;

 

获取当前SRB数据。

#025      PSCSI_REQUEST_BLOCK
srb              =
deviceExtension->CurrentSrb;

#026      PATAPI_REGISTERS_1
baseIoAddress1;

#027      PATAPI_REGISTERS_2
baseIoAddress2;

 

每次读取256个双字节,也就是512个字节。

#028      ULONG wordCount = 0,
wordsThisInterrupt = 256;

#029      ULONG status;

#030      ULONG i;

#031      UCHAR
statusByte,interruptReason;

#032      BOOLEAN atapiDev =
FALSE;

#033 

 

获取IDE的基地址。

#034      if (srb) {

 

如果有SRB,说明直接从SRB里读取基地址就行了。

#035          baseIoAddress1
=   
(PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[srb->TargetId
>> 1];

#036          baseIoAddress2
=   
(PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId
>> 1];

#037      } else {

 

否则就需要PPC的情况,或者使用一个默认的基地址。

#038          DebugPrint((2,

#039                     
"AtapiInterrupt: CurrentSrb is NULL/n"));

#040          //

#041          // We can only
support one ATAPI IDE master on Carolina, so find

#042          // the base address
that is non NULL and clear its interrupt before

#043          // returning.

#044          //

#045 

#046  #ifdef _PPC_

#047 

#048          if
((PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0] != NULL) {

#049             baseIoAddress1 =
(PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0];

#050          } else {

#051             baseIoAddress1 =
(PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1];

#052          }

#053 

#054         
GetBaseStatus(baseIoAddress1, statusByte);

#055  #else

#056 

 

使用一个默认的基地址

#057          if
(deviceExtension->InterruptMode == LevelSensitive) {

#058              if
(deviceExtension->BaseIoAddress1[0] != NULL) {

#059                
baseIoAddress1 =
(PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0];

#060                
GetBaseStatus(baseIoAddress1, statusByte);

#061              }

#062              if
(deviceExtension->BaseIoAddress1[1] != NULL) {

#063                
baseIoAddress1 =
(PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1];

#064                 GetBaseStatus(baseIoAddress1,
statusByte);

#065              }

#066          }

#067  #endif

 

如果没有基地址,这个驱动程序不能访问IDE控制器。

#068          return FALSE;

#069      }

#070 

 

如果驱动程序不能接收中断,就直接返回去。

#071      if
(!(deviceExtension->ExpectingInterrupt)) {

#072 

#073          DebugPrint((3,

#074                     
"AtapiInterrupt: Unexpected interrupt./n"));

#075          return FALSE;

#076      }

#077 

#078      //

#079      // Clear interrupt by
reading status.

#080      //

#081 

 

读取当前状态。

#082      GetBaseStatus(baseIoAddress1,
statusByte);

#083 

#084      DebugPrint((3,

#085                 
"AtapiInterrupt: Entered with status (%x)/n",

#086                 
statusByte));

#087 

#088 

 

如果IDE的状态为忙状态。

#089      if (statusByte &
IDE_STATUS_BUSY) {

 

如果设备需要采用轮询的方式,就直接返回。

#090          if
(deviceExtension->DriverMustPoll) {

#091 

#092              //

#093              // Crashdump is
polling and we got caught with busy asserted.

#094              // Just go away,
and we will be polled again shortly.

#095              //

#096 

#097              DebugPrint((3,

#098                         
"AtapiInterrupt: Hit BUSY while polling during
crashdump./n"));

#099 

#100              return TRUE;

#101          }

#102 

#103          //

#104          // Ensure BUSY is
non-asserted.

#105          //

#106 

 

如果查询10次,还是忙状态,说明IDE还是在忙,没有办法响应,调用函数ScsiPortNotification来设置回调函数。

#107          for (i = 0; i <
10; i++) {

#108 

#109             
GetBaseStatus(baseIoAddress1, statusByte);

#110              if (!(statusByte
& IDE_STATUS_BUSY)) {

#111                  break;

#112              }

#113             
ScsiPortStallExecution(5000);

#114          }

#115 

#116          if (i == 10) {

#117 

#118              DebugPrint((2,

#119                         
"AtapiInterrupt: BUSY on entry. Status %x, Base IO %x/n",

#120                         
statusByte,

#121                         
baseIoAddress1));

#122 

#123             
ScsiPortNotification(RequestTimerCall,

#124                                  
HwDeviceExtension,

#125                                   AtapiCallBack,

#126                                  
500);

#127              return TRUE;

#128          }

#129      }

#130 

#131 

#132      //

#133      // Check for error
conditions.

#134      //

#135 

 

如果当前IDE设备的状态为出错,就设置这个SRB请求完成,并且是出错返回。

#136      if (statusByte &
IDE_STATUS_ERROR) {

#137 

#138          if (srb->Cdb[0]
!= SCSIOP_REQUEST_SENSE) {

#139 

#140              //

#141              // Fail this
request.

#142              //

#143 

#144              status =
SRB_STATUS_ERROR;

#145              goto
CompleteRequest;

#146          }

#147      }

#148 

#149      //

#150      // check reason for this
interrupt.

#151      //

#152 

 

如果没有出错,也没有忙状态,判断这个中断的原因是什么。

#153      if
(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {

 

如果ATAPI设备中断,就读取中断的原因,并设置传送的字节数为512个字节。

#154 

#155          interruptReason =
(ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason) & 0x3);

#156          atapiDev = TRUE;

#157          wordsThisInterrupt =
256;

#158 

#159      } else {

#160 

 

如果是DRQ的方式传送,就进入下面处理。

#161          if (statusByte &
IDE_STATUS_DRQ) {

#162 

 

多块传送数据。

#163              if
(deviceExtension->MaximumBlockXfer[srb->TargetId]) {

#164                 
wordsThisInterrupt = 256 * deviceExtension->MaximumBlockXfer[srb->TargetId];

#165 

#166             
}

#167 

 

读取数据进来。

#168             
if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {

#169 

#170                 
interruptReason =  0x2;

#171 

 

传送数据出去。

#172              } else if
(srb->SrbFlags & SRB_FLAGS_DATA_OUT) {

#173                 
interruptReason = 0x0;

#174 

#175              } else {

 

错误请求中断。

#176                  status =
SRB_STATUS_ERROR;

#177                  goto
CompleteRequest;

#178              }

#179 

#180          } else if
(statusByte & IDE_STATUS_BUSY) {

#181 

#182              return FALSE;

#183 

#184          } else {

#185 

 

如果需要补充写字节,就进入下面处理。

#186              if
(deviceExtension->WordsLeft) {

#187 

#188                  ULONG k;

#189 

#190                  //

#191                  // Funky
behaviour seen with PCI IDE (not all, just one).

#192                  // The ISR
hits with DRQ low, but comes up later.

#193                  //

#194 

#195                  for (k = 0;
k < 5000; k++) {

#196                     
GetStatus(baseIoAddress2,statusByte);

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

#198                         
ScsiPortStallExecution(100);

#199                      } else {

#200                         
break;

#201                      }

#202                  }

#203 

#204                  if (k ==
5000) {

#205 

#206                      //

#207                      // reset
the controller.

#208                      //

#209 

#210                     
DebugPrint((1,

#211                                  "AtapiInterrupt: Resetting due to DRQ
not up. Status %x, Base IO %x/n",

#212                                 
statusByte,

#213                                 
baseIoAddress1));

#214 

#215                     
AtapiResetController(HwDeviceExtension,srb->PathId);

#216                      return
TRUE;

#217                  } else {

#218 

#219                     
interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 :
0x0;

#220                  }

#221 

#222              } else {

#223 

 

下面获取媒介的状态。

#224                  //

#225                  // Command
complete - verify, write, or the SMART enable/disable.

#226                  //

#227                  // Also
get_media_status

#228 

#229                 
interruptReason = 0x3;

#230              }

#231          }

#232      }

#233 

 

根据中断原因进行处理。

#234      if (interruptReason ==
0x1 && (statusByte & IDE_STATUS_DRQ)) {

#235 

 

中断原因是写数据到IDE设备。

#236          //

#237          // Write the packet.

#238          //

#239 

#240          DebugPrint((2,

#241                     
"AtapiInterrupt: Writing Atapi packet./n"));

#242 

#243          //

#244          // Send CDB to
device.

#245          //

#246 

 

CDB数据发送给设备。这里的WriteBuffer,其实是调用函数ScsiPortWritePortBufferUshort,它的作用就是把缓冲区里的数据发送到HBA总线上。

#247          WriteBuffer(baseIoAddress1,

#248                     
(PUSHORT)srb->Cdb,

#249                      6);

#250 

#251          return TRUE;

#252 

#253      } else if
(interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) {

#254 

#255          //

#256          // Write the data.

#257          //

#258 

 

确认是否ATAPI设备。

#259          if
(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {

#260 

#261              //

#262              // Pick up bytes
to transfer and convert to words.

#263              //

#264 

 

ATAPI设备里读取要传送的字节数,把字节转换为字的个数。

#265              wordCount =

#266                 
ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);

#267 

#268              wordCount |=

#269                 
ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8;

#270 

#271              //

#272              // Covert bytes
to words.

#273              //

#274 

#275              wordCount
>>= 1;

#276 

#277              if (wordCount !=
deviceExtension->WordsLeft) {

#278                  DebugPrint((3,

#279                            
"AtapiInterrupt: %d words requested; %d words xferred/n",

#280                            
deviceExtension->WordsLeft,

#281                            
wordCount));

#282              }

#283 

 

如果要传送的字个数大于剩余的个数,那么就只传送剩余的个数。

#284              //

#285              // Verify this
makes sense.

#286              //

#287 

#288              if (wordCount
> deviceExtension->WordsLeft) {

#289                  wordCount =
deviceExtension->WordsLeft;

#290              }

#291 

#292          } else {

#293 

#294              //

#295              // IDE path.
Check if words left is at least 256.

#296              //

#297 

 

判断是否剩余字个数小于256个字,如果是小于,就只传送剩余个数,否则就传送256个字。

#298              if
(deviceExtension->WordsLeft < wordsThisInterrupt) {

#299 

#300                 //

#301                 // Transfer
only words requested.

#302                 //

#303 

#304                 wordCount =
deviceExtension->WordsLeft;

#305 

#306              } else {

#307 

#308                 //

#309                 // Transfer
next block.

#310                 //

#311 

#312                 wordCount =
wordsThisInterrupt;

#313              }

#314          }

#315 

#316          //

#317          // Ensure that this
is a write command.

#318          //

#319 

 

检查它是写的命令。

#320          if (srb->SrbFlags
& SRB_FLAGS_DATA_OUT) {

#321 

#322             DebugPrint((3,

#323                       
"AtapiInterrupt: Write interrupt/n"));

#324 

 

等到IDE设备不忙。

#325            
WaitOnBusy(baseIoAddress2,statusByte);

#326 

 

判断是否写到第三个基地址。

#327             if (atapiDev ||
!deviceExtension->DWordIO) {

#328 

#329                
WriteBuffer(baseIoAddress1,

#330                            
deviceExtension->DataBuffer,

#331                            
wordCount);

#332             } else {

#333 

#334                
PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1;

#335 

#336                
WriteBuffer2(address3,

#337                            
(PULONG)(deviceExtension->DataBuffer),

#338                             wordCount / 2);

#339             }

#340          } else {

#341 

 

如果不是写的命令,就提示出错返回。

#342              DebugPrint((1,

#343                         
"AtapiInterrupt: Int reason %x, but srb is for a write %x./n",

#344                         
interruptReason,

#345                         
srb));

#346 

#347              //

#348              // Fail this
request.

#349              //

#350 

#351              status =
SRB_STATUS_ERROR;

#352              goto
CompleteRequest;

#353          }

#354 

#355  

#356          //

#357          // Advance data
buffer pointer and bytes left.

#358          //

#359 

 

调整已经传送的缓冲区字个数,以便下一次传送。

#360         
deviceExtension->DataBuffer += wordCount;

#361         
deviceExtension->WordsLeft -= wordCount;

#362 

#363          return TRUE;

#364 

#365      } else if
(interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {

#366 

#367 

 

这是读取数据命令。

#368          if
(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {

#369 

#370              //

#371              // Pick up bytes to transfer and convert
to words.

#372              //

#373 

 

读取IDE设备要传送的字节数,并转换为字的个数。

#374              wordCount =

#375                 
ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);

#376 

#377              wordCount |=

#378                 
ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8;

#379 

#380              //

#381              // Covert bytes
to words.

#382              //

#383 

#384              wordCount
>>= 1;

#385 

 

请求的个数不等于IDE设备要传送的字节数,就提示。

#386              if (wordCount !=
deviceExtension->WordsLeft) {

#387                 
DebugPrint((3,

#388                            
"AtapiInterrupt: %d words requested; %d words xferred/n",

#389                            
deviceExtension->WordsLeft,

#390                             wordCount));

#391              }

#392 

#393              //

#394              // Verify this
makes sense.

#395              //

#396 

 

如果取得最小的值来传送。

#397              if (wordCount
> deviceExtension->WordsLeft) {

#398                  wordCount = deviceExtension->WordsLeft;

#399              }

#400 

#401          } else {

#402 

#403              //

#404              // Check if
words left is at least 256.

#405              //

#406 

 

如果只是传送剩余的字节,就设置传送剩余字节,否则就是传送512个字节。

#407              if (deviceExtension->WordsLeft <
wordsThisInterrupt) {

#408 

#409                 //

#410                 // Transfer
only words requested.

#411                 //

#412 

#413                 wordCount =
deviceExtension->WordsLeft;

#414 

#415              } else {

#416 

#417                 //

#418                 // Transfer
next block.

#419                 //

#420 

#421                 wordCount =
wordsThisInterrupt;

#422              }

#423          }

#424 

#425          //

#426          // Ensure that this
is a read command.

#427         
//

#428 

 

检查这个命令是读取的命令。

#429         
if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {

#430 

#431             DebugPrint((3,

#432                       
"AtapiInterrupt: Read interrupt/n"));

#433 

 

等待IDE设备空闲。

#434            
WaitOnBusy(baseIoAddress2,statusByte);

#435 

 

读取数据到缓冲区。

#436             if (atapiDev ||
!deviceExtension->DWordIO) {

#437                
ReadBuffer(baseIoAddress1,

#438                          
deviceExtension->DataBuffer,

#439                           wordCount);

#440 

#441             } else {

 

使用4字节的方式读取。

#442                
PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1;

#443 

#444                
ReadBuffer2(address3,

#445                           
(PULONG)(deviceExtension->DataBuffer),

#446                           
wordCount / 2);

#447             }

#448          } else {

#449 

 

处理这个IDE设备请示失败。

#450              DebugPrint((1,

#451                         
"AtapiInterrupt: Int reason %x, but srb is for a read %x./n",

#452                         
interruptReason,

#453                         
srb));

#454 

#455              //

#456              // Fail this
request.

#457              //

#458 

#459              status =
SRB_STATUS_ERROR;

#460              goto CompleteRequest;

#461          }

#462 

#463          //

#464          // Translate ATAPI
data back to SCSI data if needed

#465          //

#466 

#467          if (srb->Cdb[0]
== ATAPI_MODE_SENSE &&

#468             
deviceExtension->DeviceFlags[srb->TargetId] &
DFLAGS_ATAPI_DEVICE) {

#469 

#470              //

#471              //convert and
adjust the wordCount

#472              //

#473 

#474              wordCount -=
Atapi2Scsi(srb, (char *)deviceExtension->DataBuffer,

#475                               
       wordCount << 1);

#476          }

#477          //

#478          // Advance data
buffer pointer and bytes left.

#479          //

#480 

 

调整已经传送的字节。

#481         
deviceExtension->DataBuffer += wordCount;

#482         
deviceExtension->WordsLeft -= wordCount;

#483 

#484          //

#485          // Check for read
command complete.

抱歉!评论已关闭.