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:
@@ -33,6 +33,7 @@ extern uint32 gBootPartitionOffset;
|
|||||||
#define BIOS_GET_DRIVE_PARAMETERS 0x0800
|
#define BIOS_GET_DRIVE_PARAMETERS 0x0800
|
||||||
#define BIOS_IS_EXT_PRESENT 0x4100
|
#define BIOS_IS_EXT_PRESENT 0x4100
|
||||||
#define BIOS_EXT_READ 0x4200
|
#define BIOS_EXT_READ 0x4200
|
||||||
|
#define BIOS_EXT_WRITE 0x4300
|
||||||
#define BIOS_GET_EXT_DRIVE_PARAMETERS 0x4800
|
#define BIOS_GET_EXT_DRIVE_PARAMETERS 0x4800
|
||||||
#define BIOS_BOOT_CD_GET_STATUS 0x4b01
|
#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
|
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
|
// we support only LBA addressing
|
||||||
return B_NOT_ALLOWED;
|
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, ®s);
|
||||||
|
|
||||||
|
if (regs.flags & CARRY_FLAG)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
pos += blocksToWrite;
|
||||||
|
blocksLeft -= blocksToWrite;
|
||||||
|
bufferSize -= bytesToWrite;
|
||||||
|
buffer = (void*)((addr_t)buffer + bytesToWrite);
|
||||||
|
totalBytesWritten += bytesToWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalBytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user