Maray中对8259A PIC的初始化代码

 学习接口,才发现原来做的很多事情是在对接口在编程:(

捡起到处凑出来的代码看看,唉,其实真的很简单!

重新写了些注释,为后来人铺路~


/*
  Name:    irq.c
  Copyright: GPL
  Author: Raywill
  Date: 22-12-06
  Description: init,disable and enable interrupt procedure
*/


#ifndef IRQ1_PORT
    #define IRQ1_PORT 
0x21
    #define IRQ2_PORT 
0xA1
#endif
/*
关于8259A
1.8259A是PC中管理中断的芯片。在实际PC主板中并不能找到8259,
这是因为它被集成到了一个大规模芯片中去了,其可提供的功能于8259等价
作为OSer,我们我们完全可以当做PC中含有8259芯片。

2.8259工作前需要对其初始化,包括
    1)中断请求方式的设定(ICW1)
    2)中断类型号的设定(ICW2)
    3)中断级联方式的设定(ICW3)
    4)特定完全嵌套方式(ICW4)

3.PIC端口地址
    Master PIC    command     0x20  
    Master PIC    data         0x21  
    Slave PIC    command     0xA0  
    Slave PIC    data         0xA1  

4.对init_irq()函数中的操作的解释
    ==========================================
    outportb(0x20, 0x11);
    *)对ICW1编程使用20H号端口(A0=0)
    *)11H=000 1 0 0 0 1B
        D7-D5    000    中断向量地址的A7~A5
        D4=1
        D3    0    边缘出发输入
        D2    0    调用间隔为8
        D1    0    级联方式
        D0    1    要写ICW4
        
    ==========================================
    
    outportb(0x21, irq0_int);
    outportb(0xA1, irq8_int);
    
    *)对ICW2编程使用21H号端口(A0=1)
    *)irq0_int = 20H = 00100 000B
        D7-D3    00100    中断类型号高5位  100000=20H
                经过这一步后,IR0对应的中断号码为100000B=20H
                         IR1对应的中断号码为100000B=21H
                         ·······
                         IR7对应的中断号码为100000B=27H
        D2-D0    000    低三位中断类型号,由硬件IR0~IR7提供
    *) irq8_int = 28H = 00101 000B;    
        D7-D3    00101    中断类型号高5位  101000=28H
                经过这一步后,IR8对应的中断号码为100000B=28H
                         IR9对应的中断号码为100000B=29H
                         ·······
                         IR15对应的中断号码为100000B=2FH
        D2-D0    000    低三位中断类型号,由硬件IR8~IR15提供
        
    ==========================================
    
    outportb(0x21, 0x04);        //对主片(Master)编程
    outportb(0xA1, 0x02);        //对从片(Slave)编程
    *)对ICW3编程使用21H号端口(A0=1)
    *)只有配置成为级联模式才需要设置ICW3
    *)主片和从片的ICW各位表示的含义不同
    *)主片
        04H = 00000010B
            1)D7-D0    00000010     INT级联掩码,第二位S1=1表示从片是通过IR1引脚连接到主片的
    *)从片
        02H = 00000 010
            1)D7-D3    00000        保留不用,全置零
            2)D2-D0    010        表示本从片的INT信号连接到主片的第几个引脚,
                            010B表示2号引脚,和主片中的04H正好对应

    ==========================================    
    
    outportb(0x21, 0x01);
    outportb(0xA1, 0x01);
    *)01H=000 0 00 0 1
        D7-D5    000    强制为0
        D4    0    非特殊全嵌套方式
        D3-D2    00    非缓冲方式
        D1    0    正常EIO(需要在中断末尾加入中断结束命令)
        D0    1    MCS 8086/88 模式

    ==========================================
    
5.对上面过程的总结    
    init_irq主要做了下面几件事:
    1)重定向中断向量位置
    The default (BIOS-defined) vector offsets are 8 for Master PIC and 0x70 for Slave PIC: 
    Master: IRQ 0..7 -> INT 8..0xF (vector offset = 0x08) 
    Slave: IRQ 8..15 -> INT 0x70..0x77 (vector offset = 0x70) 
    However, these default values don't suit the needs of ProtectedMode programming: there's a collision between IRQs 0..7 (mapped to INT 8..0xF) and processor exceptions (INT 0..0x1F are reserved). Consequently you wouldn't be able to tell the difference between an IRQ or an software error. 
    2)对级联进行编程,确定工作模式
    
6.ICW初始化完成后,就可以对PIC发OCW命令字了用来初始化中断屏蔽字
    Master PIC    data         0x21  
    Slave PIC    data         0xA1  
    Di=1为关i对应中断,Di=0为关闭对应中断
Maray中代码为:
    //Disable All Interrupt First
    outportb(0x21, ~0x00);
    outportb(0xA1, ~0x00);
*/

void  init_irq()
{
    static const unsigned irq0_int 
= 0x20, irq8_int = 0x28;
/**/

/* Initialization Control Word #1 (ICW1) */
    outportb(
0x200x11);
    outportb(
0xA00x11);
/* ICW2:
route IRQs 0-7 to INTs 20h-27h 
*/

    outportb(
0x21, irq0_int);
/* route IRQs 8-15 to INTs 28h-2Fh */
    outportb(
0xA1, irq8_int);
/* ICW3 */
    outportb(
0x210x04);
    outportb(
0xA10x02);
/* ICW4 */
    outportb(
0x210x01);
    outportb(
0xA10x01);
/* enable IRQ0 (timer) and IRQ1 (keyboard) */
    outportb(
0x21~0x00);/*only keyboard for testing*/
    outportb(
0xA1~0x00);
    
    kprintf(
"8259 init OK! ");    
}


void  enable_irq( int  irq)
{
    
/*two case:irq<8,irq>=8*/
    
byte bit=1;
    
    
if(irq>(15+IRQ_OFFSET)||irq<(0+IRQ_OFFSET)) return;
    
    bit
<<=irq%8;
    
if( irq < (8+IRQ_OFFSET) ){
        outportb(IRQ1_PORT,
~bit & inportb(IRQ1_PORT) );
    }
else{
        outportb(IRQ2_PORT,
~bit & inportb(IRQ2_PORT));
    }

}


void  disable_irq( int  irq)
{
    
/*two case:irq<8,irq>=8*/
    
byte bit=1;
    
    
if(irq>(15+IRQ_OFFSET)||irq<(0+IRQ_OFFSET)) return;

    bit
<<=irq%8;
    
if( irq < (8+IRQ_OFFSET) ){
        outportb(IRQ1_PORT,bit
|inportb(IRQ1_PORT));
    }
else{
        outportb(IRQ2_PORT,bit
|inportb(IRQ2_PORT));
    }

}

你可能感兴趣的:(编程,timer,工作,Date,byte,keyboard)