2 * Acess2 IDE Harddisk Driver
10 #include <tpl_drv_common.h>
13 #define MAX_ATA_DISKS 4
14 #define SECTOR_SIZE 512
15 #define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
17 #define IDE_PRI_BASE 0x1F0
18 #define IDE_SEC_BASE 0x170
20 #define IDE_PRDT_LAST 0x8000
23 \brief Commands to be sent to HDD_CMD
44 Uint16 Usused1[9]; // 10
45 char SerialNum[20]; // 20
46 Uint16 Usused2[3]; // 23
47 char FirmwareVer[8]; // 27
48 char ModelNumber[40]; // 47
49 Uint16 SectPerInt; // 48 - and with 0xFF to get true value;
51 Uint16 Capabilities[2]; // 51
52 Uint16 Unused4[2]; // 53
53 Uint16 ValidExtData; // 54
54 Uint16 Unused5[5]; // 59
55 Uint16 SizeOfRWMultiple; // 60
56 Uint32 Sectors28; // 62
57 Uint16 Unused6[100-62];
59 Uint16 Unused7[256-104];
62 Uint8 BootCode[0x1BE];
65 Uint8 Unused1; // Also CHS Start
66 Uint16 StartHi; // Also CHS Start
68 Uint8 Unused2; // Also CHS Length
69 Uint16 LengthHi; // Also CHS Length
72 } __attribute__ ((packed)) Parts[4];
73 Uint16 BootFlag; // = 0xAA 55
74 } __attribute__ ((packed)) tMBR;
87 tATA_Partition *Partitions;
93 static void ATA_SetupPartitions();
95 int ATA_ScanDisk(int Disk);
96 void ATA_ParseGPT(int Disk);
97 void ATA_ParseMBR(int Disk);
98 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
99 Uint16 ATA_GetBasePort(int Disk);
100 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
101 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
102 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
103 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
104 int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer);
105 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
106 void ATA_IRQHandlerPri(void);
107 void ATA_IRQHandlerSec(void);
108 Uint8 ATA_int_BusMasterReadByte(int Ofs);
109 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
110 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
113 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL);
114 tDevFS_Driver gATA_DriverInfo = {
119 .Flags = VFS_FFLAG_DIRECTORY,
120 .ACLs = &gVFS_ACL_EveryoneRX,
121 .ReadDir = ATA_ReadDir,
122 .FindDir = ATA_FindDir
125 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
127 tVFS_Node **gATA_Nodes;
128 Uint16 gATA_BusMasterBase = 0;
129 Uint8 *gATA_BusMasterBasePtr = 0;
130 int gATA_IRQPri = 14;
131 int gATA_IRQSec = 15;
132 int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
133 Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
134 int gaATA_IRQs[2] = {0};
135 tPRDT_Ent gATA_PRDTs[2] = {
136 {0, 512, IDE_PRDT_LAST},
137 {0, 512, IDE_PRDT_LAST}
142 * \fn int ATA_Install()
149 if(ret != 1) return ret;
151 ATA_SetupPartitions();
155 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
162 * \fn int ATA_SetupIO()
163 * \brief Sets up the ATA controller's DMA mode
172 // Get IDE Controller's PCI Entry
173 ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
174 LOG("ent = %i\n", ent);
175 gATA_BusMasterBase = PCI_GetBAR4( ent );
176 LOG("gATA_BusMasterBase = 0x%x\n", gATA_BusMasterBase);
177 if( gATA_BusMasterBase == 0 ) {
178 Warning("It seems that there is no Bus Master Controller on this machine, get one");
182 if( !(gATA_BusMasterBase & 1) )
184 if( gATA_BusMasterBase < 0x100000 )
185 gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
187 gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
190 IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
191 IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
193 gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
194 gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
196 LOG("gATA_PRDTs = {0x%x, 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
198 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
199 ATA_int_BusMasterWriteDWord(4, addr);
200 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
201 ATA_int_BusMasterWriteDWord(12, addr);
208 * \fn static void ATA_SetupPartitions()
210 static void ATA_SetupPartitions()
213 for( i = 0; i < MAX_ATA_DISKS; i ++ )
215 if( !ATA_ScanDisk(i) ) {
216 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
223 * \fn void ATA_SetupVFS()
224 * \brief Sets up the ATA drivers VFS information and registers with DevFS
230 // Count number of nodes needed
232 for( i = 0; i < MAX_ATA_DISKS; i++ )
234 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
236 giATA_NumNodes += gATA_Disks[i].NumPartitions;
239 // Allocate Node space
240 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
244 for( i = 0; i < MAX_ATA_DISKS; i++ )
246 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
247 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
248 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
249 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
252 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
256 * \fn int ATA_ScanDisk(int Disk)
258 int ATA_ScanDisk(int Disk)
261 tIdentify *identify = (void*)buf;
262 tMBR *mbr = (void*)buf;
268 base = ATA_GetBasePort( Disk );
270 // Send Disk Selector
271 if(Disk == 1 || Disk == 3)
278 val = inb(base+7); // Read status
279 if(val == 0) return 0; // Disk does not exist
281 // Poll until BSY clears and DRQ sets or ERR is set
282 while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
284 if(val & 1) return 0; // Error occured, so return false
287 for(i=0;i<256;i++) buf[i] = inw(base);
289 // Populate Disk Structure
290 if(identify->Sectors48 != 0)
291 gATA_Disks[ Disk ].Sectors = identify->Sectors48;
293 gATA_Disks[ Disk ].Sectors = identify->Sectors28;
296 if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
297 Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
298 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
299 else if( gATA_Disks[ Disk ].Sectors / 2048 )
300 Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
301 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
303 Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
304 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
307 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
308 gATA_Disks[ Disk ].Name[1] = '\0';
310 // Get pointer to vfs node and populate it
311 node = &gATA_Disks[ Disk ].Node;
312 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
313 node->NumACLs = 0; // Means Superuser only can access it
314 node->Inode = (Disk << 8) | 0xFF;
315 node->ImplPtr = gATA_Disks[ Disk ].Name;
317 node->ATime = node->MTime
318 = node->CTime = now();
320 node->Read = ATA_ReadFS;
321 //node->Write = ATA_WriteFS;
322 node->IOCtl = ATA_IOCtl;
325 // --- Scan Partitions ---
327 ATA_ReadDMA( Disk, 0, 1, mbr );
329 // Check for a GPT table
330 if(mbr->Parts[0].SystemID == 0xEE)
332 else // No? Just parse the MBR
339 * \fn void ATA_ParseGPT(int Disk)
340 * \brief Parses the GUID Partition Table
342 void ATA_ParseGPT(int Disk)
344 ///\todo Support GPT Disks
345 Warning("GPT Disks are currently unsupported");
349 * \fn void ATA_ParseMBR(int Disk)
351 void ATA_ParseMBR(int Disk)
358 ATA_ReadDMA( Disk, 0, 1, &mbr );
361 gATA_Disks[Disk].NumPartitions = 0;
363 for( i = 0; i < 4; i ++ )
365 if( mbr.Parts[i].SystemID == 0 ) continue;
367 mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28
368 || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48
371 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
372 if(extendedLBA != 0) {
373 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
376 extendedLBA = mbr.Parts[i].LBAStart;
380 gATA_Disks[Disk].NumPartitions ++;
383 // Invalid Partition, so don't count it
385 while(extendedLBA != 0)
387 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
388 break; // Stop on Errors
392 if( mbr.Parts[0].SystemID == 0 ) continue;
393 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28
394 || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48
397 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
398 extendedLBA = mbr.Parts[0].LBAStart;
400 gATA_Disks[Disk].NumPartitions ++;
403 if( mbr.Parts[1].SystemID == 0 ) continue;
404 if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28
405 || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48
408 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
409 if(extendedLBA == 0) {
410 Warning("Disk %i has twp forward link in the extended partition",
414 extendedLBA = mbr.Parts[1].LBAStart;
417 if(extendedLBA != 0) {
418 Warning("Disk %i lacks a forward link in the extended partition",
422 gATA_Disks[Disk].NumPartitions ++;
427 // Create patition array
428 gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
430 // --- Fill Partition Info ---
432 for( i = 0; i < 4; i ++ )
434 if( mbr.Parts[i].SystemID == 0 ) continue;
435 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
437 if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
438 if(extendedLBA != 0) {
439 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
442 extendedLBA = mbr.Parts[1].LBAStart;
446 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
447 mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
452 if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
454 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
455 if(extendedLBA != 0) {
456 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
459 extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
462 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
463 (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
464 (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
468 // Invalid Partition, so don't count it
470 // Scan extended partition
471 while(extendedLBA != 0)
473 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
474 break; // Stop on Errors
478 // Check first entry (should be partition)
479 if( mbr.Parts[0].SystemID != 0)
481 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28
483 // Forward Link to next Extended partition entry
484 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
485 extendedLBA = mbr.Parts[0].LBAStart;
487 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
488 mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
493 else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48
495 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
496 extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
498 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
499 (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
500 (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
507 // Check second entry (should be forward link)
508 if( mbr.Parts[1].SystemID != 0)
510 if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28
512 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
513 if(extendedLBA == 0) {
514 Warning("Disk %i has twp forward link in the extended partition",
518 extendedLBA = mbr.Parts[1].LBAStart;
522 if(extendedLBA != 0) {
523 Warning("Disk %i lacks a forward link in the extended partition",
527 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
528 mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
534 else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48
536 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
537 if(extendedLBA == 0) {
538 Warning("Disk %i has twp forward link in the extended partition",
542 extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
546 if(extendedLBA != 0) {
547 Warning("Disk %i lacks a forward link in the extended partition",
551 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
552 (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
553 (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
563 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
564 * \brief Fills a parition's information structure
566 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
568 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
570 Part->Length = Length;
571 Part->Name[0] = 'A'+Disk;
573 Part->Name[1] = '1'+Num/10;
574 Part->Name[2] = '1'+Num%10;
575 Part->Name[3] = '\0';
577 Part->Name[1] = '1'+Num;
578 Part->Name[2] = '\0';
580 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
581 Part->Node.Inode = (Disk << 8) | Num;
582 Part->Node.ImplPtr = Part->Name;
584 Part->Node.Read = ATA_ReadFS;
585 Part->Node.IOCtl = ATA_IOCtl;
586 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
591 * \fn Uint16 ATA_GetPortBase(int Disk)
592 * \brief Returns the base port for a given disk
594 Uint16 ATA_GetBasePort(int Disk)
598 case 0: case 1: return IDE_PRI_BASE;
599 case 2: case 3: return IDE_SEC_BASE;
605 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
607 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
609 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
610 return strdup( gATA_Nodes[Pos]->ImplPtr );
614 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
616 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
619 // Check first character
620 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
623 if(Name[1] == '\0') return &gATA_Disks[Name[0]-'A'].Node;
626 if(Name[1] < '0' || '9' < Name[1]) return NULL;
627 if(Name[2] == '\0') { // <= 9
628 part = Name[1] - '0';
630 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
633 if('0' > Name[2] || '9' < Name[2]) return NULL;
634 if(Name[3] != '\0') return NULL;
636 part = (Name[1] - '0') * 10;
637 part += Name[2] - '0';
639 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
644 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
646 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
650 Uint64 sector, count;
652 disk = Node->Inode >> 8;
653 part = Node->Inode & 0xFF;
656 if(Offset % SECTOR_SIZE == 0 && Length % SECTOR_SIZE == 0)
658 sector = Offset / SECTOR_SIZE;
659 count = Length / SECTOR_SIZE;
664 if( sector >= gATA_Disks[disk].Sectors ) return 0;
665 if( sector + count > gATA_Disks[disk].Sectors )
666 count = gATA_Disks[disk].Sectors - sector;
668 ret = ATA_Read(disk, sector, count, Buffer);
670 else // Or a partition
672 //Log(" ATA_ReadFS: %i:%i 0x%llx + 0x%llx\n", disk, part,
673 // gATA_Disks[disk].Partitions[part].Start,
674 // gATA_Disks[disk].Partitions[part].Length );
677 if( sector >= gATA_Disks[disk].Partitions[part].Length ) return 0;
678 if( sector + count > gATA_Disks[disk].Partitions[part].Length )
679 count = gATA_Disks[disk].Partitions[part].Length - sector;
682 gATA_Disks[disk].Partitions[part].Start + sector,
686 // Check return value
688 return count * SECTOR_SIZE;
690 Warning("ATA_ReadFS: RETURN 0 (Read failed with ret = %i)", ret);
694 Warning("ATA_ReadFS: RETURN 0 (Non-Aligned Read 0x%llx 0x%llx)", Offset, Length);
699 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
701 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
707 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
708 * \brief IO Control Funtion
710 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
714 case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
719 // --- Disk Access ---
721 * \fn int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
723 int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
728 // Pass straight on to ATA_ReadDMAPage if we can
729 if(Count <= MAX_DMA_SECTORS)
730 return ATA_ReadDMA(Disk, Address, Count, Buffer);
732 // Else we will have to break up the transfer
734 while(Count > MAX_DMA_SECTORS)
736 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
738 if(ret != 1) return ret;
740 Count -= MAX_DMA_SECTORS;
741 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
744 return ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
748 * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
750 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
752 int cont = (Disk>>1)&1; // Controller ID
756 // Check if the count is small enough
757 if(Count > MAX_DMA_SECTORS) return -1;
759 // Get exclusive access to the disk controller
760 LOCK( &giaATA_ControllerLock[ cont ] );
763 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
766 base = ATA_GetBasePort(Disk);
769 outb(base+0x01, 0x00);
770 if( Address > 0x0FFFFFFF ) // Use LBA48
772 outb(base+0x6, 0x40 | (disk << 4));
773 outb(base+0x2, 0 >> 8); // Upper Sector Count
774 outb(base+0x3, Address >> 24); // Low 2 Addr
775 outb(base+0x3, Address >> 28); // Mid 2 Addr
776 outb(base+0x3, Address >> 32); // High 2 Addr
780 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
783 outb(base+0x02, (Uint8) Count); // Sector Count
784 outb(base+0x03, (Uint8) Address); // Low Addr
785 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
786 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
787 if( Address > 0x0FFFFFFF )
788 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
790 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
793 gaATA_IRQs[cont] = 0;
796 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
798 // Wait for transfer to complete
799 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
802 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
804 // Copy to destination buffer
805 memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
807 // Release controller lock
808 RELEASE( &giaATA_ControllerLock[ cont ] );
814 * \fn void ATA_IRQHandlerPri(void)
816 void ATA_IRQHandlerPri(void)
820 // IRQ bit set for Primary Controller
821 val = ATA_int_BusMasterReadByte( 0x2 );
823 //Log(" ATA_IRQHandlerPri: IRQ hit (val = 0x%x)", val);
824 ATA_int_BusMasterWriteByte( 0x2, 4 );
831 * \fn void ATA_IRQHandlerSec(void)
833 void ATA_IRQHandlerSec(void)
836 // IRQ bit set for Secondary Controller
837 val = ATA_int_BusMasterReadByte( 0xA );
839 //Log(" ATA_IRQHandlerSec: IRQ hit (val = 0x%x)", val);
840 ATA_int_BusMasterWriteByte( 0xA, 4 );
847 * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
849 Uint8 ATA_int_BusMasterReadByte(int Ofs)
851 if( gATA_BusMasterBase & 1 )
852 return inb( (gATA_BusMasterBase & ~1) + Ofs );
854 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
858 * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
859 * \brief Writes a byte to a Bus Master Register
861 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
863 if( gATA_BusMasterBase & 1 )
864 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
866 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
870 * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
871 * \brief Writes a dword to a Bus Master Register
873 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
876 if( gATA_BusMasterBase & 1 )
877 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
879 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;