/* * OPTIVIP.C - OPTi Viper-M PCI chipset routines. * * Notes: * Algorithms from OPTi Viper-M 82C556M/82C557M/82C558M doc, * 82C558M spec. * */ #include "local.h" // IRQ = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const UCHAR rgbIRQToBig[16] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 6, 7 }; const UCHAR rgbIRQToSmall[16] = { 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 }; const UCHAR rgbBigToIRQ[8] = { 0, 5, 9, 10, 11, 12, 14, 15 }; const UCHAR rgbSmallToIRQ[8] = { 0, 3, 4, 7 }; /**************************************************************************** * * OptiViperSetIRQ - Set a OptiViper PCI link to a specific IRQ * * Exported. * * ENTRY: bIRQNumber is the new IRQ to be used. * * bLink is the Link to be set. * * EXIT: Standard PCIMP return value. * ***************************************************************************/ PCIMPRET CDECL OptiViperSetIRQ(UCHAR bIRQNumber, UCHAR bLink) { ULONG ulIRQRegister; // // If not an OPTi IRQ, bail. // if (bIRQNumber && (!rgbIRQToBig[bIRQNumber] && !rgbIRQToSmall[bIRQNumber])) { return(PCIMP_INVALID_IRQ); } // // Make link number 0 based, and validate. // bLink--; if (bLink > 3) { return(PCIMP_INVALID_LINK); } // // Read in the big IRQ Register, // clear the old IRQ index for the link, // set the new IRQ index, // and write it back. // ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40); ulIRQRegister &= ~(0x7 << (3 * bLink)); ulIRQRegister |= rgbIRQToBig[bIRQNumber] << (3 * bLink); WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x40, ulIRQRegister); // // Read in the small IRQ register, // clear the old IRQ index for the link, // set the new IRQ index, // and write it back. // ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50); ulIRQRegister &= ~(0x3 << (2 * bLink)); ulIRQRegister |= rgbIRQToSmall[bIRQNumber] << (2 * bLink); WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x50, ulIRQRegister); return(PCIMP_SUCCESS); } /**************************************************************************** * * OptiViperGetIRQ - Get the IRQ of a OptiViper PCI link * * Exported. * * ENTRY: pbIRQNumber is the buffer to fill. * * bLink is the Link to be read. * * EXIT: Standard PCIMP return value. * ***************************************************************************/ PCIMPRET CDECL OptiViperGetIRQ(PUCHAR pbIRQNumber, UCHAR bLink) { ULONG ulIRQRegister; ULONG ulIndex; // // Make link number 0 based, and validate. // bLink--; if (bLink > 3) { return(PCIMP_INVALID_LINK); } // // Read in the big IRQ Register. // ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40); // // If we have a big IRQ, we're done. // ulIndex = (ulIRQRegister >> (bLink * 3)) & 0x7; if ((*pbIRQNumber = rgbBigToIRQ[ulIndex]) != 0) { return(PCIMP_SUCCESS); } // // Read in the small IRQ register. // ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50); // // Set the buffer to the small IRQ's value. // ulIndex = (ulIRQRegister >> (bLink * 2)) & 0x3; *pbIRQNumber = rgbSmallToIRQ[ulIndex]; return(PCIMP_SUCCESS); } /**************************************************************************** * * OptiViperSetTrigger - Set the IRQ triggering values for the OptiViper * * Exported. * * ENTRY: ulTrigger has bits set for Level triggered IRQs. * * EXIT: Standard PCIMP return value. * ***************************************************************************/ PCIMPRET CDECL OptiViperSetTrigger(ULONG ulTrigger) { ULONG ulBigIRQRegister; ULONG ulSmallIRQRegister; ULONG i; // // Read in the big & small IRQ registers, // setting all IRQs to edge. // ulBigIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40) & ~0x00FE0000; ulSmallIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50) & ~0x00000700; // // For each IRQ... // for (i=0; i<16; i++) { // // If we want this to be level triggered... // if (ulTrigger & (1 << i)) { if (rgbIRQToBig[i]) { // // If it's a big IRQ, set the // corresponding bit in the // big register. // ulBigIRQRegister |= 1 << (16 + rgbIRQToBig[i]); } else if (rgbIRQToSmall[i]) { // // If it's a small IRQ, set the // corresponding bit in the // small register. // ulSmallIRQRegister |= 1 << (11 - rgbIRQToSmall[i]); } else { // // Trying to level set an unsupported IRQ. // return(PCIMP_INVALID_IRQ); } } } // // Write the new IRQ register values. // WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x40, ulBigIRQRegister); WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x50, ulSmallIRQRegister); return(PCIMP_SUCCESS); } /**************************************************************************** * * OptiViperGetTrigger - Get the IRQ triggering values for the OptiViper * * Exported. * * ENTRY: pulTrigger will have bits set for Level triggered IRQs. * * EXIT: Standard PCIMP return value. * ***************************************************************************/ PCIMPRET CDECL OptiViperGetTrigger(PULONG pulTrigger) { ULONG ulBigIRQRegister; ULONG ulSmallIRQRegister; ULONG i; // // Assume all edge. // *pulTrigger = 0; // // Read in the big&small IRQ registers. // ulBigIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40); ulSmallIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50); // // For each IRQ... // for (i=0; i<16; i++) { // // If it's a big IRQ and it's level triggered, // or if it's a small IRQ and it's level triggered, // set the corresponding bit in pulTrigger. // if ( ((rgbIRQToBig[i]) && (ulBigIRQRegister & (1 << (16 + rgbIRQToBig[i])))) || ((rgbIRQToSmall[i]) && (ulSmallIRQRegister & (1 << (11 - rgbIRQToSmall[i]))))) { *pulTrigger |= 1 << i; } } return(PCIMP_SUCCESS); } /**************************************************************************** * * OptiViperValidateTable - Validate an IRQ table * * Exported. * * ENTRY: piihIRQInfoHeader points to an IRQInfoHeader followed * by an IRQ Routing Table. * * ulFlags are PCIMP_VALIDATE flags. * * EXIT: Standard PCIMP return value. * ***************************************************************************/ #ifdef ALLOC_PRAGMA PCIMPRET CDECL OptiViperValidateTable(PIRQINFOHEADER piihIRQInfoHeader, ULONG ulFlags); #pragma alloc_text(PAGE, OptiViperValidateTable) #endif //ALLOC_PRAGMA PCIMPRET CDECL OptiViperValidateTable(PIRQINFOHEADER piihIRQInfoHeader, ULONG ulFlags) { PAGED_CODE(); if (GetMaxLink(piihIRQInfoHeader)>0x04) { return(PCIMP_FAILURE); } return(PCIMP_SUCCESS); }