* Acess2 IDE Harddisk Driver
* - main.c
*/
-#define DEBUG 0
+#define DEBUG 1
#include <acess.h>
#include <modules.h>
#include <vfs.h>
void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
// === GLOBALS ===
-MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
+MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, "PCI", NULL);
tDevFS_Driver gATA_DriverInfo = {
NULL, "ata",
{
int ATA_Install()
{
int ret;
-
+
ret = ATA_SetupIO();
- if(ret != 1) return ret;
-
+ if(ret) return ret;
+
ATA_SetupPartitions();
-
+
ATA_SetupVFS();
-
+
if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
- return MODULE_INIT_FAILURE;
-
- return MODULE_INIT_SUCCESS;
+ return MODULE_ERR_MISC;
+
+ return MODULE_ERR_OK;
}
/**
{
int ent;
tPAddr addr;
-
+
ENTER("");
-
+
// Get IDE Controller's PCI Entry
ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
LOG("ent = %i", ent);
gATA_BusMasterBase = PCI_GetBAR4( ent );
if( gATA_BusMasterBase == 0 ) {
Warning("It seems that there is no Bus Master Controller on this machine. Get one");
- LEAVE('i', MODULE_INIT_FAILURE);
- return MODULE_INIT_FAILURE;
+ LEAVE('i', MODULE_ERR_NOTNEEDED);
+ return MODULE_ERR_NOTNEEDED;
}
+
+ // Map memory
if( !(gATA_BusMasterBase & 1) )
{
if( gATA_BusMasterBase < 0x100000 )
// Bit 0 is left set as a flag to other functions
LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
}
-
+
+ // Register IRQs and get Buffers
IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
-
+
gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
-
+
LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
-
+
addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
LOG("addr = 0x%x", addr);
ATA_int_BusMasterWriteDWord(4, addr);
addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
LOG("addr = 0x%x", addr);
ATA_int_BusMasterWriteDWord(12, addr);
-
+
+ // Enable controllers
outb(IDE_PRI_BASE+1, 1);
outb(IDE_SEC_BASE+1, 1);
-
- LEAVE('i', MODULE_INIT_SUCCESS);
- return MODULE_INIT_SUCCESS;
+
+ // return
+ LEAVE('i', MODULE_ERR_OK);
+ return MODULE_ERR_OK;
}
/**
void ATA_SetupVFS()
{
int i, j, k;
-
+
// Count number of nodes needed
giATA_NumNodes = 0;
for( i = 0; i < MAX_ATA_DISKS; i++ )
giATA_NumNodes ++;
giATA_NumNodes += gATA_Disks[i].NumPartitions;
}
-
+
// Allocate Node space
gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
-
+
// Set nodes
k = 0;
for( i = 0; i < MAX_ATA_DISKS; i++ )
for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
}
-
+
gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
}
Uint8 val;
int i;
tVFS_Node *node;
-
+
ENTER("iDisk", Disk);
-
+
base = ATA_GetBasePort( Disk );
-
+
LOG("base = 0x%x", base);
-
+
// Send Disk Selector
if(Disk == 1 || Disk == 3)
outb(base+6, 0xB0);
else
outb(base+6, 0xA0);
-
+
// Send IDENTIFY
outb(base+7, 0xEC);
val = inb(base+7); // Read status
LEAVE('i', 0);
return 0; // Disk does not exist
}
-
+
// Poll until BSY clears and DRQ sets or ERR is set
while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
-
+
if(val & 1) {
LEAVE('i', 0);
return 0; // Error occured, so return false
}
-
+
// Read Data
for(i=0;i<256;i++) buf[i] = inw(base);
-
+
// Populate Disk Structure
if(identify->Sectors48 != 0)
gATA_Disks[ Disk ].Sectors = identify->Sectors48;
else
gATA_Disks[ Disk ].Sectors = identify->Sectors28;
-
-
+
+
LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors);
-
+
if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
else
Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
-
+
// Create Name
gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
gATA_Disks[ Disk ].Name[1] = '\0';
-
+
// Get pointer to vfs node and populate it
node = &gATA_Disks[ Disk ].Node;
node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
node->NumACLs = 0; // Means Superuser only can access it
node->Inode = (Disk << 8) | 0xFF;
node->ImplPtr = gATA_Disks[ Disk ].Name;
-
+
node->ATime = node->MTime
= node->CTime = now();
-
+
node->Read = ATA_ReadFS;
node->Write = ATA_WriteFS;
node->IOCtl = ATA_IOCtl;
LOG("Reading MBR");
// Read Boot Sector
ATA_ReadDMA( Disk, 0, 1, mbr );
-
+
// Check for a GPT table
if(mbr->Parts[0].SystemID == 0xEE)
ATA_ParseGPT(Disk);
else // No? Just parse the MBR
ATA_ParseMBR(Disk);
-
+
LEAVE('i', 0);
return 1;
}
Part->Node.NumACLs = 0; // Only root can read/write raw block devices
Part->Node.Inode = (Disk << 8) | Num;
Part->Node.ImplPtr = Part->Name;
-
+
Part->Node.Read = ATA_ReadFS;
Part->Node.Write = ATA_WriteFS;
Part->Node.IOCtl = ATA_IOCtl;
return NULL;
return &gATA_Disks[Name[0]-'A'].Node;
}
-
+
// Partitions
if(Name[1] < '0' || '9' < Name[1]) return NULL;
if(Name[2] == '\0') { // <= 9
// > 9
if('0' > Name[2] || '9' < Name[2]) return NULL;
if(Name[3] != '\0') return NULL;
-
+
part = (Name[1] - '0') * 10;
part += Name[2] - '0';
part --;
return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
-
+
}
/**
{
int disk = Node->Inode >> 8;
int part = Node->Inode & 0xFF;
-
+
// Raw Disk Access
if(part == 0xFF)
{
Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
}
-
+
//Log("ATA_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
}
{
int disk = Node->Inode >> 8;
int part = Node->Inode & 0xFF;
-
+
// Raw Disk Access
if(part == 0xFF)
{
Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
}
-
+
Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
Debug_HexDump("ATA_WriteFS", Buffer, Length);
return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
int ret;
Uint offset;
Uint done = 0;
-
+
// Pass straight on to ATA_ReadDMAPage if we can
if(Count <= MAX_DMA_SECTORS)
{
if(ret == 0) return 0;
return Count;
}
-
+
// Else we will have to break up the transfer
offset = 0;
while(Count > MAX_DMA_SECTORS)
Count -= MAX_DMA_SECTORS;
offset += MAX_DMA_SECTORS*SECTOR_SIZE;
}
-
+
ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
if(ret != 1) return 0;
return done+Count;
int ret;
Uint offset;
Uint done = 0;
-
+
// Pass straight on to ATA_WriteDMA if we can
if(Count <= MAX_DMA_SECTORS)
{
if(ret == 0) return 0;
return Count;
}
-
+
// Else we will have to break up the transfer
offset = 0;
while(Count > MAX_DMA_SECTORS)
Count -= MAX_DMA_SECTORS;
offset += MAX_DMA_SECTORS*SECTOR_SIZE;
}
-
+
ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
if(ret != 1) return 0;
return done+Count;
int cont = (Disk>>1)&1; // Controller ID
int disk = Disk & 1;
Uint16 base;
-
+
ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
-
+
// Check if the count is small enough
if(Count > MAX_DMA_SECTORS) {
Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
LEAVE('i');
return 0;
}
-
+
// Get exclusive access to the disk controller
LOCK( &giaATA_ControllerLock[ cont ] );
-
+
// Set Size
gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
+
// Get Port Base
base = ATA_GetBasePort(Disk);
-
+
// Reset IRQ Flag
gaATA_IRQs[cont] = 0;
-
+
// Set up transfer
outb(base+0x01, 0x00);
if( Address > 0x0FFFFFFF ) // Use LBA48
{
outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
}
-
+
outb(base+0x02, (Uint8) Count); // Sector Count
outb(base+0x03, (Uint8) Address); // Low Addr
outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
-
+
LOG("Starting Transfer");
#if START_BEFORE_CMD
// Start transfer
// Start transfer
ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
#endif
-
+
// Wait for transfer to complete
//ATA_int_BusMasterWriteByte( (cont << 3) + 2, 0x4 );
while( gaATA_IRQs[cont] == 0 ) {
//LOG("val = 0x%02x", val);
Threads_Yield();
}
-
+
// Complete Transfer
ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
-
+
LOG("Transfer Completed & Acknowledged");
-
+
// Copy to destination buffer
memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-
+
// Release controller lock
RELEASE( &giaATA_ControllerLock[ cont ] );
-
+
LEAVE('i', 1);
return 1;
}
int cont = (Disk>>1)&1; // Controller ID
int disk = Disk & 1;
Uint16 base;
-
+
// Check if the count is small enough
if(Count > MAX_DMA_SECTORS) return 0;
-
+
// Get exclusive access to the disk controller
LOCK( &giaATA_ControllerLock[ cont ] );
-
+
// Set Size
gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
+
// Get Port Base
base = ATA_GetBasePort(Disk);
-
+
// Set up transfer
outb(base+0x01, 0x00);
if( Address > 0x0FFFFFFF ) // Use LBA48
{
outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
}
-
+
outb(base+0x02, (Uint8) Count); // Sector Count
outb(base+0x03, (Uint8) Address); // Low Addr
outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
else
outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
-
+
// Reset IRQ Flag
gaATA_IRQs[cont] = 0;
-
+
// Copy to output buffer
memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
-
+
// Start transfer
ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
-
+
// Wait for transfer to complete
while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
-
+
// Complete Transfer
ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
-
+
// Release controller lock
RELEASE( &giaATA_ControllerLock[ cont ] );
-
+
return 1;
}
void ATA_IRQHandlerPri(int unused)
{
Uint8 val;
-
+
// IRQ bit set for Primary Controller
val = ATA_int_BusMasterReadByte( 0x2 );
LOG("IRQ val = 0x%x", val);
Uint8 val;
// IRQ bit set for Secondary Controller
val = ATA_int_BusMasterReadByte( 0xA );
+ LOG("IRQ val = 0x%x", val);
if(val & 4) {
LOG("IRQ hit (val = 0x%x)", val);
ATA_int_BusMasterWriteByte( 0xA, 4 );
*/
void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
{
-
+
if( gATA_BusMasterBase & 1 )
outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
else