学习接口,才发现原来做的很多事情是在对接口在编程:(
捡起到处凑出来的代码看看,唉,其实真的很简单!
重新写了些注释,为后来人铺路~
/**/ /*
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(0x20, 0x11);
outportb(0xA0, 0x11);
/**//* 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(0x21, 0x04);
outportb(0xA1, 0x02);
/**//* ICW4 */
outportb(0x21, 0x01);
outportb(0xA1, 0x01);
/**//* 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));
}
}