⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ioapic.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id$
 *
 * COPYRIGHT:             See COPYING in the top level directory
 * PROJECT:               ReactOS kernel
 * FILE:                  hal/halx86/generic/ioapic.c
 * PURPOSE:               
 * PROGRAMMER:            
 */

/* INCLUDES *****************************************************************/

#include <hal.h>
#define NDEBUG
#include <debug.h>

/* GLOBALS *****************************************************************/

MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */
ULONG IRQCount = 0;                             /* Number of IRQs  */
ULONG IrqApicMap[MAX_IRQ_SOURCE];

UCHAR BUSMap[MAX_BUS];				/* Map of all buses in the system */
UCHAR PCIBUSMap[MAX_BUS];			/* Map of all PCI buses in the system */

IOAPIC_INFO IOAPICMap[MAX_IOAPIC];		/* Map of all I/O APICs in the system */
ULONG IOAPICCount;				/* Number of I/O APICs in the system */

ULONG IRQVectorMap[MAX_IRQ_SOURCE];             /* IRQ to vector map */

/* EISA interrupts are always polarity zero and can be edge or level
 * trigger depending on the ELCR value.  If an interrupt is listed as
 * EISA conforming in the MP table, that means its trigger type must
 * be read in from the ELCR */

#define default_EISA_trigger(idx)	(EISA_ELCR(IRQMap[idx].SrcBusIrq))
#define default_EISA_polarity(idx)	(0)

/* ISA interrupts are always polarity zero edge triggered,
 * when listed as conforming in the MP table. */

#define default_ISA_trigger(idx)	(0)
#define default_ISA_polarity(idx)	(0)

/* PCI interrupts are always polarity one level triggered,
 * when listed as conforming in the MP table. */

#define default_PCI_trigger(idx)	(1)
#define default_PCI_polarity(idx)	(1)

/* MCA interrupts are always polarity zero level triggered,
 * when listed as conforming in the MP table. */

#define default_MCA_trigger(idx)	(1)
#define default_MCA_polarity(idx)	(0)

/***************************************************************************/

extern VOID Disable8259AIrq(ULONG irq);
ULONG IOAPICRead(ULONG Apic, ULONG Offset);
VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value);

/* FUNCTIONS ***************************************************************/

/*
 * EISA Edge/Level control register, ELCR
 */
static ULONG EISA_ELCR(ULONG irq)
{
   if (irq < 16) 
   {
      PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3));
      return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1;
   }
   DPRINT("Broken MPtable reports ISA irq %d\n", irq);
   return 0;
}

static ULONG 
IRQPolarity(ULONG idx)
{
   ULONG bus = IRQMap[idx].SrcBusId;
   ULONG polarity;

   /*
    * Determine IRQ line polarity (high active or low active):
    */
   switch (IRQMap[idx].IrqFlag & 3)
   {
      case 0: /* conforms, ie. bus-type dependent polarity */
         {
            switch (BUSMap[bus])
	    {
	       case MP_BUS_ISA: /* ISA pin */
		  polarity = default_ISA_polarity(idx);
		  break;
		  
	       case MP_BUS_EISA: /* EISA pin */
		  polarity = default_EISA_polarity(idx);
		  break;
		
	       case MP_BUS_PCI: /* PCI pin */
		  polarity = default_PCI_polarity(idx);
		  break;

	       case MP_BUS_MCA: /* MCA pin */
                  polarity = default_MCA_polarity(idx);
		  break;
		
	       default:
		  DPRINT("Broken BIOS!!\n");
		  polarity = 1;
	    }
	 }
	 break;

      case 1: /* high active */
	 polarity = 0;
	 break;

      case 2: /* reserved */
	 DPRINT("Broken BIOS!!\n");
	 polarity = 1;
	 break;

      case 3: /* low active */
         polarity = 1;
	 break;

      default: /* invalid */
	 DPRINT("Broken BIOS!!\n");
	 polarity = 1;
   }
   return polarity;
}

