Implemented BIOSDrive::WriteAt(). Currently it supports only LBA addressing

and requires position and size to be block-aligned.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35881 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-03-16 17:10:00 +00:00
parent fac2ce3d92
commit d1367a37cc

View File

@ -33,6 +33,7 @@ extern uint32 gBootPartitionOffset;
#define BIOS_GET_DRIVE_PARAMETERS 0x0800
#define BIOS_IS_EXT_PRESENT 0x4100
#define BIOS_EXT_READ 0x4200
#define BIOS_EXT_WRITE 0x4300
#define BIOS_GET_EXT_DRIVE_PARAMETERS 0x4800
#define BIOS_BOOT_CD_GET_STATUS 0x4b01
@ -707,10 +708,65 @@ BIOSDrive::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
ssize_t
BIOSDrive::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
BIOSDrive::WriteAt(void* cookie, off_t pos, const void* buffer,
size_t bufferSize)
{
// we don't have to know how to write
return B_NOT_ALLOWED;
// we support only LBA addressing
if (!fLBA) {
dprintf("BIOSDrive::WriteAt(): CHS addressing not supported\n");
return B_UNSUPPORTED;
}
// we support only block-aligned writes
if (pos % fBlockSize != 0 || bufferSize % fBlockSize != 0) {
dprintf("BIOSDrive::WriteAt(pos: %" B_PRIdOFF ", size: %" B_PRIuSIZE
"): Block-unaligned write not supported.\n", pos, bufferSize);
return B_UNSUPPORTED;
}
pos /= fBlockSize;
uint32 blocksLeft = bufferSize / fBlockSize;
int32 totalBytesWritten = 0;
uint32 scratchSize = 24 * 1024 / fBlockSize;
// maximum value allowed by Phoenix BIOS is 0x7f
while (blocksLeft > 0) {
uint32 blocksToWrite = blocksLeft;
if (blocksToWrite > scratchSize)
blocksToWrite = scratchSize;
uint32 bytesToWrite = blocksToWrite * fBlockSize;
memcpy((void*)kExtraSegmentScratch, buffer, bytesToWrite);
struct disk_address_packet* packet
= (disk_address_packet*)kDataSegmentScratch;
memset(packet, 0, sizeof(disk_address_packet));
packet->size = sizeof(disk_address_packet);
packet->number_of_blocks = blocksToWrite;
packet->buffer = kExtraSegmentScratch;
packet->lba = pos;
struct bios_regs regs;
regs.eax = BIOS_EXT_WRITE; // al = 0x00 -- no write verify
regs.edx = fDriveID;
regs.esi = (addr_t)packet - kDataSegmentBase;
call_bios(0x13, &regs);
if (regs.flags & CARRY_FLAG)
return B_ERROR;
pos += blocksToWrite;
blocksLeft -= blocksToWrite;
bufferSize -= bytesToWrite;
buffer = (void*)((addr_t)buffer + bytesToWrite);
totalBytesWritten += bytesToWrite;
}
return totalBytesWritten;
}