修改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
#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 }