added controller probing and channel publishing

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18787 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen 2006-09-10 15:02:10 +00:00
parent c561dbbcc0
commit 8bb6ce1a81

View File

@ -6,13 +6,57 @@
#include <KernelExport.h>
#include <stdlib.h>
#include <string.h>
#include <device_manager.h>
#include <bus/ide/ide_adapter.h>
#include <block_io.h>
#define TRACE(a...) dprintf("si-3112 " a)
#define DRIVER_PRETTY_NAME "Silicon Image SATA"
#define CONTROLLER_DRIVER "silicon_image_3112"
#define CONTROLLER_NAME DRIVER_PRETTY_NAME
#define CONTROLLER_MODULE_NAME "busses/ide/silicon_image_3112/device_v1"
#define CHANNEL_MODULE_NAME "busses/ide/silicon_image_3112/channel/v1"
enum asic_type {
ASIC_SI3112 = 0,
ASIC_SI3114 = 1,
};
static const char *adapter_asic_names[] = {
"si3112",
"si3114",
NULL
};
static const struct {
uint16 channel_count;
uint32 mmio_bar_size;
} asic_data[2] = {
{ 2, 0x200 },
{ 4, 0x400 },
};
static const struct {
uint16 cmd;
uint16 ctl;
uint16 bmdma;
uint16 sien;
const char *name;
} controller_channel_data[] = {
{ 0x80, 0x8A, 0x00, 0x148, "Primary Channel" },
{ 0xC0, 0xCA, 0x08, 0x1C8, "Secondary Channel" },
{ 0x280, 0x28A, 0x200, 0x348, "Tertiary Channel" },
{ 0x2C0, 0x2CA, 0x208, 0x3C8, "Quaternary Channel" },
};
#define SI_SYSCFG 0x48
#define SI_BMDMA2 0x200
#define SI_INT_STEERING 0x02
#define SI_MASK_2PORT ((1 << 22) | (1 << 23))
#define SI_MASK_4PORT ((1 << 22) | (1 << 23) | (1 << 24) | (1 << 25))
static ide_for_controller_interface * ide;
static ide_adapter_interface * ide_adapter;
@ -22,10 +66,142 @@ static device_manager_info * dm;
static status_t
controller_probe(device_node_handle parent)
{
pci_device device;
pci_device_module_info *pci;
device_node_handle controller_node;
uint32 mmio_base;
uint16 device_id;
uint8 int_num;
int asic_index;
int chan_index;
status_t res;
TRACE("controller_probe\n");
if (dm->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
return B_ERROR;
device_id = pci->read_pci_config(device, PCI_device_id, 2);
int_num = pci->read_pci_config(device, PCI_interrupt_line, 1);
mmio_base = pci->read_pci_config(device, PCI_base_registers + 20, 4);
mmio_base &= PCI_address_io_mask;
switch (device_id) {
case 0x3112:
asic_index = ASIC_SI3112;
break;
case 0x3114:
asic_index = ASIC_SI3114;
break;
default:
TRACE("unsupported asic\n");
goto err;
}
if (!mmio_base) {
TRACE("mmio not configured\n");
goto err;
}
if (int_num == 0 || int_num == 0xff) {
TRACE("irq not configured\n");
goto err;
}
{
io_resource_handle resource_handles[2];
io_resource resources[2] = {
{ IO_MEM, mmio_base, asic_data[asic_index].mmio_bar_size },
{}
};
if (dm->acquire_io_resources(resources, resource_handles) != B_OK) {
TRACE("acquire_io_resources failed\n");
goto err;
}
{
device_attr controller_attrs[] = {
// info about ourself and our consumer
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: CONTROLLER_DRIVER }},
// properties of this controller for ide bus manager
// there are always max. 2 devices
// (unless this is a Compact Flash Card with a built-in IDE controller,
// which has exactly 1 device)
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: asic_data[asic_index].channel_count }},
// of course we can DMA
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: true }},
// command queuing always works
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: true }},
// choose any name here
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: CONTROLLER_NAME }},
// DMA properties
// data must be word-aligned;
// warning: some controllers are more picky!
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1}},
// one S/G block must not cross 64K boundary
{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
// max size of S/G block is 16 bits with zero being 64K
{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: 0x10000 }},
// see definition of MAX_SG_COUNT
{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }},
// private data to find controller
{ "silicon_image_3112/asic_index", B_UINT32_TYPE, { ui32: asic_index }},
{ "silicon_image_3112/int_num", B_UINT32_TYPE, { ui32: int_num }},
{ NULL }
};
TRACE("publishing controller");
res = dm->register_device(parent, controller_attrs, resource_handles, &controller_node);
if (res != B_OK || controller_node == NULL) {
TRACE("register controller failed\n");
goto err;
}
}
// publish channel nodes
for (chan_index = 0; chan_index < asic_data[asic_index].channel_count; chan_index++) {
device_attr channel_attrs[] = {
// info about ourself and our consumer
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: CHANNEL_MODULE_NAME }},
{ B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: DRIVER_PRETTY_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: controller_channel_data[chan_index].name }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
// private data to identify channel
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: true }},
{ "silicon_image_3112/chan_index", B_UINT32_TYPE, { ui32: chan_index }},
{ NULL }
};
device_node_handle channel_node;
TRACE("publishing %s\n", controller_channel_data[chan_index].name );
dm->register_device(controller_node, channel_attrs, resource_handles, &channel_node);
}
}
dm->uninit_driver(parent);
TRACE("controller_probe success\n");
return B_OK;
err:
dm->uninit_driver(parent);
TRACE("controller_probe failed\n");
return B_ERROR;
}
static status_t
controller_init(device_node_handle node, void *user_cookie, void **_cookie)
{