Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
-// Disk Read
+// Read/Write Interface/Quantiser
Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+// Read/Write DMA
int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
-// Disk Write
+ int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
// IRQs
void ATA_IRQHandlerPri(int unused);
void ATA_IRQHandlerSec(int unused);
= node->CTime = now();
node->Read = ATA_ReadFS;
- //node->Write = ATA_WriteFS;
+ node->Write = ATA_WriteFS;
node->IOCtl = ATA_IOCtl;
Part->Node.ImplPtr = Part->Name;
Part->Node.Read = ATA_ReadFS;
+ Part->Node.Write = ATA_WriteFS;
Part->Node.IOCtl = ATA_IOCtl;
LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
LEAVE('-');
*/
Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
{
- return 0;
+ int disk = Node->Inode >> 8;
+ int part = Node->Inode & 0xFF;
+
+ // Raw Disk Access
+ if(part == 0xFF)
+ {
+ if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
+ return 0;
+ if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
+ Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
+ }
+ // Partition
+ else
+ {
+ if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+ return 0;
+ if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+ Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
+ Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
+ }
+
+ Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
+ Debug_HexDump("ATA_WriteFS", Buffer, Length);
+ return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
}
/**
return done+Count;
}
+/**
+ * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ */
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+{
+ int ret;
+ Uint offset;
+ Uint done = 0;
+
+ // Pass straight on to ATA_ReadDMAPage if we can
+ if(Count <= MAX_DMA_SECTORS)
+ {
+ ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
+ if(ret == 0) return 0;
+ return Count;
+ }
+
+ // Else we will have to break up the transfer
+ offset = 0;
+ while(Count > MAX_DMA_SECTORS)
+ {
+ ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
+ // Check for errors
+ if(ret != 1) return done;
+ // Change Position
+ done += MAX_DMA_SECTORS;
+ Count -= MAX_DMA_SECTORS;
+ offset += MAX_DMA_SECTORS*SECTOR_SIZE;
+ }
+
+ ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
+ if(ret != 1) return 0;
+ return done+Count;
+}
+
/**
* \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
*/
return 1;
}
+/**
+ * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ */
+int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+ int cont = (Disk>>1)&1; // Controller ID
+ int disk = Disk & 1;
+ Uint16 base;
+
+ // Check if the count is small enough
+ if(Count > MAX_DMA_SECTORS) return 0;
+
+ // Get exclusive access to the disk controller
+ LOCK( &giaATA_ControllerLock[ cont ] );
+
+ // Set Size
+ gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+
+ // Get Port Base
+ base = ATA_GetBasePort(Disk);
+
+ // Set up transfer
+ outb(base+0x01, 0x00);
+ if( Address > 0x0FFFFFFF ) // Use LBA48
+ {
+ outb(base+0x6, 0x40 | (disk << 4));
+ outb(base+0x2, 0 >> 8); // Upper Sector Count
+ outb(base+0x3, Address >> 24); // Low 2 Addr
+ outb(base+0x3, Address >> 28); // Mid 2 Addr
+ outb(base+0x3, Address >> 32); // High 2 Addr
+ }
+ else
+ {
+ outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
+ }
+
+ outb(base+0x02, (Uint8) Count); // Sector Count
+ outb(base+0x03, (Uint8) Address); // Low Addr
+ outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
+ outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
+ if( Address > 0x0FFFFFFF )
+ outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
+ else
+ outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
+
+ // Reset IRQ Flag
+ gaATA_IRQs[cont] = 0;
+
+ // Copy to output buffer
+ memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
+
+ // Start transfer
+ ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
+
+ // Wait for transfer to complete
+ while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
+
+ // Complete Transfer
+ ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
+
+ // Release controller lock
+ RELEASE( &giaATA_ControllerLock[ cont ] );
+
+ return 1;
+}
+
/**
* \fn void ATA_IRQHandlerPri(int unused)
*/
*
* See: ~/Sources/bochs/bochs.../iodev/ne2k.cc
*/
+#define DEBUG 1
#include <common.h>
#include <modules.h>
#include <fs_devfs.h>
outb( base + IMR, 0x00 );
outb( base + ISR, 0xFF );
outb( base + RCR, 0x20 ); // Reciever to Monitor
- outb( base + TCR, 0x02 ); // Transmitter OFF
+ outb( base + TCR, 0x02 ); // Transmitter OFF (TCR.LB = 1, Internal Loopback)
outb( base + RBCR0, 6*4 ); // Remote Byte Count
outb( base + RBCR1, 0 );
outb( base + RSAR0, 0 ); // Clear Source Address
outb( base+ISR, 0xFF ); // Clear all ints
outb( base+CMD, 0x22 ); // No DMA, Start
outb( base+IMR, 0x3F ); // Set Interupt Mask
- outb( base+RCR, 0x8F ); // Set WRAP and allow all packet matches
+ outb( base+RCR, 0x0F ); // Set WRAP and allow all packet matches
outb( base+TCR, 0x00 ); // Set Normal Transmitter mode
outb( base+TPSR, 0x40); // Set Transmit Start
// Set MAC Address
Uint16 *buf = Buffer;
int rem = Length;
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
// Sanity Check Length
- if(Length > TX_BUF_SIZE) return 0;
+ if(Length > TX_BUF_SIZE) {
+ LEAVE('i', 0);
+ return 0;
+ }
outb(Card->IOBase + CMD, 0|0x22); // Page 0, Start, NoDMA
- // Send Size
+ // Send Size - Transmit Byte Count Register
+ outb(Card->IOBase + TBCR0, Length & 0xFF);
+ outb(Card->IOBase + TBCR1, Length >> 8);
+ // Send Size - Remote Byte Count Register
outb(Card->IOBase + RBCR0, Length & 0xFF);
outb(Card->IOBase + RBCR1, Length >> 8);
// Clear Remote DMA Flag
outb(Card->IOBase + RSAR0, 0x00); // Page Offset
outb(Card->IOBase + RSAR1, Ne2k_int_GetWritePage(Card, Length)); // Page Offset
// Start
- outb(Card->IOBase + CMD, 0|0x12); // Page 0, Start, DMA
+ outb(Card->IOBase + CMD, 0|0x18|0x4|0x2); // Page 0, Transmit Packet, TXP, Start
// Send Data
for(rem = Length; rem; rem -= 2)
outw(Card->IOBase + 0x10, *buf++);
- return 0;
+
+ // Complete DMA
+ outb(Card->IOBase + CMD, 0|0x20);
+
+ LEAVE('i', Length);
+ return Length;
}
/**
Uint64 allocSize;\r
int bNewBlocks = 0;\r
\r
+ Debug_HexDump("Ext2_Write", Buffer, Length);\r
+ \r
Ext2_int_GetInode(Node, &inode);\r
\r
- // Round size up to block size\r
- // block size is a power of two, so this will work\r
+ // Get the ammount of space already allocated\r
+ // - Round size up to block size\r
+ // - block size is a power of two, so this will work\r
allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);\r
+ \r
+ // Are we writing to inside the allocated space?\r
if( Offset < allocSize )\r
{\r
+ // Will we go out of it?\r
if(Offset + Length > allocSize) {\r
bNewBlocks = 1;\r
retLen = allocSize - Offset;\r
} else\r
retLen = Length;\r
+ \r
// Within the allocated space\r
block = Offset / disk->BlockSize;\r
Offset %= disk->BlockSize;\r
// Write only block (if only one)\r
if(Offset + retLen <= disk->BlockSize) {\r
VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);\r
- if(bNewBlocks) return Length;\r
+ if(!bNewBlocks) return Length;\r
goto addBlocks; // Ugh! A goto, but it seems unavoidable\r
}\r
\r
// Write last block\r
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
VFS_WriteAt(disk->FD, base, retLen, Buffer);\r
- if(bNewBlocks) return Length; // Writing in only allocated space\r
+ if(!bNewBlocks) return Length; // Writing in only allocated space\r
}\r
\r
addBlocks:\r