修改System_call.S中的hd_interrupt函数,主要功能就是重设EOI,判断do_hd是否为空,空报错,不为空调用回调函数。
hd_interrupt:
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0xA0 # EOI to interrupt controller #1
jmp 1f # give port chance to breathe
1: jmp 1f
1: xorl %edx,%edx
xchgl do_hd,%edx
testl %edx,%edx
jne 1f
movl $unexpected_hd_interrupt,%edx
1: outb %al,$0x20
call *%edx # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
完整的hd.c
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/hdreg.h>
#include <asm/system.h>
#include <asm/io.h>
extern void hd_interrupt(void);
#define NULL ((void *) 0)
int cylinders;//柱面数
int heads;//磁头数
int sect_per_track;//每个磁道的扇区数
int dev=0;//
void (*do_hd)(void) = NULL;
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):)
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):)
static int controller_ready(void)
{
int retries=10000;
while (--retries && (inb_p(HD_STATUS)&0x80));
return (retries);
}
void unexpected_hd_interrupt(void)
{
printk("Unexpected HD interrupt\n\r");
}
#define LBA
#ifdef LBA//LBA模式
/*
*drive-硬盘号(0或1)
*nsect-要读写的扇区数
*lba -起始扇区
*cmd -命令码
*intr_addr- 回调函数的函数指针
*/
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int lba,unsigned int cmd,void (*intr_addr)(void))
{
register int port asm("dx");
if (drive>1)
printk("Trying to write bad sector");
if (!controller_ready())
printk("HD controller not ready");
do_hd = intr_addr;
outb_p(0,HD_CMD);
port=HD_DATA;
outb_p(0,++port);
outb_p(nsect,++port);
outb_p(lba&0xff,++port);
outb_p((lba>>8)&0xff,++port);
outb_p((lba>>16)&0xff,++port);
outb_p(0xE0|(drive<<4)|((lba>>24)&0xf),++port);
outb(cmd,++port);
}
#else//CHS模式
/*
*drive-硬盘号(0或1)
*nsect-要读写的扇区数
*sect -起始扇区
*head -磁头号
*cyl -柱面号
*cmd -命令码
*intr_addr- 回调函数的函数指针
*/
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
unsigned int head,unsigned int cyl,unsigned int cmd,void (*intr_addr)(void))
{
register int port asm("dx");
if (drive>1 || head>15)
printk("Trying to write bad sector");
if (!controller_ready())
printk("HD controller not ready");
do_hd = intr_addr;
outb_p(0,HD_CMD);
port=HD_DATA;
outb_p(0,++port);
outb_p(nsect,++port);
outb_p(sect,++port);
outb_p(cyl,++port);
outb_p(cyl>>8,++port);
outb_p(0xA0|(drive<<4)|head,++port);
outb(cmd,++port);
}
#endif
#define SECTOR_SIZE 512
u8 hdbuf[SECTOR_SIZE * 2];
void hd_init(void)
{
//blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
set_intr_gate(0x2E,&hd_interrupt);
outb_p(inb_p(0x21)&0xfb,0x21);
outb(inb_p(0xA1)&0xbf,0xA1);
}
void print_identify_info()
{
int i, k;
char s[64];
port_read(HD_DATA, hdbuf, SECTOR_SIZE);
u16* hdinfo = hdbuf;
//看手册77页这张表
printk("Number of logical cylinders:%x\n",hdinfo[1]);
printk("Number of logical heads:%x\n",hdinfo[3]);
printk("sectors per track:%x\n",hdinfo[6]);
hdinfo[20]='\0';
printk("Serial number:%s\n",&hdinfo[10]);
printk("obsolete:%x\n",hdinfo[22]);
//cylinders=hdinfo[54];
//heads=hdinfo[55];
//sect_per_track=hdinfo[56];
}
void hd_identify(int drive)
{
//读identify
#ifdef LBA
hd_out(0,0,0,0xEC,&print_identify_info);
#else
hd_out(0,0,0,0,0,0xEC,&print_identify_info);
#endif
}
void read_intr(void)
{
int i;
port_read(HD_DATA,hdbuf,512);
for(i=0x1be;i<512;i++)
printk("hdbuf=%x ; \n",hdbuf[i]);
}
#define WIN_READ 0x20
void read(void)
{
#ifdef LBA//LBA模式
//读硬盘0的0扇区(第一个扇区),读一个扇区,回调函数为read_intr
hd_out(0,1,0,WIN_READ,&read_intr);
#else //CHS模式
//读硬盘0的0磁头0柱面1扇区(第一个扇区),读一个扇区,回调函数为read_intr
hd_out(0,1,1,0,0,WIN_READ,&read_intr);
#endif
}