126 lines
3.8 KiB
C++
126 lines
3.8 KiB
C++
#include "ArchInterrupts.h"
|
|
#include "BDDriver.h"
|
|
#include "BDRequest.h"
|
|
#include "BDVirtualDevice.h"
|
|
#include "kstring.h"
|
|
#include "debug.h"
|
|
#include "kprintf.h"
|
|
|
|
BDVirtualDevice::BDVirtualDevice(BDDriver * driver, uint32 offset, uint32 num_sectors, uint32 sector_size,
|
|
const char *name, bool writable) :
|
|
offset_(offset), num_sectors_(num_sectors), sector_size_(sector_size), block_size_(sector_size),
|
|
writable_(writable), driver_(driver), partition_type_(0), name_(name)
|
|
{
|
|
|
|
debug(BD_VIRT_DEVICE, "ctor: offset = %d, num_sectors = %d,\n sector_size = %d, "
|
|
"name = %s \n",
|
|
offset, num_sectors, sector_size, name);
|
|
dev_number_ = 0;
|
|
}
|
|
|
|
void BDVirtualDevice::addRequest(BDRequest * command)
|
|
{
|
|
command->setResult(5);
|
|
switch (command->getCmd())
|
|
{
|
|
case BDRequest::BD_GET_BLK_SIZE:
|
|
command->setResult(block_size_);
|
|
command->setStatus(BDRequest::BD_DONE);
|
|
break;
|
|
case BDRequest::BD_GET_NUM_BLOCKS:
|
|
command->setResult(getNumBlocks());
|
|
command->setStatus(BDRequest::BD_DONE);
|
|
break;
|
|
case BDRequest::BD_READ:
|
|
case BDRequest::BD_WRITE:
|
|
//start block and num blocks will be interpreted as start sector and num sectors
|
|
command->setStartBlock(command->getStartBlock() * (block_size_ / sector_size_) + offset_);
|
|
command->setNumBlocks(command->getNumBlocks() * (block_size_ / sector_size_));
|
|
// fall-through
|
|
default:
|
|
command->setResult(driver_->addRequest(command));
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
int32 BDVirtualDevice::readData(uint32 offset, uint32 size, char *buffer)
|
|
{
|
|
assert(buffer);
|
|
assert(offset % block_size_ == 0 && "we can only read multiples of block_size_ from the device");
|
|
assert(size % block_size_ == 0 && "we can only read multiples of block_size_ from the device");
|
|
|
|
assert((offset + size <= getNumBlocks() * block_size_) && "tried reading out of range");
|
|
|
|
debug(BD_VIRT_DEVICE, "readData\n");
|
|
uint32 blocks2read = size / block_size_, jiffies = 0;
|
|
uint32 blockoffset = offset / block_size_;
|
|
|
|
debug(BD_VIRT_DEVICE, "blocks2read %d\n", blocks2read);
|
|
BDRequest bd(dev_number_, BDRequest::BD_READ, blockoffset, blocks2read, buffer);
|
|
addRequest(&bd);
|
|
|
|
if (driver_->irq != 0)
|
|
{
|
|
bool interrupt_context = ArchInterrupts::disableInterrupts();
|
|
ArchInterrupts::enableInterrupts();
|
|
|
|
while (bd.getStatus() == BDRequest::BD_QUEUED && jiffies++ < IO_TIMEOUT)
|
|
ArchInterrupts::yieldIfIFSet();
|
|
|
|
if (!interrupt_context)
|
|
ArchInterrupts::disableInterrupts();
|
|
}
|
|
|
|
if (bd.getStatus() != BDRequest::BD_DONE)
|
|
{
|
|
return -1;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
int32 BDVirtualDevice::writeData(uint32 offset, uint32 size, char *buffer)
|
|
{
|
|
assert(offset % block_size_ == 0 && "we can only write multiples of block_size_ to the device");
|
|
assert(size % block_size_ == 0 && "we can only write multiples of block_size_ to the device");
|
|
|
|
assert((offset + size <= getNumBlocks() * block_size_) && "tried writing out of range");
|
|
|
|
debug(BD_VIRT_DEVICE, "writeData\n");
|
|
uint32 blocks2write = size / block_size_, jiffies = 0;
|
|
uint32 blockoffset = offset / block_size_;
|
|
|
|
BDRequest bd(dev_number_, BDRequest::BD_WRITE, blockoffset, blocks2write, buffer);
|
|
addRequest(&bd);
|
|
|
|
if (driver_->irq != 0)
|
|
{
|
|
bool interrupt_context = ArchInterrupts::disableInterrupts();
|
|
ArchInterrupts::enableInterrupts();
|
|
|
|
while (bd.getStatus() == BDRequest::BD_QUEUED && jiffies++ < IO_TIMEOUT)
|
|
ArchInterrupts::yieldIfIFSet();
|
|
|
|
if (!interrupt_context)
|
|
ArchInterrupts::disableInterrupts();
|
|
}
|
|
|
|
if (bd.getStatus() != BDRequest::BD_DONE)
|
|
return -1;
|
|
else
|
|
return size;
|
|
}
|
|
|
|
|
|
void BDVirtualDevice::setPartitionType(uint8 part_type)
|
|
{
|
|
partition_type_ = part_type;
|
|
}
|
|
|
|
uint8 BDVirtualDevice::getPartitionType(void) const
|
|
{
|
|
return partition_type_;
|
|
}
|