2 * Acess2 IDE Harddisk Driver
11 #include <tpl_drv_common.h>
14 #define MAX_ATA_DISKS 4
15 #define SECTOR_SIZE 512
16 #define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
18 #define IDE_PRI_BASE 0x1F0
19 #define IDE_SEC_BASE 0x170
21 #define IDE_PRDT_LAST 0x8000
24 \brief Commands to be sent to HDD_CMD
45 Uint16 Usused1[9]; // 10
46 char SerialNum[20]; // 20
47 Uint16 Usused2[3]; // 23
48 char FirmwareVer[8]; // 27
49 char ModelNumber[40]; // 47
50 Uint16 SectPerInt; // 48 - and with 0xFF to get true value;
52 Uint16 Capabilities[2]; // 51
53 Uint16 Unused4[2]; // 53
54 Uint16 ValidExtData; // 54
55 Uint16 Unused5[5]; // 59
56 Uint16 SizeOfRWMultiple; // 60
57 Uint32 Sectors28; // 62
58 Uint16 Unused6[100-62];
60 Uint16 Unused7[256-104];
63 Uint8 BootCode[0x1BE];
66 Uint8 Unused1; // Also CHS Start
67 Uint16 StartHi; // Also CHS Start
69 Uint8 Unused2; // Also CHS Length
70 Uint16 LengthHi; // Also CHS Length
73 } __attribute__ ((packed)) Parts[4];
74 Uint16 BootFlag; // = 0xAA 55
75 } __attribute__ ((packed)) tMBR;
88 tATA_Partition *Partitions;
94 static void ATA_SetupPartitions();
96 int ATA_ScanDisk(int Disk);
97 void ATA_ParseGPT(int Disk);
98 void ATA_ParseMBR(int Disk);
99 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
100 Uint16 ATA_GetBasePort(int Disk);
101 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
102 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
103 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
104 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
105 int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer);
106 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
107 void ATA_IRQHandlerPri(void);
108 void ATA_IRQHandlerSec(void);
109 Uint8 ATA_int_BusMasterReadByte(int Ofs);
110 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
111 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
114 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL);
115 tDevFS_Driver gATA_DriverInfo = {
120 .Flags = VFS_FFLAG_DIRECTORY,
121 .ACLs = &gVFS_ACL_EveryoneRX,
122 .ReadDir = ATA_ReadDir,
123 .FindDir = ATA_FindDir
126 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
128 tVFS_Node **gATA_Nodes;
129 Uint16 gATA_BusMasterBase = 0;
130 Uint8 *gATA_BusMasterBasePtr = 0;
131 int gATA_IRQPri = 14;
132 int gATA_IRQSec = 15;
133 int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
134 Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
135 int gaATA_IRQs[2] = {0};
136 tPRDT_Ent gATA_PRDTs[2] = {
137 {0, 512, IDE_PRDT_LAST},
138 {0, 512, IDE_PRDT_LAST}
143 * \fn int ATA_Install()
150 if(ret != 1) return ret;
152 ATA_SetupPartitions();
156 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
163 * \fn int ATA_SetupIO()
164 * \brief Sets up the ATA controller's DMA mode
173 // Get IDE Controller's PCI Entry
174 ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
175 LOG("ent = %i\n", ent);
176 gATA_BusMasterBase = PCI_GetBAR4( ent );
177 LOG("gATA_BusMasterBase = 0x%x\n", gATA_BusMasterBase);
178 if( gATA_BusMasterBase == 0 ) {
179 Warning("It seems that there is no Bus Master Controller on this machine, get one");
183 if( !(gATA_BusMasterBase & 1) )
185 if( gATA_BusMasterBase < 0x100000 )
186 gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
188 gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
191 IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
192 IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
194 gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
195 gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
197 LOG("gATA_PRDTs = {0x%x, 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
199 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
200 ATA_int_BusMasterWriteDWord(4, addr);
201 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
202 ATA_int_BusMasterWriteDWord(12, addr);
209 * \fn static void ATA_SetupPartitions()
211 static void ATA_SetupPartitions()
214 for( i = 0; i < MAX_ATA_DISKS; i ++ )
216 if( !ATA_ScanDisk(i) ) {
217 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
224 * \fn void ATA_SetupVFS()
225 * \brief Sets up the ATA drivers VFS information and registers with DevFS
231 // Count number of nodes needed
233 for( i = 0; i < MAX_ATA_DISKS; i++ )
235 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
237 giATA_NumNodes += gATA_Disks[i].NumPartitions;
240 // Allocate Node space
241 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
245 for( i = 0; i < MAX_ATA_DISKS; i++ )
247 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
248 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
249 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
250 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
253 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
257 * \fn int ATA_ScanDisk(int Disk)
259 int ATA_ScanDisk(int Disk)
262 tIdentify *identify = (void*)buf;
263 tMBR *mbr = (void*)buf;
269 base = ATA_GetBasePort( Disk );
271 // Send Disk Selector
272 if(Disk == 1 || Disk == 3)
279 val = inb(base+7); // Read status
280 if(val == 0) return 0; // Disk does not exist
282 // Poll until BSY clears and DRQ sets or ERR is set
283 while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
285 if(val & 1) return 0; // Error occured, so return false
288 for(i=0;i<256;i++) buf[i] = inw(base);
290 // Populate Disk Structure
291 if(identify->Sectors48 != 0)
292 gATA_Disks[ Disk ].Sectors = identify->Sectors48;
294 gATA_Disks[ Disk ].Sectors = identify->Sectors28;
297 if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
298 Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
299 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
300 else if( gATA_Disks[ Disk ].Sectors / 2048 )
301 Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
302 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
304 Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
305 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
308 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
309 gATA_Disks[ Disk ].Name[1] = '\0';
311 // Get pointer to vfs node and populate it
312 node = &gATA_Disks[ Disk ].Node;
313 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
314 node->NumACLs = 0; // Means Superuser only can access it
315 node->Inode = (Disk << 8) | 0xFF;
316 node->ImplPtr = gATA_Disks[ Disk ].Name;
318 node->ATime = node->MTime
319 = node->CTime = now();
321 node->Read = ATA_ReadFS;
322 //node->Write = ATA_WriteFS;
323 node->IOCtl = ATA_IOCtl;
326 // --- Scan Partitions ---
328 ATA_ReadDMA( Disk, 0, 1, mbr );
330 // Check for a GPT table
331 if(mbr->Parts[0].SystemID == 0xEE)
333 else // No? Just parse the MBR
340 * \fn void ATA_ParseGPT(int Disk)
341 * \brief Parses the GUID Partition Table
343 void ATA_ParseGPT(int Disk)
345 ///\todo Support GPT Disks
346 Warning("GPT Disks are currently unsupported");
350 * \fn void ATA_ParseMBR(int Disk)
352 void ATA_ParseMBR(int Disk)
359 ATA_ReadDMA( Disk, 0, 1, &mbr );
362 gATA_Disks[Disk].NumPartitions = 0;
364 for( i = 0; i < 4; i ++ )
366 if( mbr.Parts[i].SystemID == 0 ) continue;
368 mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28
369 || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48
372 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
373 if(extendedLBA != 0) {
374 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
377 extendedLBA = mbr.Parts[i].LBAStart;
381 gATA_Disks[Disk].NumPartitions ++;
384 // Invalid Partition, so don't count it
386 while(extendedLBA != 0)
388 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
389 break; // Stop on Errors
393 if( mbr.Parts[0].SystemID == 0 ) continue;
394 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28
395 || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48
398 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
399 extendedLBA = mbr.Parts[0].LBAStart;
401 gATA_Disks[Disk].NumPartitions ++;
404 if( mbr.Parts[1].SystemID == 0 ) continue;
405 if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28
406 || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48
409 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
410 if(extendedLBA == 0) {
411 Warning("Disk %i has twp forward link in the extended partition",
415 extendedLBA = mbr.Parts[1].LBAStart;
418 if(extendedLBA != 0) {
419 Warning("Disk %i lacks a forward link in the extended partition",
423 gATA_Disks[Disk].NumPartitions ++;
428 // Create patition array
429 gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
431 // --- Fill Partition Info ---
433 for( i = 0; i < 4; i ++ )
435 if( mbr.Parts[i].SystemID == 0 ) continue;
436 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
438 if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
439 if(extendedLBA != 0) {
440 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
443 extendedLBA = mbr.Parts[1].LBAStart;
447 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
448 mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
453 if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
455 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
456 if(extendedLBA != 0) {
457 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
460 extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
463 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
464 (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
465 (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
469 // Invalid Partition, so don't count it
471 // Scan extended partition
472 while(extendedLBA != 0)
474 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
475 break; // Stop on Errors
479 // Check first entry (should be partition)
480 if( mbr.Parts[0].SystemID != 0)
482 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28
484 // Forward Link to next Extended partition entry
485 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
486 extendedLBA = mbr.Parts[0].LBAStart;
488 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
489 mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
494 else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48
496 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
497 extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
499 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
500 (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
501 (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
508 // Check second entry (should be forward link)
509 if( mbr.Parts[1].SystemID != 0)
511 if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28
513 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
514 if(extendedLBA == 0) {
515 Warning("Disk %i has twp forward link in the extended partition",
519 extendedLBA = mbr.Parts[1].LBAStart;
523 if(extendedLBA != 0) {
524 Warning("Disk %i lacks a forward link in the extended partition",
528 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
529 mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
535 else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48
537 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
538 if(extendedLBA == 0) {
539 Warning("Disk %i has twp forward link in the extended partition",
543 extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
547 if(extendedLBA != 0) {
548 Warning("Disk %i lacks a forward link in the extended partition",
552 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
553 (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
554 (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
564 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
565 * \brief Fills a parition's information structure
567 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
569 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
571 Part->Length = Length;
572 Part->Name[0] = 'A'+Disk;
574 Part->Name[1] = '1'+Num/10;
575 Part->Name[2] = '1'+Num%10;
576 Part->Name[3] = '\0';
578 Part->Name[1] = '1'+Num;
579 Part->Name[2] = '\0';
581 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
582 Part->Node.Inode = (Disk << 8) | Num;
583 Part->Node.ImplPtr = Part->Name;
585 Part->Node.Read = ATA_ReadFS;
586 Part->Node.IOCtl = ATA_IOCtl;
587 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
592 * \fn Uint16 ATA_GetPortBase(int Disk)
593 * \brief Returns the base port for a given disk
595 Uint16 ATA_GetBasePort(int Disk)
599 case 0: case 1: return IDE_PRI_BASE;
600 case 2: case 3: return IDE_SEC_BASE;
606 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
608 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
610 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
611 return strdup( gATA_Nodes[Pos]->ImplPtr );
615 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
617 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
620 // Check first character
621 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
624 if(Name[1] == '\0') return &gATA_Disks[Name[0]-'A'].Node;
627 if(Name[1] < '0' || '9' < Name[1]) return NULL;
628 if(Name[2] == '\0') { // <= 9
629 part = Name[1] - '0';
631 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
634 if('0' > Name[2] || '9' < Name[2]) return NULL;
635 if(Name[3] != '\0') return NULL;
637 part = (Name[1] - '0') * 10;
638 part += Name[2] - '0';
640 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
645 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
647 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
651 Uint64 sector, count;
653 disk = Node->Inode >> 8;
654 part = Node->Inode & 0xFF;
657 if(Offset % SECTOR_SIZE == 0 && Length % SECTOR_SIZE == 0)
659 sector = Offset / SECTOR_SIZE;
660 count = Length / SECTOR_SIZE;
665 if( sector >= gATA_Disks[disk].Sectors ) return 0;
666 if( sector + count > gATA_Disks[disk].Sectors )
667 count = gATA_Disks[disk].Sectors - sector;
669 ret = ATA_Read(disk, sector, count, Buffer);
671 else // Or a partition
673 //Log(" ATA_ReadFS: %i:%i 0x%llx + 0x%llx\n", disk, part,
674 // gATA_Disks[disk].Partitions[part].Start,
675 // gATA_Disks[disk].Partitions[part].Length );
678 if( sector >= gATA_Disks[disk].Partitions[part].Length ) return 0;
679 if( sector + count > gATA_Disks[disk].Partitions[part].Length )
680 count = gATA_Disks[disk].Partitions[part].Length - sector;
683 gATA_Disks[disk].Partitions[part].Start + sector,
687 // Check return value
689 return count * SECTOR_SIZE;
691 Warning("ATA_ReadFS: RETURN 0 (Read failed with ret = %i)", ret);
695 Warning("ATA_ReadFS: RETURN 0 (Non-Aligned Read 0x%llx 0x%llx)", Offset, Length);
700 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
702 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
708 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
709 * \brief IO Control Funtion
711 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
715 case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
720 // --- Disk Access ---
722 * \fn int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
724 int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
729 // Pass straight on to ATA_ReadDMAPage if we can
730 if(Count <= MAX_DMA_SECTORS)
731 return ATA_ReadDMA(Disk, Address, Count, Buffer);
733 // Else we will have to break up the transfer
735 while(Count > MAX_DMA_SECTORS)
737 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
739 if(ret != 1) return ret;
741 Count -= MAX_DMA_SECTORS;
742 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
745 return ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
749 * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
751 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
753 int cont = (Disk>>1)&1; // Controller ID
757 // Check if the count is small enough
758 if(Count > MAX_DMA_SECTORS) return -1;
760 // Get exclusive access to the disk controller
761 LOCK( &giaATA_ControllerLock[ cont ] );
764 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
767 base = ATA_GetBasePort(Disk);
770 outb(base+0x01, 0x00);
771 if( Address > 0x0FFFFFFF ) // Use LBA48
773 outb(base+0x6, 0x40 | (disk << 4));
774 outb(base+0x2, 0 >> 8); // Upper Sector Count
775 outb(base+0x3, Address >> 24); // Low 2 Addr
776 outb(base+0x3, Address >> 28); // Mid 2 Addr
777 outb(base+0x3, Address >> 32); // High 2 Addr
781 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
784 outb(base+0x02, (Uint8) Count); // Sector Count
785 outb(base+0x03, (Uint8) Address); // Low Addr
786 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
787 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
788 if( Address > 0x0FFFFFFF )
789 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
791 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
794 gaATA_IRQs[cont] = 0;
797 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
799 // Wait for transfer to complete
800 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
803 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
805 // Copy to destination buffer
806 memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
808 // Release controller lock
809 RELEASE( &giaATA_ControllerLock[ cont ] );
815 * \fn void ATA_IRQHandlerPri(void)
817 void ATA_IRQHandlerPri(void)
821 // IRQ bit set for Primary Controller
822 val = ATA_int_BusMasterReadByte( 0x2 );
824 //Log(" ATA_IRQHandlerPri: IRQ hit (val = 0x%x)", val);
825 ATA_int_BusMasterWriteByte( 0x2, 4 );
832 * \fn void ATA_IRQHandlerSec(void)
834 void ATA_IRQHandlerSec(void)
837 // IRQ bit set for Secondary Controller
838 val = ATA_int_BusMasterReadByte( 0xA );
840 //Log(" ATA_IRQHandlerSec: IRQ hit (val = 0x%x)", val);
841 ATA_int_BusMasterWriteByte( 0xA, 4 );
848 * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
850 Uint8 ATA_int_BusMasterReadByte(int Ofs)
852 if( gATA_BusMasterBase & 1 )
853 return inb( (gATA_BusMasterBase & ~1) + Ofs );
855 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
859 * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
860 * \brief Writes a byte to a Bus Master Register
862 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
864 if( gATA_BusMasterBase & 1 )
865 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
867 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
871 * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
872 * \brief Writes a dword to a Bus Master Register
874 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
877 if( gATA_BusMasterBase & 1 )
878 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
880 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;