2 * Acess2 IDE Harddisk Driver
11 #include <tpl_drv_common.h>
12 #include <tpl_drv_disk.h>
16 #define START_BEFORE_CMD 0
24 } __attribute__ ((packed)) tPRDT_Ent;
28 Uint16 Usused1[9]; // 10
29 char SerialNum[20]; // 20
30 Uint16 Usused2[3]; // 23
31 char FirmwareVer[8]; // 27
32 char ModelNumber[40]; // 47
33 Uint16 SectPerInt; // 48 - AND with 0xFF to get true value;
35 Uint16 Capabilities[2]; // 51
36 Uint16 Unused4[2]; // 53
37 Uint16 ValidExtData; // 54
38 Uint16 Unused5[5]; // 59
39 Uint16 SizeOfRWMultiple; // 60
40 Uint32 Sectors28; // 62
41 Uint16 Unused6[100-62];
43 Uint16 Unused7[256-104];
44 } __attribute__ ((packed)) tIdentify;
47 extern void ATA_ParseMBR(int Disk);
52 void ATA_SetupPartitions();
54 int ATA_ScanDisk(int Disk);
55 void ATA_ParseGPT(int Disk);
56 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
57 Uint16 ATA_GetBasePort(int Disk);
58 // Filesystem Interface
59 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
60 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
61 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
62 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
63 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
64 // Read/Write Interface/Quantiser
65 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
66 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
68 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
69 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
71 void ATA_IRQHandlerPri(int unused);
72 void ATA_IRQHandlerSec(int unused);
74 Uint8 ATA_int_BusMasterReadByte(int Ofs);
75 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
76 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
79 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
80 tDevFS_Driver gATA_DriverInfo = {
85 .Flags = VFS_FFLAG_DIRECTORY,
86 .ACLs = &gVFS_ACL_EveryoneRX,
87 .ReadDir = ATA_ReadDir,
88 .FindDir = ATA_FindDir
91 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
93 tVFS_Node **gATA_Nodes;
94 Uint16 gATA_BusMasterBase = 0;
95 Uint8 *gATA_BusMasterBasePtr = 0;
98 int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
99 Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
100 int gaATA_IRQs[2] = {0};
101 tPRDT_Ent gATA_PRDTs[2] = {
102 {0, 512, IDE_PRDT_LAST},
103 {0, 512, IDE_PRDT_LAST}
108 * \fn int ATA_Install()
115 if(ret != 1) return ret;
117 ATA_SetupPartitions();
121 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
122 return MODULE_INIT_FAILURE;
124 return MODULE_INIT_SUCCESS;
128 * \fn int ATA_SetupIO()
129 * \brief Sets up the ATA controller's DMA mode
138 // Get IDE Controller's PCI Entry
139 ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
140 LOG("ent = %i", ent);
141 gATA_BusMasterBase = PCI_GetBAR4( ent );
142 if( gATA_BusMasterBase == 0 ) {
143 Warning("It seems that there is no Bus Master Controller on this machine. Get one");
144 LEAVE('i', MODULE_INIT_FAILURE);
145 return MODULE_INIT_FAILURE;
147 if( !(gATA_BusMasterBase & 1) )
149 if( gATA_BusMasterBase < 0x100000 )
150 gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
152 gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
153 LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
156 // Bit 0 is left set as a flag to other functions
157 LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
160 IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
161 IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
163 gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
164 gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
166 LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
168 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
169 LOG("addr = 0x%x", addr);
170 ATA_int_BusMasterWriteDWord(4, addr);
171 addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
172 LOG("addr = 0x%x", addr);
173 ATA_int_BusMasterWriteDWord(12, addr);
175 outb(IDE_PRI_BASE+1, 1);
176 outb(IDE_SEC_BASE+1, 1);
178 LEAVE('i', MODULE_INIT_SUCCESS);
179 return MODULE_INIT_SUCCESS;
183 * \fn void ATA_SetupPartitions()
185 void ATA_SetupPartitions()
188 for( i = 0; i < MAX_ATA_DISKS; i ++ )
190 if( !ATA_ScanDisk(i) ) {
191 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
198 * \fn void ATA_SetupVFS()
199 * \brief Sets up the ATA drivers VFS information and registers with DevFS
205 // Count number of nodes needed
207 for( i = 0; i < MAX_ATA_DISKS; i++ )
209 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
211 giATA_NumNodes += gATA_Disks[i].NumPartitions;
214 // Allocate Node space
215 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
219 for( i = 0; i < MAX_ATA_DISKS; i++ )
221 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
222 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
223 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
224 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
227 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
231 * \fn int ATA_ScanDisk(int Disk)
233 int ATA_ScanDisk(int Disk)
236 tIdentify *identify = (void*)buf;
237 tMBR *mbr = (void*)buf;
243 ENTER("iDisk", Disk);
245 base = ATA_GetBasePort( Disk );
247 LOG("base = 0x%x", base);
249 // Send Disk Selector
250 if(Disk == 1 || Disk == 3)
257 val = inb(base+7); // Read status
260 return 0; // Disk does not exist
263 // Poll until BSY clears and DRQ sets or ERR is set
264 while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7);
268 return 0; // Error occured, so return false
272 for(i=0;i<256;i++) buf[i] = inw(base);
274 // Populate Disk Structure
275 if(identify->Sectors48 != 0)
276 gATA_Disks[ Disk ].Sectors = identify->Sectors48;
278 gATA_Disks[ Disk ].Sectors = identify->Sectors28;
281 LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors);
283 if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
284 Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
285 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
286 else if( gATA_Disks[ Disk ].Sectors / 2048 )
287 Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
288 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
290 Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
291 gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
294 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
295 gATA_Disks[ Disk ].Name[1] = '\0';
297 // Get pointer to vfs node and populate it
298 node = &gATA_Disks[ Disk ].Node;
299 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
300 node->NumACLs = 0; // Means Superuser only can access it
301 node->Inode = (Disk << 8) | 0xFF;
302 node->ImplPtr = gATA_Disks[ Disk ].Name;
304 node->ATime = node->MTime
305 = node->CTime = now();
307 node->Read = ATA_ReadFS;
308 node->Write = ATA_WriteFS;
309 node->IOCtl = ATA_IOCtl;
312 // --- Scan Partitions ---
315 ATA_ReadDMA( Disk, 0, 1, mbr );
317 // Check for a GPT table
318 if(mbr->Parts[0].SystemID == 0xEE)
320 else // No? Just parse the MBR
328 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
329 * \brief Fills a parition's information structure
331 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
333 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
335 Part->Length = Length;
336 Part->Name[0] = 'A'+Disk;
338 Part->Name[1] = '1'+Num/10;
339 Part->Name[2] = '1'+Num%10;
340 Part->Name[3] = '\0';
342 Part->Name[1] = '1'+Num;
343 Part->Name[2] = '\0';
345 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
346 Part->Node.Inode = (Disk << 8) | Num;
347 Part->Node.ImplPtr = Part->Name;
349 Part->Node.Read = ATA_ReadFS;
350 Part->Node.Write = ATA_WriteFS;
351 Part->Node.IOCtl = ATA_IOCtl;
352 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
357 * \fn void ATA_ParseGPT(int Disk)
358 * \brief Parses the GUID Partition Table
360 void ATA_ParseGPT(int Disk)
362 ///\todo Support GPT Disks
363 Warning("GPT Disks are currently unsupported");
367 * \fn Uint16 ATA_GetPortBase(int Disk)
368 * \brief Returns the base port for a given disk
370 Uint16 ATA_GetBasePort(int Disk)
374 case 0: case 1: return IDE_PRI_BASE;
375 case 2: case 3: return IDE_SEC_BASE;
381 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
383 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
385 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
386 return strdup( gATA_Nodes[Pos]->ImplPtr );
390 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
392 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
395 // Check first character
396 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
399 if(Name[1] == '\0') {
400 if( gATA_Disks[Name[0]-'A'].Sectors == 0 )
402 return &gATA_Disks[Name[0]-'A'].Node;
406 if(Name[1] < '0' || '9' < Name[1]) return NULL;
407 if(Name[2] == '\0') { // <= 9
408 part = Name[1] - '0';
410 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
413 if('0' > Name[2] || '9' < Name[2]) return NULL;
414 if(Name[3] != '\0') return NULL;
416 part = (Name[1] - '0') * 10;
417 part += Name[2] - '0';
419 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
424 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
426 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
428 int disk = Node->Inode >> 8;
429 int part = Node->Inode & 0xFF;
434 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
436 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
437 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
442 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
444 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
445 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
446 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
449 //Log("ATA_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
450 return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
454 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
456 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
458 int disk = Node->Inode >> 8;
459 int part = Node->Inode & 0xFF;
464 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
466 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
467 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
472 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
474 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
475 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
476 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
479 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
480 Debug_HexDump("ATA_WriteFS", Buffer, Length);
481 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
485 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
486 * \brief IO Control Funtion
488 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
492 case DRV_IOCTL_TYPE: return DRV_TYPE_DISK;
497 // --- Disk Access ---
499 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
501 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
507 // Pass straight on to ATA_ReadDMAPage if we can
508 if(Count <= MAX_DMA_SECTORS)
510 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
511 if(ret == 0) return 0;
515 // Else we will have to break up the transfer
517 while(Count > MAX_DMA_SECTORS)
519 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
521 if(ret != 1) return done;
523 done += MAX_DMA_SECTORS;
524 Count -= MAX_DMA_SECTORS;
525 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
528 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
529 if(ret != 1) return 0;
534 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
536 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
542 // Pass straight on to ATA_WriteDMA if we can
543 if(Count <= MAX_DMA_SECTORS)
545 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
546 if(ret == 0) return 0;
550 // Else we will have to break up the transfer
552 while(Count > MAX_DMA_SECTORS)
554 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
556 if(ret != 1) return done;
558 done += MAX_DMA_SECTORS;
559 Count -= MAX_DMA_SECTORS;
560 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
563 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
564 if(ret != 1) return 0;
569 * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
571 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
573 int cont = (Disk>>1)&1; // Controller ID
577 ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
579 // Check if the count is small enough
580 if(Count > MAX_DMA_SECTORS) {
581 Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
582 Count, MAX_DMA_SECTORS);
587 // Get exclusive access to the disk controller
588 LOCK( &giaATA_ControllerLock[ cont ] );
591 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
594 base = ATA_GetBasePort(Disk);
597 gaATA_IRQs[cont] = 0;
600 outb(base+0x01, 0x00);
601 if( Address > 0x0FFFFFFF ) // Use LBA48
603 outb(base+0x6, 0x40 | (disk << 4));
604 outb(base+0x2, 0 >> 8); // Upper Sector Count
605 outb(base+0x3, Address >> 24); // Low 2 Addr
606 outb(base+0x3, Address >> 28); // Mid 2 Addr
607 outb(base+0x3, Address >> 32); // High 2 Addr
611 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
614 outb(base+0x02, (Uint8) Count); // Sector Count
615 outb(base+0x03, (Uint8) Address); // Low Addr
616 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
617 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
619 LOG("Starting Transfer");
622 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
623 if( Address > 0x0FFFFFFF )
624 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
626 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
628 if( Address > 0x0FFFFFFF )
629 outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
631 outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
633 ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start
636 // Wait for transfer to complete
637 //ATA_int_BusMasterWriteByte( (cont << 3) + 2, 0x4 );
638 while( gaATA_IRQs[cont] == 0 ) {
639 //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 );
640 //LOG("val = 0x%02x", val);
645 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
647 LOG("Transfer Completed & Acknowledged");
649 // Copy to destination buffer
650 memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
652 // Release controller lock
653 RELEASE( &giaATA_ControllerLock[ cont ] );
660 * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
662 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
664 int cont = (Disk>>1)&1; // Controller ID
668 // Check if the count is small enough
669 if(Count > MAX_DMA_SECTORS) return 0;
671 // Get exclusive access to the disk controller
672 LOCK( &giaATA_ControllerLock[ cont ] );
675 gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
678 base = ATA_GetBasePort(Disk);
681 outb(base+0x01, 0x00);
682 if( Address > 0x0FFFFFFF ) // Use LBA48
684 outb(base+0x6, 0x40 | (disk << 4));
685 outb(base+0x2, 0 >> 8); // Upper Sector Count
686 outb(base+0x3, Address >> 24); // Low 2 Addr
687 outb(base+0x3, Address >> 28); // Mid 2 Addr
688 outb(base+0x3, Address >> 32); // High 2 Addr
692 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
695 outb(base+0x02, (Uint8) Count); // Sector Count
696 outb(base+0x03, (Uint8) Address); // Low Addr
697 outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
698 outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
699 if( Address > 0x0FFFFFFF )
700 outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
702 outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
705 gaATA_IRQs[cont] = 0;
707 // Copy to output buffer
708 memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
711 ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
713 // Wait for transfer to complete
714 while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
717 ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
719 // Release controller lock
720 RELEASE( &giaATA_ControllerLock[ cont ] );
726 * \fn void ATA_IRQHandlerPri(int unused)
728 void ATA_IRQHandlerPri(int unused)
732 // IRQ bit set for Primary Controller
733 val = ATA_int_BusMasterReadByte( 0x2 );
734 LOG("IRQ val = 0x%x", val);
736 LOG("IRQ hit (val = 0x%x)", val);
737 ATA_int_BusMasterWriteByte( 0x2, 4 );
744 * \fn void ATA_IRQHandlerSec(int unused)
746 void ATA_IRQHandlerSec(int unused)
749 // IRQ bit set for Secondary Controller
750 val = ATA_int_BusMasterReadByte( 0xA );
751 LOG("IRQ val = 0x%x", val);
753 LOG("IRQ hit (val = 0x%x)", val);
754 ATA_int_BusMasterWriteByte( 0xA, 4 );
761 * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
763 Uint8 ATA_int_BusMasterReadByte(int Ofs)
765 if( gATA_BusMasterBase & 1 )
766 return inb( (gATA_BusMasterBase & ~1) + Ofs );
768 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
772 * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
773 * \brief Writes a byte to a Bus Master Register
775 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
777 if( gATA_BusMasterBase & 1 )
778 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
780 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
784 * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
785 * \brief Writes a dword to a Bus Master Register
787 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
790 if( gATA_BusMasterBase & 1 )
791 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
793 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;