genode/os/src/drivers/atapi/ata_device.h
Sebastian Sumpf 2dce04618e atapi_drv: Implement LBA48 specific block count
Use NATIVE MAX ADDRESS EXT to retrieve last block for LBA48. Also check not only
for enabled LBA48 support but for the 'host protected area' bit before using the
LBA48 version. This is because the high order byte (HOB) data retrieval is
broken in Qemu.

Fixes #761.
2013-07-11 12:44:18 +02:00

163 lines
3.8 KiB
C++

/*
* \brief ATA device class
* \author Sebastian.Sump <Sebastian.Sumpf@genode-labs.com>
* \date 2010-07-15
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ATA_DEVICE_H_
#define _ATA_DEVICE_H_
#include <base/exception.h>
#include <base/stdint.h>
namespace Genode {
class Io_port_session;
class Irq_connection;
}
namespace Ata {
class Bus_master;
class Device
{
/* I/O back end may access private data (see io.cc) */
friend Genode::Io_port_session *get_io(Device *dev);
friend Genode::Irq_connection *get_irq(Device *dev);
friend Bus_master *get_bus_master(Device *dev);
protected:
unsigned char _dev_num;
Genode::Io_port_session *_pio;
Genode::Irq_connection *_irq;
Bus_master *_bus_master;
bool _dma;
unsigned _block_start;
unsigned _block_end;
unsigned _block_size;
Genode::addr_t _base_addr;
bool _lba48;
bool _host_protected_area;
protected:
void probe_dma();
void set_bus_master(bool secondary);
void set_irq(unsigned irq);
void set_dev_num(unsigned char dev_num) { _dev_num = dev_num; }
unsigned char dev_num() { return _dev_num; }
Bus_master *bus_master(){ return _bus_master; }
Genode::Irq_connection *irq() { return _irq; }
Genode::Io_port_session *io() { return _pio; }
public:
/**
* Constructor
*
* \param base_cmd I/O port base of command registers
* \param base_ctrl I/O prot base of control registers
*/
Device(unsigned base_cmd, unsigned base_ctrl);
~Device();
/**
* Return and set current device
*/
static Device * current(Device *dev = 0)
{
static Device *_current = 0;
if (dev) _current = dev;
return _current;
}
/**
* Probe legacy bus for device class
*
* \param search_type REG_CONFIG_TYPE_ATA or REG_CONFIG_TYPE_ATAPI
*/
static Device * probe_legacy(int search_type);
/**
* Return number of blocks
*/
unsigned block_count() { return _block_end - _block_start + 1; }
/**
* Return actual block size in bytes
*/
unsigned block_size() { return _block_size; }
/**
* Read block size and block count (from device),
* updates block_count and block_size
*/
virtual void read_capacity();
/**
* Read one or more blocks from the device
*
* \param block_nr Block number to read
* \param count Number of blocks to read
* \param offset Offset in I/O buffer
*/
virtual void read(unsigned long block_nr,
unsigned long count, Genode::off_t offset);
/**
* Write one or more blocks to the device
*
* \param block_nr Block number to read
* \param count Number of blocks to read
* \param offset Offset in I/O buffer
*/
virtual void write(unsigned long block_nr,
unsigned long count, Genode::off_t offset);
/**
* Set I/O buffer base address
*/
void set_base_addr(Genode::addr_t addr) { _base_addr = addr; }
/**
* Return true if DMA is enabled by device
*/
bool dma_enabled() { return _dma; }
class Exception : public ::Genode::Exception { };
class Io_error : public Exception { };
};
class Atapi_device : public Device
{
private:
int read_sense(unsigned char *sense, int length);
public:
Atapi_device(unsigned base_cmd, unsigned base_ctrl);
void read_capacity();
void read(unsigned long block_nr,
unsigned long count, Genode::off_t offset);
bool test_unit_ready(int level = 0);
void write(unsigned long block_nr,
unsigned long count, Genode::off_t offset);
};
}
#endif