2 * Acess2 Kernel - AHCI Driver
3 * - By John Hodge (thePowersGang)
16 #define MAX_CONTROLLERS 4
19 int AHCI_Install(char **Arguments);
20 int AHCI_Cleanup(void);
23 MODULE_DEFINE(0, VERSION, AHCI, AHCI_Install, AHCI_Cleanup, "LVM", NULL);
24 tAHCI_Ctrlr gaAHCI_Controllers[MAX_CONTROLLERS];
27 int AHCI_Install(char **Arguments)
30 LOG("offsetof(struct sAHCI_MemSpace, Ports) = %x", offsetof(struct sAHCI_MemSpace, Ports));
31 ASSERT( offsetof(struct sAHCI_MemSpace, Ports) == 0x100 );
33 // 0106XX = Standard, 010400 = RAID
36 while( (id = PCI_GetDeviceByClass(0x010601, 0xFFFFFF, id)) >= 0 && i < MAX_CONTROLLERS )
38 tAHCI_Ctrlr *ctrlr = &gaAHCI_Controllers[i];
39 ctrlr->PMemBase = PCI_GetBAR(id, 5);
41 if( !ctrlr->PMemBase )
43 // ctrlr->PMemBase = PCI_AllocateBAR(id, 5);
44 // TODO: Allocate space
48 if( (ctrlr->PMemBase & 0x1FFF) ) {
49 Log_Warning("AHCI", "Controller %i [PCI %i] is invalid (BAR5=%P)",
50 i, id, ctrlr->PMemBase);
54 ctrlr->IRQ = PCI_GetIRQ(id);
56 // Prepare MMIO (two pages according to the spec)
57 ctrlr->MMIO = (void*)MM_MapHWPages(ctrlr->PMemBase, 2);
59 LOG("%i [%i]: %P/IRQ%i mapped to %p",
60 i, id, ctrlr->PMemBase, ctrlr->IRQ, ctrlr->MMIO);
62 LOG(" CAP = %x, PI = %x, VS = %x",
63 ctrlr->MMIO->CAP, ctrlr->MMIO->PI, ctrlr->MMIO->VS);
68 Log_Notice("AHCI", "Only up to %i controllers are supported", MAX_CONTROLLERS);
74 int AHCI_Cleanup(void)
79 int AHCI_InitSys(tAHCI_Ctrlr *Ctrlr)
82 Ctrlr->MMIO->GHC |= AHCI_GHC_AE;
83 // 2. Enumerate ports using PI
84 // 3. (for each port) Ensure that port is not running
85 // - if PxCMD.(ST|CR|FRE|FR) all are clear, port is idle
86 // - Idle is set by clearing PxCMD.ST and waiting for .CR to clear (timeout 500ms)
87 // - AND .FRE = 0, checking .FR (timeout 500ms again)
88 // > On timeout, port/HBA reset
90 // 5. Allocate PxCLB and PxFB for each port (setting PxCMD.FRE once done)
91 // 6. Clear PxSERR with 1 to each implimented bit
92 // > Clear PxIS then IS.IPS before setting PxIE/GHC.IE
93 // 7. Set PxIE with desired interrupts and set GHC.IE
95 // Detect present ports using:
96 // > PxTFD.STS.BSY = 0, PxTFD.STS.DRQ = 0, and PxSSTS.DET = 3