static ULONG 
IRQTrigger(ULONG idx)
{
   ULONG bus = IRQMap[idx].SrcBusId;
   ULONG trigger;

   /*
    * Determine IRQ trigger mode (edge or level sensitive):
    */
   switch ((IRQMap[idx].IrqFlag >> 2) & 3)
   {
      case 0: /* conforms, ie. bus-type dependent */
	 {
            switch (BUSMap[bus])
	    {
	       case MP_BUS_ISA: /* ISA pin */
	          trigger = default_ISA_trigger(idx);
		  break;

	       case MP_BUS_EISA: /* EISA pin */
		  trigger = default_EISA_trigger(idx);
		  break;
		
	       case MP_BUS_PCI: /* PCI pin */
		  trigger = default_PCI_trigger(idx);
		  break;

               case MP_BUS_MCA: /* MCA pin */
		  trigger = default_MCA_trigger(idx);
		  break;
		
               default:
                  DPRINT("Broken BIOS!!\n");
		  trigger = 1;
	    }
	 }
	 break;

      case 1: /* edge */
	 trigger = 0;
	 break;

      case 2: /* reserved */
	 DPRINT("Broken BIOS!!\n");
	 trigger = 1;
	 break;

      case 3: /* level */
 	 trigger = 1;
	 break;
	
      default: /* invalid */
	 DPRINT("Broken BIOS!!\n");
	 trigger = 0;					
   }
   return trigger;
}

static ULONG 
Pin2Irq(ULONG idx,
	ULONG apic,
	ULONG pin)
{
   ULONG irq, i;
   ULONG bus = IRQMap[idx].SrcBusId;

   /*
    * Debugging check, we are in big trouble if this message pops up!
    */
   if (IRQMap[idx].DstApicInt != pin) 
   {
      DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
   }

   switch (BUSMap[bus])
   {
      case MP_BUS_ISA: /* ISA pin */
      case MP_BUS_EISA:
      case MP_BUS_MCA:
	irq = IRQMap[idx].SrcBusIrq;
	break;

      case MP_BUS_PCI: /* PCI pin */
	 /*
	  * PCI IRQs are mapped in order
	  */
	 i = irq = 0;
	 while (i < apic)
	 {
	    irq += IOAPICMap[i++].EntryCount;
	 }
	 irq += pin;
	 break;
	
      default:
	 DPRINT("Unknown bus type %d.\n",bus);
	 irq = 0;
   }
   return irq;
}

static ULONG 
AssignIrqVector(ULONG irq)
{
#if 0
   static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0;
#endif
   ULONG vector;
   /* There may already have been assigned a vector for this IRQ */
   vector = IRQVectorMap[irq];
   if (vector > 0)
   {
      return vector;
   }
#if 0
   if (current_vector > FIRST_SYSTEM_VECTOR) 
   {
      vector_offset++;
      current_vector = FIRST_DEVICE_VECTOR + vector_offset;
   } 
   else if (current_vector == FIRST_SYSTEM_VECTOR) 
   {
      DPRINT1("Ran out of interrupt sources!");
      KEBUGCHECK(0);
   }

   vector = current_vector;
   IRQVectorMap[irq] = vector;
   current_vector += 8;
   return vector;
#else
   vector = IRQ2VECTOR(irq);
   IRQVectorMap[irq] = vector;
   return vector;
#endif
}

/*
 * Find the IRQ entry number of a certain pin.
 */
static ULONG 
IOAPICGetIrqEntry(ULONG apic,
		  ULONG pin,
		  ULONG type)
{
   ULONG i;

   for (i = 0; i < IRQCount; i++)
   {
      if (IRQMap[i].IrqType == type &&
	  (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId || IRQMap[i].DstApicId == MP_APIC_ALL) &&
	  IRQMap[i].DstApicInt == pin)
      {
         return i;
      }
   }
   return -1;
}


VOID 
IOAPICSetupIrqs(VOID)
{
   IOAPIC_ROUTE_ENTRY entry;
   ULONG apic, pin, idx, irq, first_notcon = 1, vector, trigger;

   DPRINT("Init IO_APIC IRQs\n");

   /* Setup IRQ to vector translation map */
   memset(&IRQVectorMap, 0, sizeof(IRQVectorMap));

   for (apic = 0; apic < IOAPICCount; apic++) 
   {
      for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) 
      {
         /*
	  * add it to the IO-APIC irq-routing table
	  */
	 memset(&entry,0,sizeof(entry));

	 entry.delivery_mode = (APIC_DM_LOWEST >> 8);
	 entry.dest_mode = 1;  /* logical delivery */
	 entry.mask = 1;       /* disable IRQ */
         entry.dest.logical.logical_dest = 0;

	 idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED);
	 if (idx == (ULONG)-1)
	 {
	    if (first_notcon) 
	    {
	       DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin);
	       first_notcon = 0;
	    } 
	    else 
	    {
	       DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin);
            }
	    continue;
	 }

         trigger = IRQTrigger(idx);
	 entry.polarity = IRQPolarity(idx);

	 if (trigger) 
	 {
	    entry.trigger = 1;
	 }

	 irq = Pin2Irq(idx, apic, pin);

  	 vector = AssignIrqVector(irq);
	 entry.vector = vector;

	 DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector, irq);

         if (irq == 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -