2 * Acess2 IDE Harddisk Driver
11 #include <tpl_drv_common.h>
12 #include <tpl_drv_disk.h>
15 #define IO_DELAY() do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
23 } __attribute__ ((packed)) tPRDT_Ent;
27 Uint16 Usused1[9]; // 10
28 char SerialNum[20]; // 20
29 Uint16 Usused2[3]; // 23
30 char FirmwareVer[8]; // 27
31 char ModelNumber[40]; // 47
32 Uint16 SectPerInt; // 48 - AND with 0xFF to get true value;
34 Uint16 Capabilities[2]; // 51
35 Uint16 Unused4[2]; // 53
36 Uint16 ValidExtData; // 54
37 Uint16 Unused5[5]; // 59
38 Uint16 SizeOfRWMultiple; // 60
39 Uint32 Sectors28; // 62
40 Uint16 Unused6[100-62];
42 Uint16 Unused7[256-104];
43 } __attribute__ ((packed)) tIdentify;
46 extern void ATA_ParseMBR(int Disk, tMBR *MBR);
51 void ATA_SetupPartitions();
53 int ATA_ScanDisk(int Disk);
54 void ATA_ParseGPT(int Disk);
55 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
56 Uint16 ATA_GetBasePort(int Disk);
57 // Filesystem Interface
58 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
59 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
60 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
61 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
62 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
63 // Read/Write Interface/Quantiser
64 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
65 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
67 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
68 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
70 void ATA_IRQHandlerPri(int unused);
71 void ATA_IRQHandlerSec(int unused);
73 Uint8 ATA_int_BusMasterReadByte(int Ofs);
74 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
75 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
78 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, "PCI", NULL);
79 tDevFS_Driver gATA_DriverInfo = {
84 .Flags = VFS_FFLAG_DIRECTORY,
85 .ACLs = &gVFS_ACL_EveryoneRX,
86 .ReadDir = ATA_ReadDir,
87 .FindDir = ATA_FindDir
90 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
92 tVFS_Node **gATA_Nodes;
93 Uint16 gATA_BusMasterBase = 0;
94 Uint8 *gATA_BusMasterBasePtr = 0;
97 int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
98 Uint8 gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
99 volatile int gaATA_IRQs[2] = {0};
100 tPRDT_Ent gATA_PRDTs[2] = {
101 {0, 512, IDE_PRDT_LAST},
102 {0, 512, IDE_PRDT_LAST}
107 * \fn int ATA_Install()
116 ATA_SetupPartitions();
120 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
121 return MODULE_ERR_MISC;
123 return MODULE_ERR_OK;
127 * \fn int ATA_SetupIO()
128 * \brief Sets up the ATA controller's DMA mode
137 // Get IDE Controller's PCI Entry
138 ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
139 LOG("ent = %i", ent);
140 gATA_BusMasterBase = PCI_GetBAR4( ent );
141 if( gATA_BusMasterBase == 0 ) {
142 Log_Warning("ATA", "It seems that there is no Bus Master Controller on this machine. Get one");
143 // TODO: Use PIO mode instead
144 LEAVE('i', MODULE_ERR_NOTNEEDED);
145 return MODULE_ERR_NOTNEEDED;
149 if( !(gATA_BusMasterBase & 1) )
151 if( gATA_BusMasterBase < 0x100000 )
152 gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
154 gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
155 LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
158 // Bit 0 is left set as a flag to other functions
159 LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
162 // Register IRQs and get Buffers
163 IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
164 IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
166 gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
167 gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
169 LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
171 addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
172 LOG("addr = 0x%x", addr);
173 ATA_int_BusMasterWriteDWord(4, addr);
174 addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
175 LOG("addr = 0x%x", addr);
176 ATA_int_BusMasterWriteDWord(12, addr);
178 // Enable controllers
179 outb(IDE_PRI_BASE+1, 1);
180 outb(IDE_SEC_BASE+1, 1);
183 LEAVE('i', MODULE_ERR_OK);
184 return MODULE_ERR_OK;
188 * \fn void ATA_SetupPartitions()
190 void ATA_SetupPartitions()
193 for( i = 0; i < MAX_ATA_DISKS; i ++ )
195 if( !ATA_ScanDisk(i) ) {
196 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
203 * \fn void ATA_SetupVFS()
204 * \brief Sets up the ATA drivers VFS information and registers with DevFS
210 // Count number of nodes needed
212 for( i = 0; i < MAX_ATA_DISKS; i++ )
214 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
216 giATA_NumNodes += gATA_Disks[i].NumPartitions;
219 // Allocate Node space
220 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
224 for( i = 0; i < MAX_ATA_DISKS; i++ )
226 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
227 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
228 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
229 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
232 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
236 * \fn int ATA_ScanDisk(int Disk)
238 int ATA_ScanDisk(int Disk)
250 ENTER("iDisk", Disk);
252 base = ATA_GetBasePort( Disk );
254 LOG("base = 0x%x", base);
256 // Send Disk Selector
257 if(Disk == 1 || Disk == 3)
263 // Check for a floating bus
264 if( 0xFF == inb(base+7) ) {
270 // Check for the controller
271 outb(base+0x02, 0x66);
272 outb(base+0x03, 0xFF);
273 if(inb(base+0x02) != 0x66 || inb(base+0x03) != 0xFF) {
274 LOG("No controller");
282 val = inb(base+7); // Read status
283 LOG("val = 0x%02x", val);
286 return 0; // Disk does not exist
289 // Poll until BSY clears and DRQ sets or ERR is set
290 while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
294 return 0; // Error occured, so return false
298 for(i=0;i<256;i++) data.buf[i] = inw(base);
300 // Populate Disk Structure
301 if(data.identify.Sectors48 != 0)
302 gATA_Disks[ Disk ].Sectors = data.identify.Sectors48;
304 gATA_Disks[ Disk ].Sectors = data.identify.Sectors28;
307 LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
310 Uint64 val = gATA_Disks[ Disk ].Sectors / 2;
316 else if( val > 4*1024 ) {
320 else if( val > 4*1024 ) {
324 Log_Log("ATA", "Disk %i: 0x%llx Sectors (%lli %s)", Disk,
325 gATA_Disks[ Disk ].Sectors, val, units);
329 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
330 gATA_Disks[ Disk ].Name[1] = '\0';
332 // Get pointer to vfs node and populate it
333 node = &gATA_Disks[ Disk ].Node;
334 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
335 node->NumACLs = 0; // Means Superuser only can access it
336 node->Inode = (Disk << 8) | 0xFF;
337 node->ImplPtr = gATA_Disks[ Disk ].Name;
339 node->ATime = node->MTime
340 = node->CTime = now();
342 node->Read = ATA_ReadFS;
343 node->Write = ATA_WriteFS;
344 node->IOCtl = ATA_IOCtl;
346 // --- Scan Partitions ---
349 ATA_ReadDMA( Disk, 0, 1, &data.mbr );
351 // Check for a GPT table
352 if(data.mbr.Parts[0].SystemID == 0xEE)
354 else // No? Just parse the MBR
355 ATA_ParseMBR(Disk, &data.mbr);
358 ATA_ReadDMA( Disk, 1, 1, &data );
359 Debug_HexDump("ATA_ScanDisk", &data, 512);
367 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
368 * \brief Fills a parition's information structure
370 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
372 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
374 Part->Length = Length;
375 Part->Name[0] = 'A'+Disk;
377 Part->Name[1] = '1'+Num/10;
378 Part->Name[2] = '1'+Num%10;
379 Part->Name[3] = '\0';
381 Part->Name[1] = '1'+Num;
382 Part->Name[2] = '\0';
384 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
385 Part->Node.Inode = (Disk << 8) | Num;
386 Part->Node.ImplPtr = Part->Name;
388 Part->Node.Read = ATA_ReadFS;
389 Part->Node.Write = ATA_WriteFS;
390 Part->Node.IOCtl = ATA_IOCtl;
391 Log_Notice("ATA", "Note '%s' at 0x%llx, 0x%llx long", Part->Name, Part->Start, Part->Length);
392 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
397 * \fn void ATA_ParseGPT(int Disk)
398 * \brief Parses the GUID Partition Table
400 void ATA_ParseGPT(int Disk)
402 ///\todo Support GPT Disks
403 Warning("GPT Disks are currently unsupported");
407 * \fn Uint16 ATA_GetPortBase(int Disk)
408 * \brief Returns the base port for a given disk
410 Uint16 ATA_GetBasePort(int Disk)
414 case 0: case 1: return IDE_PRI_BASE;
415 case 2: case 3: return IDE_SEC_BASE;
421 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
423 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
425 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
426 return strdup( gATA_Nodes[Pos]->ImplPtr );
430 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
432 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
437 // Check first character
438 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
440 disk = &gATA_Disks[Name[0]-'A'];
442 if(Name[1] == '\0') {
443 if( disk->Sectors == 0 && disk->Name[0] == '\0')
449 if(Name[1] < '0' || '9' < Name[1]) return NULL;
450 if(Name[2] == '\0') { // <= 9
451 part = Name[1] - '0';
453 return &disk->Partitions[part].Node;
456 if('0' > Name[2] || '9' < Name[2]) return NULL;
457 if(Name[3] != '\0') return NULL;
459 part = (Name[1] - '0') * 10;
460 part += Name[2] - '0';
462 return &disk->Partitions[part].Node;
467 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
469 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
471 int disk = Node->Inode >> 8;
472 int part = Node->Inode & 0xFF;
474 ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
479 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
483 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
484 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
489 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
493 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
494 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
495 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
499 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
500 Debug_HexDump("ATA_ReadFS", Buffer, Length);
507 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
509 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
511 int disk = Node->Inode >> 8;
512 int part = Node->Inode & 0xFF;
517 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
519 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
520 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
525 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
527 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
528 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
529 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
532 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
533 Debug_HexDump("ATA_WriteFS", Buffer, Length);
534 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
538 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
539 * \brief IO Control Funtion
541 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
545 case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
550 // --- Disk Access ---
552 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
554 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
560 // Pass straight on to ATA_ReadDMAPage if we can
561 if(Count <= MAX_DMA_SECTORS)
563 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
564 if(ret == 0) return 0;
568 // Else we will have to break up the transfer
570 while(Count > MAX_DMA_SECTORS)
572 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
574 if(ret != 1) return done;
576 done += MAX_DMA_SECTORS;
577 Count -= MAX_DMA_SECTORS;
578 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
581 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
582 if(ret != 1) return 0;
587 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
589 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
595 // Pass straight on to ATA_WriteDMA, if we can
596 if(Count <= MAX_DMA_SECTORS)
598 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
599 if(ret == 0) return 0;
603 // Else we will have to break up the transfer
605 while(Count > MAX_DMA_SECTORS)
607 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
609 if(ret != 1) return done;
611 done += MAX_DMA_SECTORS;
612 Count -= MAX_DMA_SECTORS;
613 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
616 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
617 if(ret != 1) return 0;
622 * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
624 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
626 int cont = (Disk>>1)&1; // Controller ID
631 ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
633 // Check if the count is small enough
634 if(Count > MAX_DMA_SECTORS) {
635 Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
636 Count, MAX_DMA_SECTORS);
641 // Get exclusive access to the disk controller
642 LOCK( &giaATA_ControllerLock[ cont ] );
645 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
648 base = ATA_GetBasePort(Disk);
651 gaATA_IRQs[cont] = 0;
654 outb(base+0x01, 0x00);
655 if( Address > 0x0FFFFFFF ) // Use LBA48
657 outb(base+0x6, 0x40 | (disk << 4));
658 outb(base+0x2, 0 >> 8); // Upper Sector Count
659 outb(base+0x3, Address >> 24); // Low 2 Addr
660 outb(base+0x4, Address >> 28); // Mid 2 Addr
661 outb(base+0x5, Address >> 32); // High 2 Addr
665 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); // Magic, Disk, High addr
668 outb(base+0x02, (Uint8) Count); // Sector Count
669 outb(base+0x03, (Uint8) Address); // Low Addr
670 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
671 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
673 LOG("Starting Transfer");
674 if( Address > 0x0FFFFFFF )
675 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
677 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
679 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
681 // Wait for transfer to complete
683 while( gaATA_IRQs[cont] == 0 && !(val & 0x4) ) {
684 val = ATA_int_BusMasterReadByte( (cont << 3) + 2 );
685 //LOG("val = 0x%02x", val);
690 ATA_int_BusMasterWriteByte( cont << 3, 8 ); // Read and stop
693 LOG("Status byte = 0x%02x", val);
695 LOG("Transfer Completed & Acknowledged");
697 // Copy to destination buffer
698 memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
700 // Release controller lock
701 RELEASE( &giaATA_ControllerLock[ cont ] );
708 * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
710 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
712 int cont = (Disk>>1)&1; // Controller ID
716 // Check if the count is small enough
717 if(Count > MAX_DMA_SECTORS) return 0;
719 // Get exclusive access to the disk controller
720 LOCK( &giaATA_ControllerLock[ cont ] );
723 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
726 base = ATA_GetBasePort(Disk);
729 outb(base+0x01, 0x00);
730 if( Address > 0x0FFFFFFF ) // Use LBA48
732 outb(base+0x6, 0x40 | (disk << 4));
733 outb(base+0x2, 0 >> 8); // Upper Sector Count
734 outb(base+0x3, Address >> 24); // Low 2 Addr
735 outb(base+0x3, Address >> 28); // Mid 2 Addr
736 outb(base+0x3, Address >> 32); // High 2 Addr
740 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
743 outb(base+0x02, (Uint8) Count); // Sector Count
744 outb(base+0x03, (Uint8) Address); // Low Addr
745 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
746 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
747 if( Address > 0x0FFFFFFF )
748 outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
750 outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
753 gaATA_IRQs[cont] = 0;
755 // Copy to output buffer
756 memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
759 ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
761 // Wait for transfer to complete
762 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
765 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
767 // Release controller lock
768 RELEASE( &giaATA_ControllerLock[ cont ] );
774 * \fn void ATA_IRQHandlerPri(int unused)
776 void ATA_IRQHandlerPri(int unused)
780 // IRQ bit set for Primary Controller
781 val = ATA_int_BusMasterReadByte( 0x2 );
782 LOG("IRQ val = 0x%x", val);
784 LOG("IRQ hit (val = 0x%x)", val);
785 ATA_int_BusMasterWriteByte( 0x2, 4 );
792 * \fn void ATA_IRQHandlerSec(int unused)
794 void ATA_IRQHandlerSec(int unused)
797 // IRQ bit set for Secondary Controller
798 val = ATA_int_BusMasterReadByte( 0xA );
799 LOG("IRQ val = 0x%x", val);
801 LOG("IRQ hit (val = 0x%x)", val);
802 ATA_int_BusMasterWriteByte( 0xA, 4 );
809 * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
811 Uint8 ATA_int_BusMasterReadByte(int Ofs)
813 if( gATA_BusMasterBase & 1 )
814 return inb( (gATA_BusMasterBase & ~1) + Ofs );
816 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
820 * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
821 * \brief Writes a byte to a Bus Master Register
823 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
825 if( gATA_BusMasterBase & 1 )
826 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
828 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
832 * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
833 * \brief Writes a dword to a Bus Master Register
835 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
838 if( gATA_BusMasterBase & 1 )
839 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
841 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;