|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
pccardc.c
Abstract:
This module contains the C code to set up PcCard (pcmcia, cardbus) configuration data.
Author:
Neil Sandlin (neilsa) 16-Dec-1998 (DetectIRQMap, ToggleIRQLine were copied from win9x)
Revision History:
--*/
#include "hwdetect.h"
#include "pccard.h"
#include <string.h>
extern UCHAR DisablePccardIrqScan; extern BOOLEAN SystemHas8259; extern BOOLEAN SystemHas8253;
CARDBUS_BRIDGE_DEVTYPE CBTable[] = { {0x11101013, DEVTYPE_CL_PD6832}, {0x11121013, DEVTYPE_CL_PD6834}, {0x11111013, DEVTYPE_CL_PD6833}, {0xAC12104C, DEVTYPE_TI_PCI1130}, {0xAC15104C, DEVTYPE_TI_PCI1131}, {0xAC13104C, DEVTYPE_TI_PCI1031}, {0,0}};
FPFWCONFIGURATION_COMPONENT_DATA ControllerList = NULL;
#define LEGACY_BASE_LIST_SIZE 10
USHORT LegacyBaseList[LEGACY_BASE_LIST_SIZE] = {0}; USHORT LegacyBaseListCount = 0;
VOID SetPcCardConfigurationData( PPCCARD_INFORMATION PcCardInfo ) /*++
Routine Description:
This routine creates a structure containing the result of the irq detection, and links it onto our running list. This list eventually will show up in the registry under hardware descriptions.
Arguments:
PcCardInfo - Structure containing the results of detection
Returns:
None.
--*/ { FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry; static FPFWCONFIGURATION_COMPONENT_DATA PreviousEntry = NULL; FPFWCONFIGURATION_COMPONENT Component; FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList; CHAR Identifier[32]; FPCHAR IdentifierString; USHORT Length; CM_PCCARD_DEVICE_DATA far *PcCardData; CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap ( sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE); if (!ControllerList) { ControllerList = CurrentEntry; } Component = &CurrentEntry->ComponentEntry; Component->Class = ControllerClass; Component->Type = OtherController;
strcpy (Identifier, "PcCardController"); Length = strlen(Identifier) + 1; IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE); _fstrcpy(IdentifierString, Identifier);
Component->IdentifierLength = Length; Component->Identifier = IdentifierString; Length = sizeof(HWRESOURCE_DESCRIPTOR_LIST) + sizeof(CM_PCCARD_DEVICE_DATA); DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap( Length, TRUE); CurrentEntry->ConfigurationData = DescriptorList; Component->ConfigurationDataLength = Length; DescriptorList->Count = 1; DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA; DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_PCCARD_DEVICE_DATA); PcCardData = (CM_PCCARD_DEVICE_DATA far *)(DescriptorList + 1); PcCardData->Flags = PcCardInfo->Flags; PcCardData->ErrorCode = PcCardInfo->ErrorCode; PcCardData->DeviceId = PcCardInfo->DeviceId; PcCardData->LegacyBaseAddress = (ULONG) PcCardInfo->IoBase;
if (PcCardInfo->Flags & PCCARD_DEVICE_PCI) { PcCardData->BusData = PcCardInfo->PciCfg1.u.bits.BusNumber | PcCardInfo->PciCfg1.u.bits.DeviceNumber << 8 | PcCardInfo->PciCfg1.u.bits.FunctionNumber << 16; } _fmemcpy(PcCardData->IRQMap, PcCardInfo->abIRQMap, 16); if (PreviousEntry) { PreviousEntry->Sibling = CurrentEntry; } PreviousEntry = CurrentEntry; }
BOOLEAN IsOnLegacyBaseList( USHORT IoBase ) /*++
Routine Description:
This routine runs our list of legacy base addresses to see if we have looked at the address before.
Arguments:
IoBase = base address to map
Returns:
TRUE if the base address is already on the list
--*/ { USHORT i;
for (i = 0; i<LegacyBaseListCount; i++) { if (IoBase == LegacyBaseList[i]) { return TRUE; } } return FALSE; }
BOOLEAN SetLegacyBaseList( USHORT IoBase ) /*++
Routine Description:
This routine remembers the legacy base addresses that we have looked at so far so we don't keep mapping the same address.
NOTE: We are using a DUMB mechanism that only builds the list in a fixed array. We could write some generic code which creates a linked list, but since the heap routines in ntdetect are also dumb, it makes it not possible to free the list. It's just not worth it. Arguments:
IoBase = base address to map
Returns:
TRUE if the base address is unique to this point FALSE if the base address already exists on the list
--*/ { if (IsOnLegacyBaseList(IoBase)) { return FALSE; }
if (LegacyBaseListCount < LEGACY_BASE_LIST_SIZE) { LegacyBaseList[LegacyBaseListCount++] = IoBase; } // note, we return true even if we overflow the list
return TRUE; }
VOID MapPcCardController( PPCCARD_INFORMATION PcCardInfo ) /*++
Routine Description:
This routine is the entry for doing ISA IRQ detection for PcCard controllers.
Arguments:
PcCardInfo - Structure defining the device to run detection on
Returns:
None.
--*/ { USHORT wDetected; USHORT i;
PcCardInfo->ErrorCode = 0; for (i=0; i<16; i++) { PcCardInfo->abIRQMap[i]=0; } if (!PcCardInfo->IoBase) { PcCardInfo->Flags |= PCCARD_MAP_ERROR; PcCardInfo->ErrorCode = PCCARD_NO_LEGACY_BASE; } else if (!SetLegacyBaseList(PcCardInfo->IoBase)) { PcCardInfo->Flags |= PCCARD_MAP_ERROR; PcCardInfo->ErrorCode = PCCARD_DUP_LEGACY_BASE; } if (!(PcCardInfo->Flags & PCCARD_MAP_ERROR)) { PcCardInfo->wValidIRQs = PCCARD_POSSIBLE_IRQS; #if DBG
BlPrint("Going to detect...\n"); #endif
//
// Do the IRQ detection
//
wDetected = DetectIRQMap(PcCardInfo); #if DBG
BlPrint("Detect IRQ Map returns %x on iobase %x\n", wDetected, PcCardInfo->IoBase); #endif
if (!wDetected) { PcCardInfo->ErrorCode = PCCARD_MAP_ZERO; } } #if DBG
if (PcCardInfo->Flags & PCCARD_MAP_ERROR) { BlPrint("Error mapping device, code=%x\n", PcCardInfo->ErrorCode); } #endif
//
// Report the results
//
SetPcCardConfigurationData(PcCardInfo); }
VOID LookForPciCardBusBridges( USHORT BusStart, USHORT BusEnd, ) /*++
Routine Description:
This routine is the entry for doing ISA IRQ detection for PCI-based cardbus controllers.
Arguments:
Bus = PCI Bus number to scan
Returns:
None.
--*/ { PCCARD_INFORMATION PcCardInfo = {0}; USHORT Device, Function; UCHAR HeaderType; UCHAR SecBus, SubBus; USHORT VendorId; USHORT DeviceId; ULONG LegacyBaseAddress; USHORT i; USHORT Bus;
#if DBG
BlPrint("LookForPciCardBusBridges %x-%x\n", BusStart, BusEnd); #endif
for (Bus = BusStart; Bus <= BusEnd; Bus++) {
PcCardInfo.PciCfg1.u.AsULONG = 0; PcCardInfo.PciCfg1.u.bits.BusNumber = Bus; PcCardInfo.PciCfg1.u.bits.Enable = TRUE; for (Device = 0; Device < PCI_MAX_DEVICES; Device++) { PcCardInfo.PciCfg1.u.bits.DeviceNumber = Device;
for (Function = 0; Function < PCI_MAX_FUNCTION; Function++) { PcCardInfo.PciCfg1.u.bits.FunctionNumber = Function; VendorId = 0xffff; GetPciConfigSpace(&PcCardInfo, CFGSPACE_VENDOR_ID, &VendorId, sizeof(VendorId)); if ((VendorId == 0xffff) || (VendorId == 0)) { if (Function == 0) { break; } else { continue; } }
GetPciConfigSpace(&PcCardInfo, CFGSPACE_DEVICE_ID, &DeviceId, sizeof(DeviceId)); GetPciConfigSpace(&PcCardInfo, CFGSPACE_HEADER_TYPE, &HeaderType, sizeof(HeaderType)); switch(HeaderType & 0x7f) { case PCI_CARDBUS_BRIDGE_TYPE: #if DBG
BlPrint("%x.%x.%x : DeviceID = %lx (CardBus Bridge)\n", Bus, Device, Function, DeviceId); #endif
PcCardInfo.DeviceId = (ULONG) (VendorId << 16) | DeviceId; PcCardInfo.Flags = PCCARD_DEVICE_PCI; //
// See if this is a special cased controller
//
PcCardInfo.bDevType = DEVTYPE_GENERIC_CARDBUS; i = 0; while (CBTable[i].DeviceId != 0) { if (DeviceId == CBTable[i].DeviceId) { PcCardInfo.bDevType = CBTable[i].bDevType; break; } i++; } GetPciConfigSpace(&PcCardInfo, CFGSPACE_LEGACY_MODE_BASE_ADDR, &LegacyBaseAddress, 4); PcCardInfo.IoBase = (USHORT) (LegacyBaseAddress & ~1); MapPcCardController(&PcCardInfo); break;
case PCI_BRIDGE_TYPE: #if DBG
BlPrint("%x.%x.%x : DeviceID = %lx (Pci-Pci Bridge)\n", Bus, Device, Function, DeviceId); #endif
GetPciConfigSpace(&PcCardInfo, CFGSPACE_SECONDARY_BUS, &SecBus, sizeof(SecBus)); GetPciConfigSpace(&PcCardInfo, CFGSPACE_SUBORDINATE_BUS, &SubBus, sizeof(SubBus)); if ((SecBus <= Bus) || (SubBus <= Bus) || (SubBus < SecBus)) { break; }
//
// Be conservative on stack space, only look one level deep
//
if (Bus > 0) { break; } LookForPciCardBusBridges(SecBus, SubBus); break; } } } } }
VOID LookForPcicControllers( VOID ) /*++
Routine Description:
This routine is the entry for doing ISA IRQ detection for PCIC controllers.
Arguments:
None.
Returns:
None.
--*/ { PCCARD_INFORMATION PcCardInfo = {0}; USHORT IoBase; UCHAR id;
for (IoBase = 0x3e0; IoBase < 0x3e6; IoBase+=2) { if (IsOnLegacyBaseList(IoBase)) { continue; } PcCardInfo.Flags = 0; PcCardInfo.IoBase = IoBase; PcCardInfo.bDevType = DEVTYPE_GENERIC_PCIC; id = PcicReadSocket(&PcCardInfo, EXCAREG_IDREV); switch (id) { case PCIC_REVISION: case PCIC_REVISION2: case PCIC_REVISION3:
#if DBG
BlPrint("Pcic Controller at base %x, rev(%x)\n", IoBase, id); #endif
MapPcCardController(&PcCardInfo); break; #if DBG
default: BlPrint("Not mapping base %x, return is (%x)\n", IoBase, id); #endif
} } }
FPFWCONFIGURATION_COMPONENT_DATA GetPcCardInformation( VOID ) /*++
Routine Description:
This routine is the entry for doing ISA IRQ detection for PcCard controllers.
Arguments:
None.
Returns:
A pointer to a pccard component structure, if IRQ's were properly detected. Otherwise a NULL pointer is returned.
--*/ { PCCARD_INFORMATION PcCardInfo = {0}; UCHAR ErrorCode = 0;
//
// Check for things which would prevent us from attempting
// the irq detection
//
if (DisablePccardIrqScan == 1) { ErrorCode = PCCARD_SCAN_DISABLED; } else if (!SystemHas8259) { ErrorCode = PCCARD_NO_PIC; } else if (!SystemHas8253) { ErrorCode = PCCARD_NO_TIMER; }
//
// If things look ok so far, do the detection
//
if (!ErrorCode) { #if DBG
BlPrint("press any key to continue...\n"); while ( !HwGetKey() ) ; // wait until key pressed to continue
clrscrn(); BlPrint("Looking for PcCard Controllers...\n"); #endif
//
// Look first for cardbus
//
LookForPciCardBusBridges(0,0); //
// Now check for regular pcic devices
//
LookForPcicControllers(); #if DBG
BlPrint("press any key to continue...\n"); while ( !HwGetKey() ) ; // wait until key pressed to continue
#endif
if (!ControllerList) { ErrorCode = PCCARD_NO_CONTROLLERS; } }
if (ErrorCode) { //
// Something when wrong, so write a single entry to
// allow someone to see what the error was
//
PcCardInfo.Flags |= PCCARD_MAP_ERROR; PcCardInfo.ErrorCode = ErrorCode; SetPcCardConfigurationData(&PcCardInfo); }
return ControllerList; }
USHORT DetectIRQMap( PPCCARD_INFORMATION pa ) /*++
Routine Description:
This routine detects the IRQ mapping of the specified cardbus controller. Note that the controller is in PCIC mode.
Arguments:
pa -> ADAPTER structure
Returns:
returns detected IRQ bit mask
--*/ { USHORT wRealIRQMask = 0; USHORT wData; UCHAR bData;
BOOLEAN fTINMIBug = FALSE;
UCHAR i; USHORT wIRQMask, wRealIRQ, w;
if (pa->bDevType == DEVTYPE_CL_PD6832) { //enable CSC IRQ routing just for IRQ detection
GetPciConfigSpace(pa, CFGSPACE_BRIDGE_CTRL, &wData, sizeof(wData)); wData |= BCTRL_CL_CSCIRQROUTING_ENABLE; SetPciConfigSpace(pa, CFGSPACE_BRIDGE_CTRL, &wData, sizeof(wData)); } else if ((pa->bDevType == DEVTYPE_CL_PD6834) || (pa->bDevType == DEVTYPE_CL_PD6833)) { //enable CSC IRQ routing just for IRQ detection
GetPciConfigSpace(pa, CFGSPACE_CL_CFGMISC1, &bData, sizeof(bData)); bData |= CL_CFGMISC1_ISACSC; SetPciConfigSpace(pa, CFGSPACE_CL_CFGMISC1, &bData, sizeof(bData)); } else if ((pa->bDevType == DEVTYPE_TI_PCI1130) || (pa->bDevType == DEVTYPE_TI_PCI1131) || (pa->bDevType == DEVTYPE_TI_PCI1031)) { GetPciConfigSpace(pa, CFGSPACE_TI_DEV_CTRL, &wData, sizeof(wData)); if ((wData & DEVCTRL_INTMODE_MASK) == DEVCTRL_INTMODE_COMPAQ) { //
// There is an errata on TI 1130, 1131 and 1031 in which if
// the chip is programmed to use serial IRQ mode (i.e. COMPAQ
// mode) and the SERIRQ pin is not pull up with a 1K resistor,
// the SERIRQ line will rise too slowly after IRQ 15 is
// deasserted so that it looks like NMI should be asserted.
// This caused spurious NMI. This is a hardware problem.
// Unfortunately, there are a large number of machines with
// this problem on the street already, so CBSS has to work
// around the problem by temporarily disabling NMI before
// doing ISA IRQ detection.
//
fTINMIBug = TRUE; _asm in al,SYSCTRL_B _asm and al,0x0f _asm push ax //
// Mask NMI
//
_asm or al,0x08 _asm out SYSCTRL_B,al } } _asm pushf _asm cli //disable interrupt
_asm in al,PIC2_IMR //save old IMRs
_asm mov ah,al _asm in al,PIC1_IMR _asm push ax
_asm mov al,0xff //mask all interrupt
_asm out PIC2_IMR,al _asm out PIC1_IMR,al
for (i = 0; i < 16; ++i) { w = (USHORT)(1 << i); if ((pa->wValidIRQs & w) && ((wIRQMask = ToggleIRQLine(pa, i)) != 0)) { _asm mov dx, wIRQMask _asm _emit 0x66 _asm _emit 0x0f _asm _emit 0xbc _asm _emit 0xc2 _asm mov wRealIRQ,ax pa->abIRQMap[wRealIRQ] = i; wRealIRQMask |= (USHORT)(1 << wRealIRQ); } } Clear_IR_Bits(wRealIRQMask);
_asm pop ax _asm out PIC1_IMR,al _asm mov al,ah _asm out PIC2_IMR,al _asm popf
if (fTINMIBug) { //
// Restore NMI mask
//
_asm pop ax _asm out SYSCTRL_B,al }
if (pa->bDevType == DEVTYPE_CL_PD6832) { //disable CSC IRQ routing (use PCI interrupt for CSC)
GetPciConfigSpace(pa, CFGSPACE_BRIDGE_CTRL, &wData, sizeof(wData)); wData &= ~BCTRL_CL_CSCIRQROUTING_ENABLE; SetPciConfigSpace(pa, CFGSPACE_BRIDGE_CTRL, &wData, sizeof(wData)); } else if ((pa->bDevType == DEVTYPE_CL_PD6834) || (pa->bDevType == DEVTYPE_CL_PD6833)) { //disable CSC IRQ routing (use PCI interrupt for CSC)
GetPciConfigSpace(pa, CFGSPACE_CL_CFGMISC1, &bData, sizeof(bData)); bData &= ~CL_CFGMISC1_ISACSC; SetPciConfigSpace(pa, CFGSPACE_CL_CFGMISC1, &bData, sizeof(bData)); }
return wRealIRQMask; } //DetectIRQMap
USHORT ToggleIRQLine( PPCCARD_INFORMATION pa, UCHAR bIRQ ) /*++
Routine Description:
This routine toggles the specified IRQ line from the adapter.
Arguments:
pa -> ADAPTER structure bIRQ - IRQ line to toggle
Returns:
returns the IRR mask from PIC
--*/ { UCHAR bOldIntCtrl, bOldIntCfg, bData; USHORT rc = 0, irr1, irr2, irr3;
bOldIntCfg = PcicReadSocket(pa, EXCAREG_CSC_CFG); bOldIntCtrl = PcicReadSocket(pa, EXCAREG_INT_GENCTRL);
//Set to a known state
PcicWriteSocket(pa, EXCAREG_INT_GENCTRL, IGC_PCCARD_RESETLO);
//Set irq number in interrupt control register and enable irq
PcicWriteSocket(pa, EXCAREG_CSC_CFG, (UCHAR)((bIRQ << 4) | CSCFG_CD_ENABLE));
//clear all pending interrupts
bData = PcicReadSocket(pa, EXCAREG_CARD_STATUS); irr1 = GetPICIRR();
if (PcicReadSocket(pa, EXCAREG_IDREV) != 0x82) { //This is not an A stepping part, try the undocumented interrupt
//register. If this fails the other routine will be tried.
PcicWriteSocket(pa, EXCAREG_CARDDET_GENCTRL, CDGC_SW_DET_INT); irr2 = GetPICIRR();
//reset pending interrupt
bData = PcicReadSocket(pa, EXCAREG_CARD_STATUS); irr3 = GetPICIRR(); rc = (USHORT)((irr1 ^ irr2) & (irr2 ^ irr3)); }
if (rc == 0) { //Generate interrupt by de-asserting IRQ line so the PIC can pull it
//high
PcicWriteSocket(pa, EXCAREG_CSC_CFG, 0); //if (pa->dwfAdapter & AF_TI_SERIALIRQ)
// TIReleaseSerialIRQ(pa, bIRQ);
irr2 = GetPICIRR();
//re-assert IRQ line
PcicWriteSocket(pa, EXCAREG_CSC_CFG, (UCHAR)((bIRQ << 4) | CSCFG_CD_ENABLE));
//reset pending interrupt
bData = PcicReadSocket(pa, EXCAREG_CARD_STATUS); irr3 = GetPICIRR(); rc = (USHORT)((irr1 ^ irr2) & (irr2 ^ irr3)); }
PcicWriteSocket(pa, EXCAREG_CSC_CFG, bOldIntCfg); PcicWriteSocket(pa, EXCAREG_INT_GENCTRL, bOldIntCtrl);
return rc; } //ToggleIRQLine
/***LP GetPICIRR - Read PIC IRR
* * ENTRY * None * * EXIT * returns the IRR mask from PIC */
USHORT GetPICIRR(VOID) { USHORT wData;
//
// Delay 2 usec before reading PIC because serial IRQ may be a bit slow.
//
TimeOut(4);
_asm mov al,PIC_RD_IR _asm out PIC2_OCW3,al _asm in al,PIC2_OCW3 _asm mov ah,al
_asm mov al,PIC_RD_IR _asm out PIC1_OCW3,al _asm in al,PIC1_OCW3
_asm mov wData,ax
return wData; } //GetPICIRR
UCHAR PcicReadSocket( PPCCARD_INFORMATION pa, USHORT Reg ) { USHORT IoBase = pa->IoBase; UCHAR value; _asm { mov dx, IoBase mov ax, Reg out dx, al inc dx in al, dx mov value, al } return value; } VOID PcicWriteSocket( PPCCARD_INFORMATION pa, USHORT Reg, UCHAR value ) { USHORT IoBase = pa->IoBase; _asm { mov dx, IoBase mov ax, Reg out dx, al inc dx mov al, value out dx, al } }
UCHAR PCIDeref[4][4] = { {4,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} }; VOID SetPciConfigSpace( PPCCARD_INFORMATION pa, USHORT Offset, PVOID pvBuffer, USHORT Length ) { USHORT IoSize; PUCHAR Buffer = (PUCHAR) pvBuffer; //
// Read it
//
while (Length) { pa->PciCfg1.u.bits.RegisterNumber = Offset / sizeof(ULONG);
IoSize = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
SetPCIType1Data (pa->PciCfg1.u.AsULONG, (Offset % sizeof(ULONG)), Buffer, IoSize);
Offset += IoSize; Buffer += IoSize; Length -= IoSize; } }
VOID GetPciConfigSpace( PPCCARD_INFORMATION pa, USHORT Offset, PVOID pvBuffer, USHORT Length ) { USHORT IoSize; USHORT i; PUCHAR Buffer = (PUCHAR) pvBuffer; //
// Zap input buffer
//
for (i=0; i < Length; i++) { Buffer[i] = 0xff; }
//
// Read it
//
while (Length) { pa->PciCfg1.u.bits.RegisterNumber = Offset / sizeof(ULONG);
IoSize = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
GetPCIType1Data (pa->PciCfg1.u.AsULONG, (Offset % sizeof(ULONG)), Buffer, IoSize);
Offset += IoSize; Buffer += IoSize; Length -= IoSize; } }
|