+++ /dev/null
-/*
- * Acess2 IDE Harddisk Driver
- * drv/ide.c
- */
-#define DEBUG 0
-#include <acess.h>
-#include <modules.h>
-#include <vfs.h>
-#include <fs_devfs.h>
-#include <drv_pci.h>
-#include <tpl_drv_common.h>
-#include <tpl_drv_disk.h>
-
-// --- Flags ---
-#define START_BEFORE_CMD 0
-
-// === CONSTANTS ===
-#define MAX_ATA_DISKS 4
-#define SECTOR_SIZE 512
-#define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
-
-#define IDE_PRI_BASE 0x1F0
-#define IDE_SEC_BASE 0x170
-
-#define IDE_PRDT_LAST 0x8000
-/**
- \enum HddControls
- \brief Commands to be sent to HDD_CMD
-*/
-enum HddControls {
- HDD_PIO_R28 = 0x20,
- HDD_PIO_R48 = 0x24,
- HDD_DMA_R48 = 0x25,
- HDD_PIO_W28 = 0x30,
- HDD_PIO_W48 = 0x34,
- HDD_DMA_W48 = 0x35,
- HDD_DMA_R28 = 0xC8,
- HDD_DMA_W28 = 0xCA,
-};
-
-// === STRUCTURES ===
-typedef struct {
- Uint32 PBufAddr;
- Uint16 Bytes;
- Uint16 Flags;
-} tPRDT_Ent;
-typedef struct {
- Uint16 Flags; // 1
- Uint16 Usused1[9]; // 10
- char SerialNum[20]; // 20
- Uint16 Usused2[3]; // 23
- char FirmwareVer[8]; // 27
- char ModelNumber[40]; // 47
- Uint16 SectPerInt; // 48 - and with 0xFF to get true value;
- Uint16 Unused3; // 49
- Uint16 Capabilities[2]; // 51
- Uint16 Unused4[2]; // 53
- Uint16 ValidExtData; // 54
- Uint16 Unused5[5]; // 59
- Uint16 SizeOfRWMultiple; // 60
- Uint32 Sectors28; // 62
- Uint16 Unused6[100-62];
- Uint64 Sectors48;
- Uint16 Unused7[256-104];
-} tIdentify;
-typedef struct {
- Uint8 BootCode[0x1BE];
- struct {
- Uint8 Boot;
- Uint8 Unused1; // Also CHS Start
- Uint16 StartHi; // Also CHS Start
- Uint8 SystemID;
- Uint8 Unused2; // Also CHS Length
- Uint16 LengthHi; // Also CHS Length
- Uint32 LBAStart;
- Uint32 LBALength;
- } __attribute__ ((packed)) Parts[4];
- Uint16 BootFlag; // = 0xAA 55
-} __attribute__ ((packed)) tMBR;
-
-typedef struct {
- Uint64 Start;
- Uint64 Length;
- char Name[4];
- tVFS_Node Node;
-} tATA_Partition;
-typedef struct {
- Uint64 Sectors;
- char Name[2];
- tVFS_Node Node;
- int NumPartitions;
- tATA_Partition *Partitions;
-} tATA_Disk;
-
-// === PROTOTYPES ===
- int ATA_Install();
- int ATA_SetupIO();
-void ATA_SetupPartitions();
-void ATA_SetupVFS();
- int ATA_ScanDisk(int Disk);
-void ATA_ParseGPT(int Disk);
-void ATA_ParseMBR(int Disk);
-void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
-Uint16 ATA_GetBasePort(int Disk);
-// Filesystem Interface
-char *ATA_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
-Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
- int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
-// Read/Write Interface/Quantiser
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
-// Read/Write DMA
- int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
- int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
-// IRQs
-void ATA_IRQHandlerPri(int unused);
-void ATA_IRQHandlerSec(int unused);
-// Controller IO
-Uint8 ATA_int_BusMasterReadByte(int Ofs);
-void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
-void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
-tDevFS_Driver gATA_DriverInfo = {
- NULL, "ata",
- {
- .NumACLs = 1,
- .Size = -1,
- .Flags = VFS_FFLAG_DIRECTORY,
- .ACLs = &gVFS_ACL_EveryoneRX,
- .ReadDir = ATA_ReadDir,
- .FindDir = ATA_FindDir
- }
-};
-tATA_Disk gATA_Disks[MAX_ATA_DISKS];
- int giATA_NumNodes;
-tVFS_Node **gATA_Nodes;
-Uint16 gATA_BusMasterBase = 0;
-Uint8 *gATA_BusMasterBasePtr = 0;
- int gATA_IRQPri = 14;
- int gATA_IRQSec = 15;
- int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
-Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
- int gaATA_IRQs[2] = {0};
-tPRDT_Ent gATA_PRDTs[2] = {
- {0, 512, IDE_PRDT_LAST},
- {0, 512, IDE_PRDT_LAST}
-};
-
-// === CODE ===
-/**
- * \fn int ATA_Install()
- */
-int ATA_Install()
-{
- int ret;
-
- ret = ATA_SetupIO();
- if(ret != 1) return ret;
-
- ATA_SetupPartitions();
-
- ATA_SetupVFS();
-
- if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
- return MODULE_INIT_FAILURE;
-
- return MODULE_INIT_SUCCESS;
-}
-
-/**
- * \fn int ATA_SetupIO()
- * \brief Sets up the ATA controller's DMA mode
- */
-int ATA_SetupIO()
-{
- 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;
- }
- if( !(gATA_BusMasterBase & 1) )
- {
- if( gATA_BusMasterBase < 0x100000 )
- gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
- else
- gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
- LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
- }
- else {
- // Bit 0 is left set as a flag to other functions
- LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
- }
-
- 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);
-
- outb(IDE_PRI_BASE+1, 1);
- outb(IDE_SEC_BASE+1, 1);
-
- LEAVE('i', MODULE_INIT_SUCCESS);
- return MODULE_INIT_SUCCESS;
-}
-
-/**
- * \fn void ATA_SetupPartitions()
- */
-void ATA_SetupPartitions()
-{
- int i;
- for( i = 0; i < MAX_ATA_DISKS; i ++ )
- {
- if( !ATA_ScanDisk(i) ) {
- gATA_Disks[i].Name[0] = '\0'; // Mark as unused
- continue;
- }
- }
-}
-
-/**
- * \fn void ATA_SetupVFS()
- * \brief Sets up the ATA drivers VFS information and registers with DevFS
- */
-void ATA_SetupVFS()
-{
- int i, j, k;
-
- // Count number of nodes needed
- giATA_NumNodes = 0;
- for( i = 0; i < MAX_ATA_DISKS; i++ )
- {
- if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
- 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++ )
- {
- if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
- gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
- for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
- gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
- }
-
- gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
-}
-
-/**
- * \fn int ATA_ScanDisk(int Disk)
- */
-int ATA_ScanDisk(int Disk)
-{
- Uint16 buf[256];
- tIdentify *identify = (void*)buf;
- tMBR *mbr = (void*)buf;
- Uint16 base;
- 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
- if(val == 0) {
- 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 if( gATA_Disks[ Disk ].Sectors / 2048 )
- Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
- gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
- 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;
-
-
- // --- Scan Partitions ---
- 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;
-}
-
-/**
- * \fn void ATA_ParseGPT(int Disk)
- * \brief Parses the GUID Partition Table
- */
-void ATA_ParseGPT(int Disk)
-{
- ///\todo Support GPT Disks
- Warning("GPT Disks are currently unsupported");
-}
-
-/**
- * \fn void ATA_ParseMBR(int Disk)
- */
-void ATA_ParseMBR(int Disk)
-{
- int i, j = 0, k = 4;
- tMBR mbr;
- Uint64 extendedLBA;
-
- ENTER("iDisk", Disk);
-
- // Read Boot Sector
- ATA_ReadDMA( Disk, 0, 1, &mbr );
-
- // Count Partitions
- gATA_Disks[Disk].NumPartitions = 0;
- extendedLBA = 0;
- for( i = 0; i < 4; i ++ )
- {
- if( mbr.Parts[i].SystemID == 0 ) continue;
- if(
- mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28
- || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48
- )
- {
- if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
- LOG("Extended Partition");
- if(extendedLBA != 0) {
- Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = mbr.Parts[i].LBAStart;
- continue;
- }
- LOG("Primary Partition");
-
- gATA_Disks[Disk].NumPartitions ++;
- continue;
- }
- // Invalid Partition, so don't count it
- }
- while(extendedLBA != 0)
- {
- if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
- break; // Stop on Errors
-
- extendedLBA = 0;
-
- if( mbr.Parts[0].SystemID == 0 ) continue;
- if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28
- || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48
- )
- {
- if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
- extendedLBA = mbr.Parts[0].LBAStart;
- else
- gATA_Disks[Disk].NumPartitions ++;
- }
-
- if( mbr.Parts[1].SystemID == 0 ) continue;
- if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28
- || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48
- )
- {
- if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
- if(extendedLBA == 0) {
- Warning("Disk %i has twp forward link in the extended partition",
- Disk);
- break;
- }
- extendedLBA = mbr.Parts[1].LBAStart;
- }
- else {
- if(extendedLBA != 0) {
- Warning("Disk %i lacks a forward link in the extended partition",
- Disk);
- break;
- }
- gATA_Disks[Disk].NumPartitions ++;
- }
- }
- }
- LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
-
- // Create patition array
- gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
-
- // --- Fill Partition Info ---
- extendedLBA = 0;
- for( i = 0; i < 4; i ++ )
- {
- Log("mbr.Parts[%i].SystemID = 0x%02x", i, mbr.Parts[i].SystemID);
- if( mbr.Parts[i].SystemID == 0 ) continue;
- if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
- {
- if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
- if(extendedLBA != 0) {
- Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = mbr.Parts[1].LBAStart;
- continue;
- }
- // Create Partition
- ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
- mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
- );
- j ++;
- continue;
- }
- if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
- {
- if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
- if(extendedLBA != 0) {
- Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
- continue;
- }
- ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
- (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
- (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
- );
- j ++;
- }
- // Invalid Partition, so don't count it
- }
- // Scan extended partition
- while(extendedLBA != 0)
- {
- if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
- break; // Stop on Errors
-
- extendedLBA = 0;
-
- // Check first entry (should be partition)
- if( mbr.Parts[0].SystemID != 0)
- {
- if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28
- {
- // Forward Link to next Extended partition entry
- if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
- extendedLBA = mbr.Parts[0].LBAStart;
- else {
- ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
- mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
- );
- j ++; k ++;
- }
- }
- else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48
- {
- if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
- extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
- else {
- ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
- (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
- (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
- );
- j ++; k ++;
- }
- }
- }
-
- // Check second entry (should be forward link)
- if( mbr.Parts[1].SystemID != 0)
- {
- if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28
- {
- if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
- if(extendedLBA == 0) {
- Warning("Disk %i has twp forward link in the extended partition",
- Disk);
- break;
- }
- extendedLBA = mbr.Parts[1].LBAStart;
- }
- else
- {
- if(extendedLBA != 0) {
- Warning("Disk %i lacks a forward link in the extended partition",
- Disk);
- break;
- }
- ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
- mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
- );
- j ++; k ++;
- }
-
- }
- else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48
- {
- if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
- if(extendedLBA == 0) {
- Warning("Disk %i has twp forward link in the extended partition",
- Disk);
- break;
- }
- extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
- }
- else
- {
- if(extendedLBA != 0) {
- Warning("Disk %i lacks a forward link in the extended partition",
- Disk);
- break;
- }
- ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
- (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
- (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
- );
- j ++; k ++;
- }
- }
- }
- }
-
- LEAVE('-');
-}
-
-/**
- * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
- * \brief Fills a parition's information structure
- */
-void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
-{
- ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
- Part->Start = Start;
- Part->Length = Length;
- Part->Name[0] = 'A'+Disk;
- if(Num >= 10) {
- Part->Name[1] = '1'+Num/10;
- Part->Name[2] = '1'+Num%10;
- Part->Name[3] = '\0';
- } else {
- Part->Name[1] = '1'+Num;
- Part->Name[2] = '\0';
- }
- 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;
- LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
- LEAVE('-');
-}
-
-/**
- * \fn Uint16 ATA_GetPortBase(int Disk)
- * \brief Returns the base port for a given disk
- */
-Uint16 ATA_GetBasePort(int Disk)
-{
- switch(Disk)
- {
- case 0: case 1: return IDE_PRI_BASE;
- case 2: case 3: return IDE_SEC_BASE;
- }
- return 0;
-}
-
-/**
- * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
- */
-char *ATA_ReadDir(tVFS_Node *Node, int Pos)
-{
- if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
- return strdup( gATA_Nodes[Pos]->ImplPtr );
-}
-
-/**
- * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
- */
-tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
-{
- int part;
- // Check first character
- if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
- return NULL;
- // Raw Disk
- if(Name[1] == '\0') {
- if( gATA_Disks[Name[0]-'A'].Sectors == 0 )
- return NULL;
- return &gATA_Disks[Name[0]-'A'].Node;
- }
-
- // Partitions
- if(Name[1] < '0' || '9' < Name[1]) return NULL;
- if(Name[2] == '\0') { // <= 9
- part = Name[1] - '0';
- part --;
- return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
- }
- // > 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;
-
-}
-
-/**
- * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- */
-Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
- int disk = Node->Inode >> 8;
- int part = Node->Inode & 0xFF;
-
- // Raw Disk Access
- if(part == 0xFF)
- {
- if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
- return 0;
- if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
- Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
- }
- // Partition
- else
- {
- if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- return 0;
- if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- 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);
-}
-
-/**
- * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- */
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
- int disk = Node->Inode >> 8;
- int part = Node->Inode & 0xFF;
-
- // Raw Disk Access
- if(part == 0xFF)
- {
- if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
- return 0;
- if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
- Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
- }
- // Partition
- else
- {
- if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- return 0;
- if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- 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);
-}
-
-/**
- * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief IO Control Funtion
- */
-int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
- switch(Id)
- {
- case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
- }
- return 0;
-}
-
-// --- Disk Access ---
-/**
- * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
- */
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
-{
- int ret;
- Uint offset;
- Uint done = 0;
-
- // Pass straight on to ATA_ReadDMAPage if we can
- if(Count <= MAX_DMA_SECTORS)
- {
- ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
- if(ret == 0) return 0;
- return Count;
- }
-
- // Else we will have to break up the transfer
- offset = 0;
- while(Count > MAX_DMA_SECTORS)
- {
- ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
- // Check for errors
- if(ret != 1) return done;
- // Change Position
- done += 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;
-}
-
-/**
- * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
- */
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
-{
- int ret;
- Uint offset;
- Uint done = 0;
-
- // Pass straight on to ATA_WriteDMA if we can
- if(Count <= MAX_DMA_SECTORS)
- {
- ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
- if(ret == 0) return 0;
- return Count;
- }
-
- // Else we will have to break up the transfer
- offset = 0;
- while(Count > MAX_DMA_SECTORS)
- {
- ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
- // Check for errors
- if(ret != 1) return done;
- // Change Position
- done += 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;
-}
-
-/**
- * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- */
-int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
-{
- 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)",
- Count, MAX_DMA_SECTORS);
- 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+0x6, 0x40 | (disk << 4));
- outb(base+0x2, 0 >> 8); // Upper Sector Count
- outb(base+0x3, Address >> 24); // Low 2 Addr
- outb(base+0x3, Address >> 28); // Mid 2 Addr
- outb(base+0x3, Address >> 32); // High 2 Addr
- }
- else
- {
- 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
- ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
- if( Address > 0x0FFFFFFF )
- outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
- else
- outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
- #else
- if( Address > 0x0FFFFFFF )
- outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
- else
- outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
- // 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 ) {
- //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 );
- //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;
-}
-
-/**
- * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- */
-int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
-{
- 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+0x6, 0x40 | (disk << 4));
- outb(base+0x2, 0 >> 8); // Upper Sector Count
- outb(base+0x3, Address >> 24); // Low 2 Addr
- outb(base+0x3, Address >> 28); // Mid 2 Addr
- outb(base+0x3, Address >> 32); // High 2 Addr
- }
- else
- {
- 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
- if( Address > 0x0FFFFFFF )
- 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;
-}
-
-/**
- * \fn void ATA_IRQHandlerPri(int unused)
- */
-void ATA_IRQHandlerPri(int unused)
-{
- Uint8 val;
-
- // IRQ bit set for Primary Controller
- val = ATA_int_BusMasterReadByte( 0x2 );
- LOG("IRQ val = 0x%x", val);
- if(val & 4) {
- LOG("IRQ hit (val = 0x%x)", val);
- ATA_int_BusMasterWriteByte( 0x2, 4 );
- gaATA_IRQs[0] = 1;
- return ;
- }
-}
-
-/**
- * \fn void ATA_IRQHandlerSec(int unused)
- */
-void ATA_IRQHandlerSec(int unused)
-{
- Uint8 val;
- // IRQ bit set for Secondary Controller
- val = ATA_int_BusMasterReadByte( 0xA );
- if(val & 4) {
- LOG("IRQ hit (val = 0x%x)", val);
- ATA_int_BusMasterWriteByte( 0xA, 4 );
- gaATA_IRQs[1] = 1;
- return ;
- }
-}
-
-/**
- * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
- */
-Uint8 ATA_int_BusMasterReadByte(int Ofs)
-{
- if( gATA_BusMasterBase & 1 )
- return inb( (gATA_BusMasterBase & ~1) + Ofs );
- else
- return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
-}
-
-/**
- * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
- * \brief Writes a byte to a Bus Master Register
- */
-void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
-{
- if( gATA_BusMasterBase & 1 )
- outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
- else
- *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
-}
-
-/**
- * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
- * \brief Writes a dword to a Bus Master Register
- */
-void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
-{
-
- if( gATA_BusMasterBase & 1 )
- outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
- else
- *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
-}
--- /dev/null
+/*
+ * Acess2 IDE Harddisk Driver
+ * - main.c
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <modules.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include <tpl_drv_common.h>
+#include <tpl_drv_disk.h>
+
+// --- Flags ---
+#define START_BEFORE_CMD 0
+
+// === CONSTANTS ===
+#define MAX_ATA_DISKS 4
+#define SECTOR_SIZE 512
+#define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
+
+#define IDE_PRI_BASE 0x1F0
+#define IDE_SEC_BASE 0x170
+
+#define IDE_PRDT_LAST 0x8000
+/**
+ \enum HddControls
+ \brief Commands to be sent to HDD_CMD
+*/
+enum HddControls {
+ HDD_PIO_R28 = 0x20,
+ HDD_PIO_R48 = 0x24,
+ HDD_DMA_R48 = 0x25,
+ HDD_PIO_W28 = 0x30,
+ HDD_PIO_W48 = 0x34,
+ HDD_DMA_W48 = 0x35,
+ HDD_DMA_R28 = 0xC8,
+ HDD_DMA_W28 = 0xCA,
+};
+
+// === STRUCTURES ===
+typedef struct {
+ Uint32 PBufAddr;
+ Uint16 Bytes;
+ Uint16 Flags;
+} tPRDT_Ent;
+typedef struct {
+ Uint16 Flags; // 1
+ Uint16 Usused1[9]; // 10
+ char SerialNum[20]; // 20
+ Uint16 Usused2[3]; // 23
+ char FirmwareVer[8]; // 27
+ char ModelNumber[40]; // 47
+ Uint16 SectPerInt; // 48 - and with 0xFF to get true value;
+ Uint16 Unused3; // 49
+ Uint16 Capabilities[2]; // 51
+ Uint16 Unused4[2]; // 53
+ Uint16 ValidExtData; // 54
+ Uint16 Unused5[5]; // 59
+ Uint16 SizeOfRWMultiple; // 60
+ Uint32 Sectors28; // 62
+ Uint16 Unused6[100-62];
+ Uint64 Sectors48;
+ Uint16 Unused7[256-104];
+} tIdentify;
+typedef struct {
+ Uint8 BootCode[0x1BE];
+ struct {
+ Uint8 Boot;
+ Uint8 Unused1; // Also CHS Start
+ Uint16 StartHi; // Also CHS Start
+ Uint8 SystemID;
+ Uint8 Unused2; // Also CHS Length
+ Uint16 LengthHi; // Also CHS Length
+ Uint32 LBAStart;
+ Uint32 LBALength;
+ } __attribute__ ((packed)) Parts[4];
+ Uint16 BootFlag; // = 0xAA 55
+} __attribute__ ((packed)) tMBR;
+
+typedef struct {
+ Uint64 Start;
+ Uint64 Length;
+ char Name[4];
+ tVFS_Node Node;
+} tATA_Partition;
+typedef struct {
+ Uint64 Sectors;
+ char Name[2];
+ tVFS_Node Node;
+ int NumPartitions;
+ tATA_Partition *Partitions;
+} tATA_Disk;
+
+// === PROTOTYPES ===
+ int ATA_Install();
+ int ATA_SetupIO();
+void ATA_SetupPartitions();
+void ATA_SetupVFS();
+ int ATA_ScanDisk(int Disk);
+void ATA_ParseGPT(int Disk);
+void ATA_ParseMBR(int Disk);
+void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
+Uint16 ATA_GetBasePort(int Disk);
+// Filesystem Interface
+char *ATA_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
+Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
+// Read/Write Interface/Quantiser
+Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+// Read/Write DMA
+ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
+ int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
+// IRQs
+void ATA_IRQHandlerPri(int unused);
+void ATA_IRQHandlerSec(int unused);
+// Controller IO
+Uint8 ATA_int_BusMasterReadByte(int Ofs);
+void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
+void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
+tDevFS_Driver gATA_DriverInfo = {
+ NULL, "ata",
+ {
+ .NumACLs = 1,
+ .Size = -1,
+ .Flags = VFS_FFLAG_DIRECTORY,
+ .ACLs = &gVFS_ACL_EveryoneRX,
+ .ReadDir = ATA_ReadDir,
+ .FindDir = ATA_FindDir
+ }
+};
+tATA_Disk gATA_Disks[MAX_ATA_DISKS];
+ int giATA_NumNodes;
+tVFS_Node **gATA_Nodes;
+Uint16 gATA_BusMasterBase = 0;
+Uint8 *gATA_BusMasterBasePtr = 0;
+ int gATA_IRQPri = 14;
+ int gATA_IRQSec = 15;
+ int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
+Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
+ int gaATA_IRQs[2] = {0};
+tPRDT_Ent gATA_PRDTs[2] = {
+ {0, 512, IDE_PRDT_LAST},
+ {0, 512, IDE_PRDT_LAST}
+};
+
+// === CODE ===
+/**
+ * \fn int ATA_Install()
+ */
+int ATA_Install()
+{
+ int ret;
+
+ ret = ATA_SetupIO();
+ if(ret != 1) return ret;
+
+ ATA_SetupPartitions();
+
+ ATA_SetupVFS();
+
+ if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
+ return MODULE_INIT_FAILURE;
+
+ return MODULE_INIT_SUCCESS;
+}
+
+/**
+ * \fn int ATA_SetupIO()
+ * \brief Sets up the ATA controller's DMA mode
+ */
+int ATA_SetupIO()
+{
+ 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;
+ }
+ if( !(gATA_BusMasterBase & 1) )
+ {
+ if( gATA_BusMasterBase < 0x100000 )
+ gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
+ else
+ gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
+ LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
+ }
+ else {
+ // Bit 0 is left set as a flag to other functions
+ LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
+ }
+
+ 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);
+
+ outb(IDE_PRI_BASE+1, 1);
+ outb(IDE_SEC_BASE+1, 1);
+
+ LEAVE('i', MODULE_INIT_SUCCESS);
+ return MODULE_INIT_SUCCESS;
+}
+
+/**
+ * \fn void ATA_SetupPartitions()
+ */
+void ATA_SetupPartitions()
+{
+ int i;
+ for( i = 0; i < MAX_ATA_DISKS; i ++ )
+ {
+ if( !ATA_ScanDisk(i) ) {
+ gATA_Disks[i].Name[0] = '\0'; // Mark as unused
+ continue;
+ }
+ }
+}
+
+/**
+ * \fn void ATA_SetupVFS()
+ * \brief Sets up the ATA drivers VFS information and registers with DevFS
+ */
+void ATA_SetupVFS()
+{
+ int i, j, k;
+
+ // Count number of nodes needed
+ giATA_NumNodes = 0;
+ for( i = 0; i < MAX_ATA_DISKS; i++ )
+ {
+ if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
+ 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++ )
+ {
+ if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
+ gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
+ for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
+ gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
+ }
+
+ gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
+}
+
+/**
+ * \fn int ATA_ScanDisk(int Disk)
+ */
+int ATA_ScanDisk(int Disk)
+{
+ Uint16 buf[256];
+ tIdentify *identify = (void*)buf;
+ tMBR *mbr = (void*)buf;
+ Uint16 base;
+ 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
+ if(val == 0) {
+ 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 if( gATA_Disks[ Disk ].Sectors / 2048 )
+ Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
+ gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
+ 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;
+
+
+ // --- Scan Partitions ---
+ 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;
+}
+
+/**
+ * \fn void ATA_ParseGPT(int Disk)
+ * \brief Parses the GUID Partition Table
+ */
+void ATA_ParseGPT(int Disk)
+{
+ ///\todo Support GPT Disks
+ Warning("GPT Disks are currently unsupported");
+}
+
+/**
+ * \fn void ATA_ParseMBR(int Disk)
+ */
+void ATA_ParseMBR(int Disk)
+{
+ int i, j = 0, k = 4;
+ tMBR mbr;
+ Uint64 extendedLBA;
+
+ ENTER("iDisk", Disk);
+
+ // Read Boot Sector
+ ATA_ReadDMA( Disk, 0, 1, &mbr );
+
+ // Count Partitions
+ gATA_Disks[Disk].NumPartitions = 0;
+ extendedLBA = 0;
+ for( i = 0; i < 4; i ++ )
+ {
+ if( mbr.Parts[i].SystemID == 0 ) continue;
+ if(
+ mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28
+ || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48
+ )
+ {
+ if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
+ LOG("Extended Partition");
+ if(extendedLBA != 0) {
+ Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+ continue;
+ }
+ extendedLBA = mbr.Parts[i].LBAStart;
+ continue;
+ }
+ LOG("Primary Partition");
+
+ gATA_Disks[Disk].NumPartitions ++;
+ continue;
+ }
+ // Invalid Partition, so don't count it
+ }
+ while(extendedLBA != 0)
+ {
+ if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
+ break; // Stop on Errors
+
+ extendedLBA = 0;
+
+ if( mbr.Parts[0].SystemID == 0 ) continue;
+ if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28
+ || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48
+ )
+ {
+ if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
+ extendedLBA = mbr.Parts[0].LBAStart;
+ else
+ gATA_Disks[Disk].NumPartitions ++;
+ }
+
+ if( mbr.Parts[1].SystemID == 0 ) continue;
+ if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28
+ || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48
+ )
+ {
+ if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
+ if(extendedLBA == 0) {
+ Warning("Disk %i has twp forward link in the extended partition",
+ Disk);
+ break;
+ }
+ extendedLBA = mbr.Parts[1].LBAStart;
+ }
+ else {
+ if(extendedLBA != 0) {
+ Warning("Disk %i lacks a forward link in the extended partition",
+ Disk);
+ break;
+ }
+ gATA_Disks[Disk].NumPartitions ++;
+ }
+ }
+ }
+ LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
+
+ // Create patition array
+ gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
+
+ // --- Fill Partition Info ---
+ extendedLBA = 0;
+ for( i = 0; i < 4; i ++ )
+ {
+ Log("mbr.Parts[%i].SystemID = 0x%02x", i, mbr.Parts[i].SystemID);
+ if( mbr.Parts[i].SystemID == 0 ) continue;
+ if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
+ {
+ if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
+ if(extendedLBA != 0) {
+ Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+ continue;
+ }
+ extendedLBA = mbr.Parts[1].LBAStart;
+ continue;
+ }
+ // Create Partition
+ ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
+ mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
+ );
+ j ++;
+ continue;
+ }
+ if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
+ {
+ if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
+ if(extendedLBA != 0) {
+ Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+ continue;
+ }
+ extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
+ continue;
+ }
+ ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
+ (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
+ (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
+ );
+ j ++;
+ }
+ // Invalid Partition, so don't count it
+ }
+ // Scan extended partition
+ while(extendedLBA != 0)
+ {
+ if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
+ break; // Stop on Errors
+
+ extendedLBA = 0;
+
+ // Check first entry (should be partition)
+ if( mbr.Parts[0].SystemID != 0)
+ {
+ if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28
+ {
+ // Forward Link to next Extended partition entry
+ if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
+ extendedLBA = mbr.Parts[0].LBAStart;
+ else {
+ ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+ mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
+ );
+ j ++; k ++;
+ }
+ }
+ else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48
+ {
+ if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
+ extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
+ else {
+ ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+ (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
+ (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
+ );
+ j ++; k ++;
+ }
+ }
+ }
+
+ // Check second entry (should be forward link)
+ if( mbr.Parts[1].SystemID != 0)
+ {
+ if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28
+ {
+ if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
+ if(extendedLBA == 0) {
+ Warning("Disk %i has twp forward link in the extended partition",
+ Disk);
+ break;
+ }
+ extendedLBA = mbr.Parts[1].LBAStart;
+ }
+ else
+ {
+ if(extendedLBA != 0) {
+ Warning("Disk %i lacks a forward link in the extended partition",
+ Disk);
+ break;
+ }
+ ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+ mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
+ );
+ j ++; k ++;
+ }
+
+ }
+ else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48
+ {
+ if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
+ if(extendedLBA == 0) {
+ Warning("Disk %i has twp forward link in the extended partition",
+ Disk);
+ break;
+ }
+ extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
+ }
+ else
+ {
+ if(extendedLBA != 0) {
+ Warning("Disk %i lacks a forward link in the extended partition",
+ Disk);
+ break;
+ }
+ ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+ (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
+ (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
+ );
+ j ++; k ++;
+ }
+ }
+ }
+ }
+
+ LEAVE('-');
+}
+
+/**
+ * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
+ * \brief Fills a parition's information structure
+ */
+void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
+{
+ ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
+ Part->Start = Start;
+ Part->Length = Length;
+ Part->Name[0] = 'A'+Disk;
+ if(Num >= 10) {
+ Part->Name[1] = '1'+Num/10;
+ Part->Name[2] = '1'+Num%10;
+ Part->Name[3] = '\0';
+ } else {
+ Part->Name[1] = '1'+Num;
+ Part->Name[2] = '\0';
+ }
+ 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;
+ LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
+ LEAVE('-');
+}
+
+/**
+ * \fn Uint16 ATA_GetPortBase(int Disk)
+ * \brief Returns the base port for a given disk
+ */
+Uint16 ATA_GetBasePort(int Disk)
+{
+ switch(Disk)
+ {
+ case 0: case 1: return IDE_PRI_BASE;
+ case 2: case 3: return IDE_SEC_BASE;
+ }
+ return 0;
+}
+
+/**
+ * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
+ */
+char *ATA_ReadDir(tVFS_Node *Node, int Pos)
+{
+ if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
+ return strdup( gATA_Nodes[Pos]->ImplPtr );
+}
+
+/**
+ * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
+ */
+tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
+{
+ int part;
+ // Check first character
+ if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
+ return NULL;
+ // Raw Disk
+ if(Name[1] == '\0') {
+ if( gATA_Disks[Name[0]-'A'].Sectors == 0 )
+ return NULL;
+ return &gATA_Disks[Name[0]-'A'].Node;
+ }
+
+ // Partitions
+ if(Name[1] < '0' || '9' < Name[1]) return NULL;
+ if(Name[2] == '\0') { // <= 9
+ part = Name[1] - '0';
+ part --;
+ return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
+ }
+ // > 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;
+
+}
+
+/**
+ * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ */
+Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ int disk = Node->Inode >> 8;
+ int part = Node->Inode & 0xFF;
+
+ // Raw Disk Access
+ if(part == 0xFF)
+ {
+ if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
+ return 0;
+ if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
+ Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
+ }
+ // Partition
+ else
+ {
+ if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+ return 0;
+ if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+ 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);
+}
+
+/**
+ * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ */
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ int disk = Node->Inode >> 8;
+ int part = Node->Inode & 0xFF;
+
+ // Raw Disk Access
+ if(part == 0xFF)
+ {
+ if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
+ return 0;
+ if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
+ Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
+ }
+ // Partition
+ else
+ {
+ if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+ return 0;
+ if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+ 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);
+}
+
+/**
+ * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief IO Control Funtion
+ */
+int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+ switch(Id)
+ {
+ case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
+ }
+ return 0;
+}
+
+// --- Disk Access ---
+/**
+ * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ */
+Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+{
+ int ret;
+ Uint offset;
+ Uint done = 0;
+
+ // Pass straight on to ATA_ReadDMAPage if we can
+ if(Count <= MAX_DMA_SECTORS)
+ {
+ ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
+ if(ret == 0) return 0;
+ return Count;
+ }
+
+ // Else we will have to break up the transfer
+ offset = 0;
+ while(Count > MAX_DMA_SECTORS)
+ {
+ ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
+ // Check for errors
+ if(ret != 1) return done;
+ // Change Position
+ done += 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;
+}
+
+/**
+ * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ */
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+{
+ int ret;
+ Uint offset;
+ Uint done = 0;
+
+ // Pass straight on to ATA_WriteDMA if we can
+ if(Count <= MAX_DMA_SECTORS)
+ {
+ ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
+ if(ret == 0) return 0;
+ return Count;
+ }
+
+ // Else we will have to break up the transfer
+ offset = 0;
+ while(Count > MAX_DMA_SECTORS)
+ {
+ ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
+ // Check for errors
+ if(ret != 1) return done;
+ // Change Position
+ done += 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;
+}
+
+/**
+ * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ */
+int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+ 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)",
+ Count, MAX_DMA_SECTORS);
+ 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+0x6, 0x40 | (disk << 4));
+ outb(base+0x2, 0 >> 8); // Upper Sector Count
+ outb(base+0x3, Address >> 24); // Low 2 Addr
+ outb(base+0x3, Address >> 28); // Mid 2 Addr
+ outb(base+0x3, Address >> 32); // High 2 Addr
+ }
+ else
+ {
+ 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
+ ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
+ if( Address > 0x0FFFFFFF )
+ outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
+ else
+ outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
+ #else
+ if( Address > 0x0FFFFFFF )
+ outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
+ else
+ outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
+ // 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 ) {
+ //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 );
+ //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;
+}
+
+/**
+ * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ */
+int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+ 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+0x6, 0x40 | (disk << 4));
+ outb(base+0x2, 0 >> 8); // Upper Sector Count
+ outb(base+0x3, Address >> 24); // Low 2 Addr
+ outb(base+0x3, Address >> 28); // Mid 2 Addr
+ outb(base+0x3, Address >> 32); // High 2 Addr
+ }
+ else
+ {
+ 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
+ if( Address > 0x0FFFFFFF )
+ 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;
+}
+
+/**
+ * \fn void ATA_IRQHandlerPri(int unused)
+ */
+void ATA_IRQHandlerPri(int unused)
+{
+ Uint8 val;
+
+ // IRQ bit set for Primary Controller
+ val = ATA_int_BusMasterReadByte( 0x2 );
+ LOG("IRQ val = 0x%x", val);
+ if(val & 4) {
+ LOG("IRQ hit (val = 0x%x)", val);
+ ATA_int_BusMasterWriteByte( 0x2, 4 );
+ gaATA_IRQs[0] = 1;
+ return ;
+ }
+}
+
+/**
+ * \fn void ATA_IRQHandlerSec(int unused)
+ */
+void ATA_IRQHandlerSec(int unused)
+{
+ Uint8 val;
+ // IRQ bit set for Secondary Controller
+ val = ATA_int_BusMasterReadByte( 0xA );
+ if(val & 4) {
+ LOG("IRQ hit (val = 0x%x)", val);
+ ATA_int_BusMasterWriteByte( 0xA, 4 );
+ gaATA_IRQs[1] = 1;
+ return ;
+ }
+}
+
+/**
+ * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
+ */
+Uint8 ATA_int_BusMasterReadByte(int Ofs)
+{
+ if( gATA_BusMasterBase & 1 )
+ return inb( (gATA_BusMasterBase & ~1) + Ofs );
+ else
+ return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
+}
+
+/**
+ * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
+ * \brief Writes a byte to a Bus Master Register
+ */
+void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
+{
+ if( gATA_BusMasterBase & 1 )
+ outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
+ else
+ *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
+}
+
+/**
+ * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
+ * \brief Writes a dword to a Bus Master Register
+ */
+void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
+{
+
+ if( gATA_BusMasterBase & 1 )
+ outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
+ else
+ *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
+}