📄 atapipci.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include "atamain.h"
#include "atapipci.h"
#include <ceddk.h>
#undef ZONE_INIT
#define ZONE_INIT 1
//BOOL g_fControllerInitialized = FALSE;
//CController g_ControllerTable[4];
//CPort g_PortTable[4];
LONG CPCIDisk::m_lDeviceCount = 0;
static TCHAR *g_szPCICDRomDisk = TEXT("CDROM Drive");
static TCHAR *g_szPCIHardDisk = TEXT("Hard Disk");
CController *g_ControllerTable=NULL;
CPort *g_PortTable=NULL;
DWORD g_dwControllerIndex=0;
//
// The following table specifies the ports to be checked when searching for
// an IDE controller. A zero entry terminates the search.
//
CONST ULONG g_AdapterAddresses[5] = {0xBD000000, 0x170, 0x0F0, 0x070, 0};
//
// The following table specifies interrupt levels corresponding to the
// port addresses in the previous table.
//
CONST ULONG g_InterruptLevels[5] = {14, 15, 11, 10, 0};
/*****************************************************************************************************/
// CPCIDisk Class
/*****************************************************************************************************/
CPCIDisk::~CPCIDisk()
{
FreeDMABuffers();
if (!InterlockedDecrement( &m_lDeviceCount)) {
}
DEBUGMSG( ZONE_INIT | ZONE_PCI, (TEXT("ATAPIPCI:~CPCIDisk DeviceCount = %ld\r\n"), m_lDeviceCount));
}
void CPCIDisk::FreeDMABuffers()
{
if (m_pPRD) {
FreePhysMem( m_pPRD);
m_pPRDPhys = NULL;
m_pPRD = NULL;
}
if (m_pPhysList) {
// Free the fixed pages. The variable ones should already be free
for (DWORD i = 0; i < MIN_PHYS_PAGES; i++) {
FreePhysMem (m_pPhysList[i].pVirtualAddress);
}
VirtualFree( m_pPhysList, UserKInfo[KINX_PAGESIZE], MEM_DECOMMIT);
m_pPhysList = NULL;
}
if (m_pSGCopy) {
VirtualFree( m_pSGCopy, UserKInfo[KINX_PAGESIZE], MEM_DECOMMIT);
m_pSGCopy = NULL;
}
if (m_pPFNs) {
VirtualFree( m_pPFNs, UserKInfo[KINX_PAGESIZE], MEM_DECOMMIT);
m_pSGCopy = NULL;
}
VirtualFree (m_pStartMemory, 0, MEM_RELEASE);
m_pStartMemory = NULL;
m_dwPhysCount = 0;
m_dwSGCount = 0;
}
void CPCIDisk::CopyDiskInfoFromPort()
{
// Set up the memory address
ASSERT( m_pPort->m_dwRegBase != 0);
m_pATAReg = (PBYTE)m_pPort->m_dwRegBase;
m_pATARegAlt = (PBYTE)m_pPort->m_dwRegAlt;
ASSERT( m_pPort->m_dwBMR != 0);
m_pBMCommand = (LPBYTE)m_pPort->m_dwBMR;
}
BOOL CPCIDisk::WaitForInterrupt(DWORD dwTimeOut)
{
BYTE bStatus;
BOOL fRet = TRUE;
DWORD dwRet;
dwRet = WaitForSingleObject( m_pPort->m_hIRQEvent, dwTimeOut);
if (dwRet == WAIT_TIMEOUT) {
fRet = FALSE;
} else
if (dwRet != WAIT_OBJECT_0) {
if (!WaitForDisc( WAIT_TYPE_DRQ, dwTimeOut, 10)) {
fRet = FALSE;
}
}
bStatus = GetBaseStatus();// Ack interrupt!!!!!
if (bStatus & ATA_STATUS_ERROR) {
bStatus = GetError();
fRet = FALSE;
}
InterruptDone(m_pPort->m_dwSysIntr);
return fRet;
}
void CPCIDisk::EnableInterrupt()
{
GetBaseStatus();// Ack interrupt!!!!!
InterruptDone(m_pPort->m_dwSysIntr);
}
BOOL CPCIDisk::Init(HKEY hActiveKey)
{
BOOL bRet = FALSE;
// Retrieve DeviceID Number from Registry (0,1,2,3,4,5,6,7).
// A Device is specified by three Bits:
// Bit 0 - Specify Device on the chanel/port. Master(0)/Slave(1)
// Bit 1 - Specify Port/Channel: 0- Primary, 1 - Secondary Port
// Bit 3 - Specify Ata Controller/Adapter.
//
if (!AtaGetRegistryValue(m_hDevKey, TEXT("DeviceId"), &m_dwDeviceId)) {
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI:Init: Missing Device Number in Registry \r\n")));
goto ExitFail;
}
// Verify that the DeviceID is in range
if ((m_dwDeviceId <0) || (m_dwDeviceId >= MAX_ATA_DEVICES))
{
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI:Init: Wrong DeviceID in the Registry DeviceId=% \r\n"),m_dwDeviceId));
goto ExitFail;
}
if (DoesDeviceAlreadyExist()) {
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI:AtaInitDevice: Device Initialized already!\r\n")));
goto ExitFail;
}
//
// Now can configure Port if not configure yet.
//
m_dwPort = (m_dwDeviceId>>1) & 1;
m_dwDevice = m_dwDeviceId & 1;
DEBUGMSG( ZONE_INIT, (TEXT("Port configuration Port=%ld Device=%ld\r\n"), m_dwPort, m_dwDevice));
if (!ConfigPort()) {
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI:ConfigPort failed DeviceId=% \r\n"),m_dwDeviceId));
goto ExitFail;
}
m_f16Bit = TRUE; // PCI Is 16 access
m_fInterruptSupported = TRUE;
bRet = CDisk::Init(hActiveKey);
if (IsCDRomDevice()) {
m_szDiskName = g_szPCICDRomDisk;
} else {
m_szDiskName = g_szPCIHardDisk;
}
m_pStartMemory = (LPBYTE)VirtualAlloc (NULL, 0x10000, MEM_RESERVE, PAGE_READWRITE);
if (!m_pStartMemory)
bRet = FALSE;
ExitFail:
return bRet;
}
//--------------------------------------------------------------------------
//
// ConfigPort: Open the device key specified by the active key
//
// Input: dwPort - Port Number
//
// Return: CPort *- ok.
// NULL - error.
//
// Notes: Configure Controller Port. Each ATA Controller has two IO Ports.
// This function is called for each device, but initialized only once.
// The following procedure is used to configure IO Port:
// 1.) Check data received from PCI Config space
// 2.) Check Registry for required keys
// 3.) Use Default values if no value is found before.
//
//--------------------------------------------------------------------------
BOOL CPCIDisk::ConfigPort()
{
g_ControllerTable=new CController[4];
g_PortTable=new CPort[4];
CController *pController= &g_ControllerTable[m_dwDeviceId>>1];
CPort *pPort = &g_PortTable[m_dwDeviceId>>1];
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI: ATAConfig Device:%x\r\n"),m_dwDeviceId));
// Configure Device only, if the Port is already configured!!!
if (pPort->m_hIRQEvent) {
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI: ConfigPort - Port is already configured pPort=%08X\r\n"), pPort));
m_pPort = pPort;
m_dwDeviceFlags |= DFLAGS_DEVICE_INITIALIZED;
CopyDiskInfoFromPort();
return TRUE;
}
DEBUGMSG( ZONE_INIT, (TEXT("ATAPIPCI: ConfigPort - Configuring pPort=%08X\r\n"), pPort));
//
// Update Base Status Register.
// Check Registry if the Base Register was not found in the PCI Config Check Registry;
// Otrewise take default value.
//
// DWORD pPhyAdd = 0;
/* if (!AtaGetRegistryValue(m_hDevKey, REG_VALUE_IOBASEADDRESS, &pPhyAdd)) {
if (pController->m_dwRegBase) {
pPort->m_dwRegBase = pController->m_dwRegBase ;
} else {
pPort->m_dwRegBase = g_AdapterAddresses[(m_dwDeviceId>>1) & 1]; // Othrewise take default value
DEBUGMSG( ZONE_INIT | ZONE_PCI, (TEXT(" ATAPIPCI: Using predefined IOBaseAddress = %08X\r\n"), pPort->m_dwRegBase));
}
// return FALSE;
}
*/ //
// Update Alternative Status Register
//
/* if (pController->m_dwRegAlt) {
pPort->m_dwRegAlt = pController->m_dwRegAlt;
} else {
pPort->m_dwRegAlt = pPort->m_dwRegBase +0x204;
}
*/
//IDE's CS0 -> CS0(0x11800000)
//IDE's CS1 -> CS1(0x12000000)
//IDE's A2 -> A3
//IDE's A1 -> A2
//IDE's A0 -> A1
/*
======================================================================================
| | -CS0 | -CS1 | HA2 | HA1 | HA0 | RD | WR | Offset|
|ADDR.----+-----+-----+----+----+----------------------------------------------------|
| | CS0 | CS1 | A3 | A2 | A1 | Command Block | |
|----+----+-----+-----+----+-----+---------------------------------------------------|
| 1F0 | 0 | 1 | 0 | 0 | 0 |Data Reg. |Data Reg. | 0x000 |
| 1F1 | 0 | 1 | 0 | 0 | 1 |Error Reg. |Features Reg.| 0x002 |
| 1F2 | 0 | 1 | 0 | 1 | 0 |SEC CNT Reg. |SEC CNT Reg. | 0x004 |
| 1F3 | 0 | 1 | 0 | 1 | 1 |SEC NUM Reg. |SEC NUM Reg. | 0x006 |
| 1F4 | 0 | 1 | 1 | 0 | 0 |CYL LOW Reg. |CYL LOW Reg. | 0x008 |
| 1F5 | 0 | 1 | 1 | 0 | 1 |CYL HIGH Reg.|CYL HIGH Reg.| 0x00A |
| 1F6 | 0 | 1 | 1 | 1 | 0 |Drv/Head Reg.|Drv/Head Reg.| 0x00C |
| 1F7 | 0 | 1 | 1 | 1 | 1 |Status Reg. |Status Reg. | 0x00E |
|------------------------------------------------------------------------------------|
| | | | | | | Contorl Block | |
|----+----+----+------+----+-----+-----------------------------|-------------|-------|
| 3F6 | 1 | 0 | 1 | 1 | 0 |AltStatus Reg |Dev Ctrl Reg | 0x00C |
| 3F7 | 1 | 0 | 1 | 1 | 1 |Drv Addr Reg. | --- | 0x00E |
=====================================================================================|
*/
DWORD pPhyAdd = 0;
PVOID pVirtual=NULL;
if (!AtaGetRegistryValue(m_hDevKey, REG_VALUE_BASEADD, &pPhyAdd)) {
return FALSE;
}
DWORD IoSpace = 0;
PHYSICAL_ADDRESS ioPhysicalBase = {0, 0};
ioPhysicalBase.LowPart = pPhyAdd;
TransBusAddrToVirtual(PCIBus, 0, ioPhysicalBase, ATA_REG_LENGTH, &IoSpace, &pVirtual);
pPort->m_dwRegBase = (ULONG)pVirtual;
if (!AtaGetRegistryValue(m_hDevKey, REG_VALUE_ALTADD, &pPhyAdd)) {
return FALSE;
}
ioPhysicalBase.LowPart = pPhyAdd;
TransBusAddrToVirtual(PCIBus, 0, ioPhysicalBase, ATA_REG_LENGTH, &IoSpace, &pVirtual);
pPort->m_dwRegAlt = ((ULONG)pVirtual+0xC);
//
// Create an Interrupt Event. This event will be used by threads waiting
// for an interrupt from Ata Device.
//
if ((pPort->m_hIRQEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
return FALSE;
//
// Check DMA Bus Master Controller
//
if (!AtaGetRegistryValue(m_hDevKey, REG_VALUE_BMR, &pPort->m_dwBMR)) {
pPort->m_dwBMR = pController->m_dwBMR ;
pPort->m_dwBMRStatic = pController->m_dwBMRStatic;
}
/* if (!AtaGetRegistryValue(m_hDevKey, REG_VALUE_INTERRUPT, &(pPort->m_dwIrq))) {
if (pController->m_dwIrq)
{
pPort->m_dwIrq = pController->m_dwIrq;
} else {
pPort->m_dwIrq = g_InterruptLevels[(m_dwDeviceId>>1) & 1];
DEBUGMSG( ZONE_INIT | ZONE_PCI, (TEXT(" ATAPIPCI: Using predefined Interrupt = %08X\r\n"), pPort->m_dwIrq));
}
}
*/
if (!pController->m_dwSysIntr) {
if (!AtaGetRegistryValue(m_hDevKey, REG_VALUE_SYSINTR, &(pController->m_dwSysIntr))) {
//
// Update an Interrupt Level
//
DWORD dwReturned;
if (!KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
(LPVOID)&pPort->m_dwIrq,
sizeof(DWORD),
(LPVOID)&pController->m_dwSysIntr,
sizeof(DWORD),
&dwReturned))
{
#if defined(x86)
pController->m_dwSysIntr = pPort->m_dwIrq+SYSINTR_FIRMWARE;
#else
return FALSE;
#endif
} else {
DEBUGMSG( ZONE_INIT | ZONE_PCI, (TEXT("ATAPIPCI: Mapped IRQ %ld to SYSINTR %ld\r\n"), pController->m_dwSysIntr, pPort->m_dwIrq));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -