/************************************************************************************** $Id: ide.c,v 1.9 2002/04/29 23:34:53 reddawg Exp $ **************************************************************************************/ #include <ubixos/video.h> #include <ubixos/io.h> #include <ubixos/8259.h> #include <ubixos/gdt.h> #include <ubixos/idt.h> #include <ubixos/8259.h> #include <ubixos/delay.h> #include <drivers/ide.h> ide_dev_t ide_dev[2]; static __u32 interrupt_occured=0; void initIde(void) { unsigned char tmp; kprint("Initializing IDE....\n"); ide_dev[0].sel=ide_dev[2].sel=0xA0; ide_dev[1].sel=ide_dev[3].sel=0xB0; ide_dev[0].ioadr=ide_dev[1].ioadr=0x1F0; ide_dev[2].ioadr=ide_dev[3].ioadr=0x170; ide_dev[0].irq=ide_dev[1].irq=0x4000; ide_dev[2].irq=ide_dev[3].irq=0x8000; set_vector(irq14, 14+0x20, (D_INT + D_PRESENT + D_DPL3)); set_vector(irq15, 15, (D_INT + D_PRESENT + D_DPL3)); enable_irq(14); enable_irq(15); //outportb(0x1F2,0x55); //tmp = inportb(0x1F2); //kprint("["); //printlong(tmp); //kprint("]\n"); ideProbe(); } void irq14() { interrupt_occured|=ide_dev[0].irq; outportb(0xA0,0x20); outportb(0x20,0x20); } void irq15() { interrupt_occured|=ide_dev[2].irq; outportb(0xA0,0x20); outportb(0x20,0x20); } void ideProbe(void) { __u8 temp1,temp2,whichdrive; __u16 ioadr,temp; for (whichdrive=0;whichdrive<4;whichdrive+=2) { ioadr=ide_dev[whichdrive].ioadr; outportb(ioadr+ATA_REG_CNT,0x55); outportb(ioadr+ATA_REG_SECT,0xAA); temp1=inportb(ioadr+ATA_REG_CNT); temp2=inportb(ioadr+ATA_REG_SECT); if (temp1!=0x55 || temp2!=0xAA) { NO_DRIVES: ide_dev[whichdrive+1].ioadr=ide_dev[whichdrive].ioadr=0; continue; } outportb(ioadr+ATA_REG_SLCT,0xE); delay(1); outportb(ioadr+ATA_REG_SLCT,0x8); delay(1); for (temp=200;temp;temp--) { if ((inportb(ioadr+ATA_REG_STAT)&0x80)==0) { break; } delay(1); } if (!temp) { kprintf("ide_probe: no master on I/F 0x%03X\r\n",ioadr); goto NO_DRIVES; } kprintf("hd%1u (0x%03X, master): ",whichdrive,ioadr); ide_probe_dev(&ide_dev[whichdrive]); if(!ide_select(&ide_dev[whichdrive+1])) { ide_select(&ide_dev[whichdrive]); ide_dev[whichdrive+1].ioadr=0; kprintf("ide_probe: no slave on I/F 0x%03X\r\n",ioadr); continue; } kprintf("hd%1u (0x%03X, slave): ",whichdrive+1,ioadr); ide_probe_dev(&ide_dev[whichdrive+1]); } } void ide_probe_dev(ide_dev_t * dev) { __u8 temp1,temp2; __u16 ioadr,temp; ioadr=dev->ioadr; temp1=inportb(ioadr+ATA_REG_CNT); temp2=inportb(ioadr+ATA_REG_SECT); if(temp1!=0x01 || temp2!=0x01) { kprintf("no drive here\r\n"); NO_DRIVE: dev->ioadr=0; dev->sel=0; return; } temp1=inportb(ioadr+ATA_REG_LOCYL); temp2=inportb(ioadr+ATA_REG_HICYL); temp=inportb(ioadr+ATA_REG_STAT); clear_irq_occured(); if(temp1==0x14 && temp2==0xEB) { kprintf("ATAPI CD-ROM, "); dev->flags|=ATA_FLG_ATAPI; temp1=ATA_CMD_PID; outportb(ioadr+ATA_REG_CMD,temp1); temp=WAIT_PID; dev->bytes_per_block=2048; } else if(!temp1 && !temp2 && temp) { kprintf("ATA HDD, "); temp1=ATA_CMD_ID; outportb(ioadr+ATA_REG_CMD,temp1); temp=WAIT_ID; dev->bytes_per_block=512; } else { kprintf("unknown drive type\r\n"); goto NO_DRIVE; } delay(4); if(!ide_await_interrupt(0xC000,temp)) { kprintf("cannot identify device\r\n"); goto NO_DRIVE; } inportb(ioadr+ATA_REG_STAT); ide_insw(ioadr+ATA_REG_DATA,(__u16 *)&dev->hwif,sizeof(ide_hwif_t)>>1); temp2=1; if(temp1==ATA_CMD_PID) { if((dev->hwif.Model[0]=='N' && dev->hwif.Model[1]=='E') || (dev->hwif.Model[0]=='F' && dev->hwif.Model[1]=='X') || (dev->hwif.Model[0]=='P' && dev->hwif.Model[1]=='i')) temp2=0; } for(temp=0;temp<40;temp+=2) { kprintf("%c",dev->hwif.Model[temp^temp2]); kprintf("%c",dev->hwif.Model[temp^temp2^1]); } kprintf("\r\n"); kprintf(" C/H/S=%u:%u:%u, ",dev->hwif.PhysCyls, dev->hwif.PhysHeads,dev->hwif.PhysSects); dev->sects=dev->hwif.PhysSects; dev->heads=dev->hwif.PhysHeads; dev->cyls=dev->hwif.PhysCyls; if(dev->hwif.Capability & 2) { kprintf("LBA, "); dev->flags|=ATA_FLG_LBA; } if(dev->hwif.Capability & 1) { kprintf("DMA, "); dev->flags|=ATA_FLG_DMA; } if((dev->hwif.MultSectValid & 1) && dev->hwif.MultSect) { temp=dev->hwif.MaxMult; kprintf("MaxMult=%u, ",temp); } else temp=1; dev->mult_count=temp; if((dev->flags & ATA_FLG_LBA) && !ide_check_lba_geometry(dev)) { kprintf("BADLBA, "); } kprintf("%uK cache\r\n",dev->hwif.BufSize>>1); kprintf(" BufType=%u ECCBytes=%u DwordIO=0x%X\r\n", dev->hwif.BufType,dev->hwif.ECCBytes,dev->hwif.DwordIO); } int ide_select(ide_dev_t * dev) { __u16 temp; temp=inportb(dev->ioadr+ATA_REG_DRVHD); if(((temp^dev->sel)&0x10)==0) return 1; outportb(dev->ioadr+ATA_REG_DRVHD,dev->sel); delay(1); for(temp=WAIT_READY;temp;temp--) { if((inportb(dev->ioadr+ATA_REG_STAT)&0x80)==0) break; delay(1); } return temp!=0 ? 1 : 0; } int ide_await_interrupt(__u32 mask,__u32 timeout) { __u32 intr; for(;timeout;timeout--) { intr=interrupt_occured; if(intr & mask) break; delay(1); } if(!timeout) return 0; interrupt_occured&=~mask; return intr & mask; } void ide_insw(__u16 Adr,__u16 * Data,__u16 Count) { for(;Count;Count--) *Data++=inportw(Adr); } int ide_check_lba_geometry(ide_dev_t * dev) { __u32 lba_sects,chs_sects,_10_percent; lba_sects=dev->hwif.LBASects; chs_sects=dev->cyls*dev->heads*dev->sects; _10_percent=chs_sects/10; if((lba_sects-chs_sects)<_10_percent) return 1; lba_sects=(lba_sects<<16)|(lba_sects>>16); if((lba_sects-chs_sects)<_10_percent) { dev->hwif.LBASects=lba_sects; dev->lba_blocks=lba_sects; dev->capabilities|=ATA_CAP_LBA; return 1; } dev->lba_blocks=0; dev->capabilities&=~ATA_CAP_LBA; } void set_irq_occured(__u32 m) { interrupt_occured=m; } void clear_irq_occured(void) { set_irq_occured(0); }