2 * Acess2 IDE Harddisk Driver
11 #include <tpl_drv_common.h>
12 #include <tpl_drv_disk.h>
15 #define START_BEFORE_CMD 0
18 #define MAX_ATA_DISKS 4
19 #define SECTOR_SIZE 512
20 #define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
22 #define IDE_PRI_BASE 0x1F0
23 #define IDE_SEC_BASE 0x170
25 #define IDE_PRDT_LAST 0x8000
28 \brief Commands to be sent to HDD_CMD
49 Uint16 Usused1[9]; // 10
50 char SerialNum[20]; // 20
51 Uint16 Usused2[3]; // 23
52 char FirmwareVer[8]; // 27
53 char ModelNumber[40]; // 47
54 Uint16 SectPerInt; // 48 - and with 0xFF to get true value;
56 Uint16 Capabilities[2]; // 51
57 Uint16 Unused4[2]; // 53
58 Uint16 ValidExtData; // 54
59 Uint16 Unused5[5]; // 59
60 Uint16 SizeOfRWMultiple; // 60
61 Uint32 Sectors28; // 62
62 Uint16 Unused6[100-62];
64 Uint16 Unused7[256-104];
67 Uint8 BootCode[0x1BE];
70 Uint8 Unused1; // Also CHS Start
71 Uint16 StartHi; // Also CHS Start
73 Uint8 Unused2; // Also CHS Length
74 Uint16 LengthHi; // Also CHS Length
77 } __attribute__ ((packed)) Parts[4];
78 Uint16 BootFlag; // = 0xAA 55
79 } __attribute__ ((packed)) tMBR;
92 tATA_Partition *Partitions;
98 void ATA_SetupPartitions();
100 int ATA_ScanDisk(int Disk);
101 void ATA_ParseGPT(int Disk);
102 void ATA_ParseMBR(int Disk);
103 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
104 Uint16 ATA_GetBasePort(int Disk);
105 // Filesystem Interface
106 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
107 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
108 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
109 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
110 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
111 // Read/Write Interface/Quantiser
112 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
113 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
115 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
116 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
118 void ATA_IRQHandlerPri(int unused);
119 void ATA_IRQHandlerSec(int unused);
121 Uint8 ATA_int_BusMasterReadByte(int Ofs);
122 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
123 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
126 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
127 tDevFS_Driver gATA_DriverInfo = {
132 .Flags = VFS_FFLAG_DIRECTORY,
133 .ACLs = &gVFS_ACL_EveryoneRX,
134 .ReadDir = ATA_ReadDir,
135 .FindDir = ATA_FindDir
138 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
140 tVFS_Node **gATA_Nodes;
141 Uint16 gATA_BusMasterBase = 0;
142 Uint8 *gATA_BusMasterBasePtr = 0;
143 int gATA_IRQPri = 14;
144 int gATA_IRQSec = 15;
145 int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
146 Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
147 int gaATA_IRQs[2] = {0};
148 tPRDT_Ent gATA_PRDTs[2] = {
149 {0, 512, IDE_PRDT_LAST},
150 {0, 512, IDE_PRDT_LAST}
155 * \fn int ATA_Install()
162 if(ret != 1) return ret;
164 ATA_SetupPartitions();
168 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
169 return MODULE_INIT_FAILURE;
171 return MODULE_INIT_SUCCESS;
175 * \fn int ATA_SetupIO()
176 * \brief Sets up the ATA controller's DMA mode
185 // Get IDE Controller's PCI Entry
186 ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
187 LOG("ent = %i", ent);
188 gATA_BusMasterBase = PCI_GetBAR4( ent );
189 if( gATA_BusMasterBase == 0 ) {
190 Warning("It seems that there is no Bus Master Controller on this machine. Get one");
191 LEAVE('i', MODULE_INIT_FAILURE);
192 return MODULE_INIT_FAILURE;
194 if( !(gATA_BusMasterBase & 1) )
196 if( gATA_BusMasterBase < 0x100000 )
197 gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
199 gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
200 LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
203 // Bit 0 is left set as a flag to other functions
204 LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
207 IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
208 IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
210 gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
211 gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
213 LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
215 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
216 LOG("addr = 0x%x", addr);
217 ATA_int_BusMasterWriteDWord(4, addr);
218 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
219 LOG("addr = 0x%x", addr);
220 ATA_int_BusMasterWriteDWord(12, addr);
222 outb(IDE_PRI_BASE+1, 1);
223 outb(IDE_SEC_BASE+1, 1);
225 LEAVE('i', MODULE_INIT_SUCCESS);
226 return MODULE_INIT_SUCCESS;
230 * \fn void ATA_SetupPartitions()
232 void ATA_SetupPartitions()
235 for( i = 0; i < MAX_ATA_DISKS; i ++ )
237 if( !ATA_ScanDisk(i) ) {
238 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
245 * \fn void ATA_SetupVFS()
246 * \brief Sets up the ATA drivers VFS information and registers with DevFS
252 // Count number of nodes needed
254 for( i = 0; i < MAX_ATA_DISKS; i++ )
256 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
258 giATA_NumNodes += gATA_Disks[i].NumPartitions;
261 // Allocate Node space
262 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
266 for( i = 0; i < MAX_ATA_DISKS; i++ )
268 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
269 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
270 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
271 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
274 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
278 * \fn int ATA_ScanDisk(int Disk)
280 int ATA_ScanDisk(int Disk)
283 tIdentify *identify = (void*)buf;
284 tMBR *mbr = (void*)buf;
290 ENTER("iDisk", Disk);
292 base = ATA_GetBasePort( Disk );
294 LOG("base = 0x%x", base);
296 // Send Disk Selector
297 if(Disk == 1 || Disk == 3)
304 val = inb(base+7); // Read status
307 return 0; // Disk does not exist
310 // Poll until BSY clears and DRQ sets or ERR is set
311 while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
315 return 0; // Error occured, so return false
319 for(i=0;i<256;i++) buf[i] = inw(base);
321 // Populate Disk Structure
322 if(identify->Sectors48 != 0)
323 gATA_Disks[ Disk ].Sectors = identify->Sectors48;
325 gATA_Disks[ Disk ].Sectors = identify->Sectors28;
328 LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors);
330 if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
331 Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
332 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
333 else if( gATA_Disks[ Disk ].Sectors / 2048 )
334 Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
335 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
337 Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
338 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
341 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
342 gATA_Disks[ Disk ].Name[1] = '\0';
344 // Get pointer to vfs node and populate it
345 node = &gATA_Disks[ Disk ].Node;
346 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
347 node->NumACLs = 0; // Means Superuser only can access it
348 node->Inode = (Disk << 8) | 0xFF;
349 node->ImplPtr = gATA_Disks[ Disk ].Name;
351 node->ATime = node->MTime
352 = node->CTime = now();
354 node->Read = ATA_ReadFS;
355 node->Write = ATA_WriteFS;
356 node->IOCtl = ATA_IOCtl;
359 // --- Scan Partitions ---
362 ATA_ReadDMA( Disk, 0, 1, mbr );
364 // Check for a GPT table
365 if(mbr->Parts[0].SystemID == 0xEE)
367 else // No? Just parse the MBR
375 * \fn void ATA_ParseGPT(int Disk)
376 * \brief Parses the GUID Partition Table
378 void ATA_ParseGPT(int Disk)
380 ///\todo Support GPT Disks
381 Warning("GPT Disks are currently unsupported");
385 * \fn void ATA_ParseMBR(int Disk)
387 void ATA_ParseMBR(int Disk)
393 ENTER("iDisk", Disk);
396 ATA_ReadDMA( Disk, 0, 1, &mbr );
399 gATA_Disks[Disk].NumPartitions = 0;
401 for( i = 0; i < 4; i ++ )
403 if( mbr.Parts[i].SystemID == 0 ) continue;
405 mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28
406 || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48
409 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
410 LOG("Extended Partition");
411 if(extendedLBA != 0) {
412 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
415 extendedLBA = mbr.Parts[i].LBAStart;
418 LOG("Primary Partition");
420 gATA_Disks[Disk].NumPartitions ++;
423 // Invalid Partition, so don't count it
425 while(extendedLBA != 0)
427 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
428 break; // Stop on Errors
432 if( mbr.Parts[0].SystemID == 0 ) continue;
433 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28
434 || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48
437 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
438 extendedLBA = mbr.Parts[0].LBAStart;
440 gATA_Disks[Disk].NumPartitions ++;
443 if( mbr.Parts[1].SystemID == 0 ) continue;
444 if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28
445 || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48
448 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
449 if(extendedLBA == 0) {
450 Warning("Disk %i has twp forward link in the extended partition",
454 extendedLBA = mbr.Parts[1].LBAStart;
457 if(extendedLBA != 0) {
458 Warning("Disk %i lacks a forward link in the extended partition",
462 gATA_Disks[Disk].NumPartitions ++;
466 LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
468 // Create patition array
469 gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
471 // --- Fill Partition Info ---
473 for( i = 0; i < 4; i ++ )
475 Log("mbr.Parts[%i].SystemID = 0x%02x", i, mbr.Parts[i].SystemID);
476 if( mbr.Parts[i].SystemID == 0 ) continue;
477 if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
479 if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
480 if(extendedLBA != 0) {
481 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
484 extendedLBA = mbr.Parts[1].LBAStart;
488 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
489 mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
494 if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
496 if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
497 if(extendedLBA != 0) {
498 Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
501 extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
504 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
505 (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
506 (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
510 // Invalid Partition, so don't count it
512 // Scan extended partition
513 while(extendedLBA != 0)
515 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
516 break; // Stop on Errors
520 // Check first entry (should be partition)
521 if( mbr.Parts[0].SystemID != 0)
523 if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28
525 // Forward Link to next Extended partition entry
526 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
527 extendedLBA = mbr.Parts[0].LBAStart;
529 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
530 mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
535 else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48
537 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
538 extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
540 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
541 (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
542 (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
549 // Check second entry (should be forward link)
550 if( mbr.Parts[1].SystemID != 0)
552 if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28
554 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
555 if(extendedLBA == 0) {
556 Warning("Disk %i has twp forward link in the extended partition",
560 extendedLBA = mbr.Parts[1].LBAStart;
564 if(extendedLBA != 0) {
565 Warning("Disk %i lacks a forward link in the extended partition",
569 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
570 mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
576 else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48
578 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
579 if(extendedLBA == 0) {
580 Warning("Disk %i has twp forward link in the extended partition",
584 extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
588 if(extendedLBA != 0) {
589 Warning("Disk %i lacks a forward link in the extended partition",
593 ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
594 (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
595 (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
607 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
608 * \brief Fills a parition's information structure
610 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
612 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
614 Part->Length = Length;
615 Part->Name[0] = 'A'+Disk;
617 Part->Name[1] = '1'+Num/10;
618 Part->Name[2] = '1'+Num%10;
619 Part->Name[3] = '\0';
621 Part->Name[1] = '1'+Num;
622 Part->Name[2] = '\0';
624 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
625 Part->Node.Inode = (Disk << 8) | Num;
626 Part->Node.ImplPtr = Part->Name;
628 Part->Node.Read = ATA_ReadFS;
629 Part->Node.Write = ATA_WriteFS;
630 Part->Node.IOCtl = ATA_IOCtl;
631 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
636 * \fn Uint16 ATA_GetPortBase(int Disk)
637 * \brief Returns the base port for a given disk
639 Uint16 ATA_GetBasePort(int Disk)
643 case 0: case 1: return IDE_PRI_BASE;
644 case 2: case 3: return IDE_SEC_BASE;
650 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
652 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
654 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
655 return strdup( gATA_Nodes[Pos]->ImplPtr );
659 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
661 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
664 // Check first character
665 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
668 if(Name[1] == '\0') {
669 if( gATA_Disks[Name[0]-'A'].Sectors == 0 )
671 return &gATA_Disks[Name[0]-'A'].Node;
675 if(Name[1] < '0' || '9' < Name[1]) return NULL;
676 if(Name[2] == '\0') { // <= 9
677 part = Name[1] - '0';
679 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
682 if('0' > Name[2] || '9' < Name[2]) return NULL;
683 if(Name[3] != '\0') return NULL;
685 part = (Name[1] - '0') * 10;
686 part += Name[2] - '0';
688 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
693 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
695 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
697 int disk = Node->Inode >> 8;
698 int part = Node->Inode & 0xFF;
703 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
705 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
706 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
711 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
713 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
714 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
715 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
718 //Log("ATA_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
719 return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
723 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
725 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
727 int disk = Node->Inode >> 8;
728 int part = Node->Inode & 0xFF;
733 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
735 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
736 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
741 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
743 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
744 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
745 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
748 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
749 Debug_HexDump("ATA_WriteFS", Buffer, Length);
750 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
754 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
755 * \brief IO Control Funtion
757 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
761 case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
766 // --- Disk Access ---
768 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
770 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
776 // Pass straight on to ATA_ReadDMAPage if we can
777 if(Count <= MAX_DMA_SECTORS)
779 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
780 if(ret == 0) return 0;
784 // Else we will have to break up the transfer
786 while(Count > MAX_DMA_SECTORS)
788 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
790 if(ret != 1) return done;
792 done += MAX_DMA_SECTORS;
793 Count -= MAX_DMA_SECTORS;
794 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
797 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
798 if(ret != 1) return 0;
803 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
805 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
811 // Pass straight on to ATA_WriteDMA if we can
812 if(Count <= MAX_DMA_SECTORS)
814 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
815 if(ret == 0) return 0;
819 // Else we will have to break up the transfer
821 while(Count > MAX_DMA_SECTORS)
823 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
825 if(ret != 1) return done;
827 done += MAX_DMA_SECTORS;
828 Count -= MAX_DMA_SECTORS;
829 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
832 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
833 if(ret != 1) return 0;
838 * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
840 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
842 int cont = (Disk>>1)&1; // Controller ID
846 ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
848 // Check if the count is small enough
849 if(Count > MAX_DMA_SECTORS) {
850 Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
851 Count, MAX_DMA_SECTORS);
856 // Get exclusive access to the disk controller
857 LOCK( &giaATA_ControllerLock[ cont ] );
860 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
863 base = ATA_GetBasePort(Disk);
866 gaATA_IRQs[cont] = 0;
869 outb(base+0x01, 0x00);
870 if( Address > 0x0FFFFFFF ) // Use LBA48
872 outb(base+0x6, 0x40 | (disk << 4));
873 outb(base+0x2, 0 >> 8); // Upper Sector Count
874 outb(base+0x3, Address >> 24); // Low 2 Addr
875 outb(base+0x3, Address >> 28); // Mid 2 Addr
876 outb(base+0x3, Address >> 32); // High 2 Addr
880 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
883 outb(base+0x02, (Uint8) Count); // Sector Count
884 outb(base+0x03, (Uint8) Address); // Low Addr
885 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
886 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
888 LOG("Starting Transfer");
891 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
892 if( Address > 0x0FFFFFFF )
893 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
895 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
897 if( Address > 0x0FFFFFFF )
898 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
900 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
902 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
905 // Wait for transfer to complete
906 //ATA_int_BusMasterWriteByte( (cont << 3) + 2, 0x4 );
907 while( gaATA_IRQs[cont] == 0 ) {
908 //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 );
909 //LOG("val = 0x%02x", val);
914 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
916 LOG("Transfer Completed & Acknowledged");
918 // Copy to destination buffer
919 memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
921 // Release controller lock
922 RELEASE( &giaATA_ControllerLock[ cont ] );
929 * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
931 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
933 int cont = (Disk>>1)&1; // Controller ID
937 // Check if the count is small enough
938 if(Count > MAX_DMA_SECTORS) return 0;
940 // Get exclusive access to the disk controller
941 LOCK( &giaATA_ControllerLock[ cont ] );
944 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
947 base = ATA_GetBasePort(Disk);
950 outb(base+0x01, 0x00);
951 if( Address > 0x0FFFFFFF ) // Use LBA48
953 outb(base+0x6, 0x40 | (disk << 4));
954 outb(base+0x2, 0 >> 8); // Upper Sector Count
955 outb(base+0x3, Address >> 24); // Low 2 Addr
956 outb(base+0x3, Address >> 28); // Mid 2 Addr
957 outb(base+0x3, Address >> 32); // High 2 Addr
961 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
964 outb(base+0x02, (Uint8) Count); // Sector Count
965 outb(base+0x03, (Uint8) Address); // Low Addr
966 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
967 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
968 if( Address > 0x0FFFFFFF )
969 outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
971 outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
974 gaATA_IRQs[cont] = 0;
976 // Copy to output buffer
977 memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
980 ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
982 // Wait for transfer to complete
983 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
986 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
988 // Release controller lock
989 RELEASE( &giaATA_ControllerLock[ cont ] );
995 * \fn void ATA_IRQHandlerPri(int unused)
997 void ATA_IRQHandlerPri(int unused)
1001 // IRQ bit set for Primary Controller
1002 val = ATA_int_BusMasterReadByte( 0x2 );
1003 LOG("IRQ val = 0x%x", val);
1005 LOG("IRQ hit (val = 0x%x)", val);
1006 ATA_int_BusMasterWriteByte( 0x2, 4 );
1013 * \fn void ATA_IRQHandlerSec(int unused)
1015 void ATA_IRQHandlerSec(int unused)
1018 // IRQ bit set for Secondary Controller
1019 val = ATA_int_BusMasterReadByte( 0xA );
1021 LOG("IRQ hit (val = 0x%x)", val);
1022 ATA_int_BusMasterWriteByte( 0xA, 4 );
1029 * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
1031 Uint8 ATA_int_BusMasterReadByte(int Ofs)
1033 if( gATA_BusMasterBase & 1 )
1034 return inb( (gATA_BusMasterBase & ~1) + Ofs );
1036 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
1040 * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
1041 * \brief Writes a byte to a Bus Master Register
1043 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
1045 if( gATA_BusMasterBase & 1 )
1046 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
1048 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
1052 * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
1053 * \brief Writes a dword to a Bus Master Register
1055 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
1058 if( gATA_BusMasterBase & 1 )
1059 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
1061 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;