2 * Acess2 IDE Harddisk Driver
11 #include <tpl_drv_common.h>
15 #define MAX_ATA_DISKS 4
16 #define SECTOR_SIZE 512
17 #define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
19 #define IDE_PRI_BASE 0x1F0
20 #define IDE_SEC_BASE 0x170
22 #define IDE_PRDT_LAST 0x8000
25 \brief Commands to be sent to HDD_CMD
46 Uint16 Usused1[9]; // 10
47 char SerialNum[20]; // 20
48 Uint16 Usused2[3]; // 23
49 char FirmwareVer[8]; // 27
50 char ModelNumber[40]; // 47
51 Uint16 SectPerInt; // 48 - and with 0xFF to get true value;
53 Uint16 Capabilities[2]; // 51
54 Uint16 Unused4[2]; // 53
55 Uint16 ValidExtData; // 54
56 Uint16 Unused5[5]; // 59
57 Uint16 SizeOfRWMultiple; // 60
58 Uint32 Sectors28; // 62
59 Uint16 Unused6[100-62];
61 Uint16 Unused7[256-104];
64 Uint8 BootCode[0x1BE];
67 Uint8 Unused1; // Also CHS Start
68 Uint16 StartHi; // Also CHS Start
70 Uint8 Unused2; // Also CHS Length
71 Uint16 LengthHi; // Also CHS Length
74 } __attribute__ ((packed)) Parts[4];
75 Uint16 BootFlag; // = 0xAA 55
76 } __attribute__ ((packed)) tMBR;
89 tATA_Partition *Partitions;
95 void ATA_SetupPartitions();
97 int ATA_ScanDisk(int Disk);
98 void ATA_ParseGPT(int Disk);
99 void ATA_ParseMBR(int Disk);
100 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
101 Uint16 ATA_GetBasePort(int Disk);
102 // Filesystem Interface
103 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
104 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
105 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
106 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
107 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
108 // Read/Write Interface/Quantiser
109 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
110 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
112 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
113 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
115 void ATA_IRQHandlerPri(int unused);
116 void ATA_IRQHandlerSec(int unused);
118 Uint8 ATA_int_BusMasterReadByte(int Ofs);
119 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
120 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
123 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL);
124 tDevFS_Driver gATA_DriverInfo = {
129 .Flags = VFS_FFLAG_DIRECTORY,
130 .ACLs = &gVFS_ACL_EveryoneRX,
131 .ReadDir = ATA_ReadDir,
132 .FindDir = ATA_FindDir
135 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
137 tVFS_Node **gATA_Nodes;
138 Uint16 gATA_BusMasterBase = 0;
139 Uint8 *gATA_BusMasterBasePtr = 0;
140 int gATA_IRQPri = 14;
141 int gATA_IRQSec = 15;
142 int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
143 Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
144 int gaATA_IRQs[2] = {0};
145 tPRDT_Ent gATA_PRDTs[2] = {
146 {0, 512, IDE_PRDT_LAST},
147 {0, 512, IDE_PRDT_LAST}
152 * \fn int ATA_Install()
159 if(ret != 1) return ret;
161 ATA_SetupPartitions();
165 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
172 * \fn int ATA_SetupIO()
173 * \brief Sets up the ATA controller's DMA mode
182 // Get IDE Controller's PCI Entry
183 ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
184 LOG("ent = %i\n", ent);
185 gATA_BusMasterBase = PCI_GetBAR4( ent );
186 LOG("gATA_BusMasterBase = 0x%x\n", gATA_BusMasterBase);
187 if( gATA_BusMasterBase == 0 ) {
188 Warning("It seems that there is no Bus Master Controller on this machine, get one");
192 if( !(gATA_BusMasterBase & 1) )
194 if( gATA_BusMasterBase < 0x100000 )
195 gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
197 gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
200 IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
201 IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
203 gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
204 gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
206 LOG("gATA_PRDTs = {0x%x, 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
208 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
209 ATA_int_BusMasterWriteDWord(4, addr);
210 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
211 ATA_int_BusMasterWriteDWord(12, addr);
218 * \fn void ATA_SetupPartitions()
220 void ATA_SetupPartitions()
223 for( i = 0; i < MAX_ATA_DISKS; i ++ )
225 if( !ATA_ScanDisk(i) ) {
226 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
233 * \fn void ATA_SetupVFS()
234 * \brief Sets up the ATA drivers VFS information and registers with DevFS
240 // Count number of nodes needed
242 for( i = 0; i < MAX_ATA_DISKS; i++ )
244 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
246 giATA_NumNodes += gATA_Disks[i].NumPartitions;
249 // Allocate Node space
250 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
254 for( i = 0; i < MAX_ATA_DISKS; i++ )
256 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
257 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
258 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
259 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
262 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
266 * \fn int ATA_ScanDisk(int Disk)
268 int ATA_ScanDisk(int Disk)
271 tIdentify *identify = (void*)buf;
272 tMBR *mbr = (void*)buf;
278 base = ATA_GetBasePort( Disk );
280 // Send Disk Selector
281 if(Disk == 1 || Disk == 3)
288 val = inb(base+7); // Read status
289 if(val == 0) return 0; // Disk does not exist
291 // Poll until BSY clears and DRQ sets or ERR is set
292 while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
294 if(val & 1) return 0; // Error occured, so return false
297 for(i=0;i<256;i++) buf[i] = inw(base);
299 // Populate Disk Structure
300 if(identify->Sectors48 != 0)
301 gATA_Disks[ Disk ].Sectors = identify->Sectors48;
303 gATA_Disks[ Disk ].Sectors = identify->Sectors28;
306 if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
307 Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
308 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
309 else if( gATA_Disks[ Disk ].Sectors / 2048 )
310 Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
311 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
313 Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
314 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
317 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
318 gATA_Disks[ Disk ].Name[1] = '\0';
320 // Get pointer to vfs node and populate it
321 node = &gATA_Disks[ Disk ].Node;
322 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
323 node->NumACLs = 0; // Means Superuser only can access it
324 node->Inode = (Disk << 8) | 0xFF;
325 node->ImplPtr = gATA_Disks[ Disk ].Name;
327 node->ATime = node->MTime
328 = node->CTime = now();
330 node->Read = ATA_ReadFS;
331 node->Write = ATA_WriteFS;
332 node->IOCtl = ATA_IOCtl;
335 // --- Scan Partitions ---
337 ATA_ReadDMA( Disk, 0, 1, mbr );
339 // Check for a GPT table
340 if(mbr->Parts[0].SystemID == 0xEE)
342 else // No? Just parse the MBR
349 * \fn void ATA_ParseGPT(int Disk)
350 * \brief Parses the GUID Partition Table
352 void ATA_ParseGPT(int Disk)
354 ///\todo Support GPT Disks
355 Warning("GPT Disks are currently unsupported");
359 * \fn void ATA_ParseMBR(int Disk)
361 void ATA_ParseMBR(int Disk)
368 ATA_ReadDMA( Disk, 0, 1, &mbr );
371 gATA_Disks[Disk].NumPartitions = 0;
373 for( i = 0; i < 4; i ++ )
375 if( mbr.Parts[i].SystemID == 0 ) continue;
377 mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28
378 || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48
381 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
382 if(extendedLBA != 0) {
383 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
386 extendedLBA = mbr.Parts[i].LBAStart;
390 gATA_Disks[Disk].NumPartitions ++;
393 // Invalid Partition, so don't count it
395 while(extendedLBA != 0)
397 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
398 break; // Stop on Errors
402 if( mbr.Parts[0].SystemID == 0 ) continue;
403 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28
404 || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48
407 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
408 extendedLBA = mbr.Parts[0].LBAStart;
410 gATA_Disks[Disk].NumPartitions ++;
413 if( mbr.Parts[1].SystemID == 0 ) continue;
414 if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28
415 || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48
418 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
419 if(extendedLBA == 0) {
420 Warning("Disk %i has twp forward link in the extended partition",
424 extendedLBA = mbr.Parts[1].LBAStart;
427 if(extendedLBA != 0) {
428 Warning("Disk %i lacks a forward link in the extended partition",
432 gATA_Disks[Disk].NumPartitions ++;
437 // Create patition array
438 gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
440 // --- Fill Partition Info ---
442 for( i = 0; i < 4; i ++ )
444 if( mbr.Parts[i].SystemID == 0 ) continue;
445 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
447 if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
448 if(extendedLBA != 0) {
449 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
452 extendedLBA = mbr.Parts[1].LBAStart;
456 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
457 mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
462 if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
464 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
465 if(extendedLBA != 0) {
466 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
469 extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
472 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
473 (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
474 (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
478 // Invalid Partition, so don't count it
480 // Scan extended partition
481 while(extendedLBA != 0)
483 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
484 break; // Stop on Errors
488 // Check first entry (should be partition)
489 if( mbr.Parts[0].SystemID != 0)
491 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28
493 // Forward Link to next Extended partition entry
494 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
495 extendedLBA = mbr.Parts[0].LBAStart;
497 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
498 mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
503 else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48
505 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
506 extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
508 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
509 (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
510 (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
517 // Check second entry (should be forward link)
518 if( mbr.Parts[1].SystemID != 0)
520 if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28
522 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
523 if(extendedLBA == 0) {
524 Warning("Disk %i has twp forward link in the extended partition",
528 extendedLBA = mbr.Parts[1].LBAStart;
532 if(extendedLBA != 0) {
533 Warning("Disk %i lacks a forward link in the extended partition",
537 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
538 mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
544 else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48
546 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
547 if(extendedLBA == 0) {
548 Warning("Disk %i has twp forward link in the extended partition",
552 extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
556 if(extendedLBA != 0) {
557 Warning("Disk %i lacks a forward link in the extended partition",
561 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
562 (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
563 (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
573 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
574 * \brief Fills a parition's information structure
576 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
578 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
580 Part->Length = Length;
581 Part->Name[0] = 'A'+Disk;
583 Part->Name[1] = '1'+Num/10;
584 Part->Name[2] = '1'+Num%10;
585 Part->Name[3] = '\0';
587 Part->Name[1] = '1'+Num;
588 Part->Name[2] = '\0';
590 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
591 Part->Node.Inode = (Disk << 8) | Num;
592 Part->Node.ImplPtr = Part->Name;
594 Part->Node.Read = ATA_ReadFS;
595 Part->Node.Write = ATA_WriteFS;
596 Part->Node.IOCtl = ATA_IOCtl;
597 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
602 * \fn Uint16 ATA_GetPortBase(int Disk)
603 * \brief Returns the base port for a given disk
605 Uint16 ATA_GetBasePort(int Disk)
609 case 0: case 1: return IDE_PRI_BASE;
610 case 2: case 3: return IDE_SEC_BASE;
616 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
618 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
620 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
621 return strdup( gATA_Nodes[Pos]->ImplPtr );
625 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
627 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
630 // Check first character
631 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
634 if(Name[1] == '\0') return &gATA_Disks[Name[0]-'A'].Node;
637 if(Name[1] < '0' || '9' < Name[1]) return NULL;
638 if(Name[2] == '\0') { // <= 9
639 part = Name[1] - '0';
641 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
644 if('0' > Name[2] || '9' < Name[2]) return NULL;
645 if(Name[3] != '\0') return NULL;
647 part = (Name[1] - '0') * 10;
648 part += Name[2] - '0';
650 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
655 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
657 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
659 int disk = Node->Inode >> 8;
660 int part = Node->Inode & 0xFF;
665 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
667 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
668 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
673 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
675 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
676 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
677 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
680 //Log("ATA_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
681 return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
685 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
687 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
689 int disk = Node->Inode >> 8;
690 int part = Node->Inode & 0xFF;
695 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
697 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
698 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
703 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
705 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
706 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
707 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
710 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
711 Debug_HexDump("ATA_WriteFS", Buffer, Length);
712 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
716 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
717 * \brief IO Control Funtion
719 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
723 case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
728 // --- Disk Access ---
730 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
732 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
738 // Pass straight on to ATA_ReadDMAPage if we can
739 if(Count <= MAX_DMA_SECTORS)
741 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
742 if(ret == 0) return 0;
746 // Else we will have to break up the transfer
748 while(Count > MAX_DMA_SECTORS)
750 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
752 if(ret != 1) return done;
754 done += MAX_DMA_SECTORS;
755 Count -= MAX_DMA_SECTORS;
756 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
759 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
760 if(ret != 1) return 0;
765 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
767 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
773 // Pass straight on to ATA_ReadDMAPage if we can
774 if(Count <= MAX_DMA_SECTORS)
776 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
777 if(ret == 0) return 0;
781 // Else we will have to break up the transfer
783 while(Count > MAX_DMA_SECTORS)
785 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
787 if(ret != 1) return done;
789 done += MAX_DMA_SECTORS;
790 Count -= MAX_DMA_SECTORS;
791 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
794 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
795 if(ret != 1) return 0;
800 * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
802 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
804 int cont = (Disk>>1)&1; // Controller ID
808 // Check if the count is small enough
809 if(Count > MAX_DMA_SECTORS) return 0;
811 // Get exclusive access to the disk controller
812 LOCK( &giaATA_ControllerLock[ cont ] );
815 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
818 base = ATA_GetBasePort(Disk);
821 outb(base+0x01, 0x00);
822 if( Address > 0x0FFFFFFF ) // Use LBA48
824 outb(base+0x6, 0x40 | (disk << 4));
825 outb(base+0x2, 0 >> 8); // Upper Sector Count
826 outb(base+0x3, Address >> 24); // Low 2 Addr
827 outb(base+0x3, Address >> 28); // Mid 2 Addr
828 outb(base+0x3, Address >> 32); // High 2 Addr
832 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
835 outb(base+0x02, (Uint8) Count); // Sector Count
836 outb(base+0x03, (Uint8) Address); // Low Addr
837 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
838 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
839 if( Address > 0x0FFFFFFF )
840 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
842 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
845 gaATA_IRQs[cont] = 0;
848 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
850 // Wait for transfer to complete
851 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
854 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
856 // Copy to destination buffer
857 memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
859 // Release controller lock
860 RELEASE( &giaATA_ControllerLock[ cont ] );
866 * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
868 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
870 int cont = (Disk>>1)&1; // Controller ID
874 // Check if the count is small enough
875 if(Count > MAX_DMA_SECTORS) return 0;
877 // Get exclusive access to the disk controller
878 LOCK( &giaATA_ControllerLock[ cont ] );
881 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
884 base = ATA_GetBasePort(Disk);
887 outb(base+0x01, 0x00);
888 if( Address > 0x0FFFFFFF ) // Use LBA48
890 outb(base+0x6, 0x40 | (disk << 4));
891 outb(base+0x2, 0 >> 8); // Upper Sector Count
892 outb(base+0x3, Address >> 24); // Low 2 Addr
893 outb(base+0x3, Address >> 28); // Mid 2 Addr
894 outb(base+0x3, Address >> 32); // High 2 Addr
898 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
901 outb(base+0x02, (Uint8) Count); // Sector Count
902 outb(base+0x03, (Uint8) Address); // Low Addr
903 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
904 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
905 if( Address > 0x0FFFFFFF )
906 outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
908 outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
911 gaATA_IRQs[cont] = 0;
913 // Copy to output buffer
914 memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
917 ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
919 // Wait for transfer to complete
920 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
923 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
925 // Release controller lock
926 RELEASE( &giaATA_ControllerLock[ cont ] );
932 * \fn void ATA_IRQHandlerPri(int unused)
934 void ATA_IRQHandlerPri(int unused)
938 // IRQ bit set for Primary Controller
939 val = ATA_int_BusMasterReadByte( 0x2 );
941 //Log(" ATA_IRQHandlerPri: IRQ hit (val = 0x%x)", val);
942 ATA_int_BusMasterWriteByte( 0x2, 4 );
949 * \fn void ATA_IRQHandlerSec(int unused)
951 void ATA_IRQHandlerSec(int unused)
954 // IRQ bit set for Secondary Controller
955 val = ATA_int_BusMasterReadByte( 0xA );
957 //Log(" ATA_IRQHandlerSec: IRQ hit (val = 0x%x)", val);
958 ATA_int_BusMasterWriteByte( 0xA, 4 );
965 * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
967 Uint8 ATA_int_BusMasterReadByte(int Ofs)
969 if( gATA_BusMasterBase & 1 )
970 return inb( (gATA_BusMasterBase & ~1) + Ofs );
972 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
976 * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
977 * \brief Writes a byte to a Bus Master Register
979 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
981 if( gATA_BusMasterBase & 1 )
982 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
984 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
988 * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
989 * \brief Writes a dword to a Bus Master Register
991 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
994 if( gATA_BusMasterBase & 1 )
995 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
997 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;