implemented most of the needed functionality, using memory mapped io

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18796 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen 2006-09-10 20:22:07 +00:00
parent b374cda7fd
commit cc51ac4772

View File

@ -7,10 +7,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <device_manager.h> #include <device_manager.h>
#include <bus/IDE.h>
#include <bus/ide/ide_adapter.h> #include <bus/ide/ide_adapter.h>
#include <block_io.h> #include <block_io.h>
#define TRACE(a...) dprintf("si-3112 " a) #define TRACE(a...) dprintf("si-3112 " a)
#define FLOW(a...) dprintf("si-3112 " a)
#define DRIVER_PRETTY_NAME "Silicon Image SATA" #define DRIVER_PRETTY_NAME "Silicon Image SATA"
@ -72,32 +74,30 @@ typedef struct {
uint32 lost; // != 0 if device got removed, i.e. if it must not uint32 lost; // != 0 if device got removed, i.e. if it must not
// be accessed anymore // be accessed anymore
} controller_cookie; } controller_data;
typedef struct { typedef struct {
pci_device_module_info *pci; pci_device_module_info *pci;
pci_device device; device_node_handle node;
pci_device device;
device_node_handle node; volatile uint8 * task_file;
volatile uint8 * control_block;
volatile uint8 * command_block;
volatile uint8 * dev_ctrl;
volatile uint8 * bm_status_reg;
volatile uint8 * bm_command_reg;
volatile uint32 * bm_prdt_address;
area_id prd_area;
prd_entry * prdt;
void * prdt_phys;
uint32 dma_active;
uint32 lost;
uint16 command_block_base; // io address command block } channel_data;
uint16 control_block_base; // io address control block
uint16 bus_master_base;
int intnum; // interrupt number
uint32 lost; // != 0 if device got removed, i.e. if it must not
// be accessed anymore
ide_channel ide_channel;
int32 (*inthand)( void *arg );
area_id prd_area;
prd_entry *prdt;
uint32 prdt_phys;
uint32 dmaing;
} channel_cookie;
static ide_for_controller_interface * ide; static ide_for_controller_interface * ide;
@ -248,9 +248,9 @@ err:
static status_t static status_t
controller_init(device_node_handle node, void *user_cookie, void **cookie) controller_init(device_node_handle node, void *user_cookie, void **controller_cookie)
{ {
controller_cookie *controller; controller_data *controller;
pci_device_module_info *pci; pci_device_module_info *pci;
pci_device device; pci_device device;
uint32 asic_index; uint32 asic_index;
@ -271,7 +271,7 @@ controller_init(device_node_handle node, void *user_cookie, void **cookie)
if (dm->get_attr_uint32(node, "silicon_image_3112/int_num", &int_num, false) != B_OK) if (dm->get_attr_uint32(node, "silicon_image_3112/int_num", &int_num, false) != B_OK)
return B_ERROR; return B_ERROR;
controller = malloc(sizeof(controller_cookie)); controller = malloc(sizeof(controller_data));
if (!controller) if (!controller)
return B_NO_MEMORY; return B_NO_MEMORY;
@ -331,7 +331,7 @@ controller_init(device_node_handle node, void *user_cookie, void **cookie)
free(controller); free(controller);
} }
*cookie = controller; *controller_cookie = controller;
TRACE("controller_init success\n"); TRACE("controller_init success\n");
return B_OK; return B_OK;
@ -339,9 +339,9 @@ controller_init(device_node_handle node, void *user_cookie, void **cookie)
static status_t static status_t
controller_uninit(void *cookie) controller_uninit(void *controller_cookie)
{ {
controller_cookie *controller = cookie; controller_data *controller = controller_cookie;
int i; int i;
TRACE("controller_uninit enter\n"); TRACE("controller_uninit enter\n");
@ -363,103 +363,358 @@ controller_uninit(void *cookie)
static void static void
controller_removed(device_node_handle node, void *cookie) controller_removed(device_node_handle node, void *controller_cookie)
{ {
controller_cookie *controller = cookie; controller_data *controller = controller_cookie;
controller->lost = 1; controller->lost = 1;
} }
static status_t static status_t
channel_init(device_node_handle node, void *user_cookie, void **_cookie) channel_init(device_node_handle node, void *user_cookie, void **channel_cookie)
{ {
return B_ERROR; ide_channel ide_channel = user_cookie;
channel_data *channel;
channel = malloc(sizeof(channel_data));
if (!channel)
return B_NO_MEMORY;
/*
channel->
pci_device_module_info *pci;
device_node_handle node;
pci_device device;
volatile uint8 *task_file (volatile uint8 *)(channel->mmio_addr + channel->command_block_base + 1);
volatile uint8 *control_block (volatile uint8 *)(channel->mmio_addr + channel->control_block_base);
volatile uint8 *command_block
volatile uint8 *dev_ctrl
volatile uint32 * bm_prdt_address = (volatile uint32 *)(channel->mmio_addr + channel->bus_master_base + ata_bm_prdt_address);
volatile uint8 * bm_status_reg = (volatile uint8 *)(channel->mmio_addr + channel->bus_master_base + ata_bm_status_reg);
volatile uint8 * bm_command_reg = (volatile uint8 *)(channel->mmio_addr + channel->bus_master_base + ata_bm_command_reg);
uint32 lost;
prd_entry *prdt;
area_id prd_area;
prd_entry *prdt;
uint32 dma_active;
*/
*channel_cookie = channel;
return B_OK;
} }
static status_t static status_t
channel_uninit(void *cookie) channel_uninit(void *channel_cookie)
{ {
channel_data *channel = channel_cookie;
return B_ERROR; return B_ERROR;
} }
static void static void
channel_removed(device_node_handle node, void *cookie) channel_removed(device_node_handle node, void *channel_cookie)
{ {
channel_data *channel = channel_cookie;
} }
static status_t static status_t
task_file_write(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask) task_file_write(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
int i;
FLOW("task_file_write\n");
if (channel->lost)
return B_ERROR;
for (i = 0; i < 7; i++) {
if( ((1 << (i+7)) & mask) != 0 ) {
FLOW("%x->HI(%x)\n", tf->raw.r[i + 7], i );
channel->task_file[i] = tf->raw.r[i + 7];
}
if (((1 << i) & mask) != 0) {
FLOW("%x->LO(%x)\n", tf->raw.r[i], i );
channel->task_file[i] = tf->raw.r[i];
}
}
*channel->dev_ctrl; // read altstatus to flush
return B_OK;
} }
static status_t static status_t
task_file_read(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask) task_file_read(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
int i;
FLOW("task_file_read\n");
if (channel->lost)
return B_ERROR;
for (i = 0; i < 7; i++) {
if (((1 << i) & mask) != 0) {
tf->raw.r[i] = channel->task_file[i];
FLOW("%x: %x\n", i, (int)tf->raw.r[i] );
}
}
return B_OK;
} }
static uint8 static uint8
altstatus_read(void *channel_cookie) altstatus_read(void *channel_cookie)
{ {
return 0xff; channel_data *channel = channel_cookie;
FLOW("altstatus_read\n");
if (channel->lost)
return 0x01; // Error bit
return *channel->dev_ctrl;
} }
static status_t static status_t
device_control_write(void *channel_cookie, uint8 val) device_control_write(void *channel_cookie, uint8 val)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
FLOW("device_control_write %x\n", val);
if (channel->lost)
return B_ERROR;
*channel->dev_ctrl = val;
*channel->dev_ctrl; // read altstatus to flush
return B_OK;
} }
static status_t static status_t
pio_write(void *channel_cookie, uint16 *data, int count, bool force_16bit) pio_write(void *channel_cookie, uint16 *data, int count, bool force_16bit)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
if (channel->lost)
return B_ERROR;
FLOW("pio_write force_16bit = %d, (count & 1) = %d\n", force_16bit, (count & 1));
// The data port is only 8 bit wide in the command register block.
if ((count & 1) != 0 || force_16bit) {
volatile uint16 * base = (volatile uint16 *)channel->command_block;
for ( ; count > 0; --count)
*base = *(data++);
} else {
volatile uint32 * base = (volatile uint32 *)channel->command_block;
uint32 *cur_data = (uint32 *)data;
for ( ; count > 0; count -= 2 )
*base = *(cur_data++);
}
*channel->dev_ctrl; // read altstatus to flush
return B_OK;
} }
static status_t static status_t
pio_read(void *channel_cookie, uint16 *data, int count, bool force_16bit) pio_read(void *channel_cookie, uint16 *data, int count, bool force_16bit)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
if (channel->lost)
return B_ERROR;
FLOW("pio_read force_16bit = %d, (count & 1) = %d\n", force_16bit, (count & 1));
// The data port is only 8 bit wide in the command register block.
// We are memory mapped and read using 16 or 32 bit access from this 8 bit location.
if ((count & 1) != 0 || force_16bit) {
volatile uint16 * base = (volatile uint16 *)channel->command_block;
for ( ; count > 0; --count)
*(data++) = *base;
} else {
volatile uint32 * base = (volatile uint32 *)channel->command_block;
uint32 *cur_data = (uint32 *)data;
for ( ; count > 0; count -= 2 )
*(cur_data++) = *base;
}
return B_OK;
} }
static status_t static status_t
dma_prepare(void *channel_cookie, const physical_entry *sg_list, size_t sg_list_count, bool write) dma_prepare(void *channel_cookie, const physical_entry *sg_list, size_t sg_list_count, bool write)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
prd_entry *prd = channel->prdt;
ide_bm_command command;
ide_bm_status status;
uint32 temp;
int i;
FLOW("dma_prepare enter\n");
for (i = sg_list_count - 1, prd = channel->prdt; i >= 0; --i, ++prd, ++sg_list ) {
prd->address = B_HOST_TO_LENDIAN_INT32(pci->ram_address(device, sg_list->address));
// 0 means 64K - this is done automatically be discarding upper 16 bits
prd->count = B_HOST_TO_LENDIAN_INT16((uint16)sg_list->size);
prd->EOT = i == 0;
FLOW("%x, %x, %d\n", (int)prd->address, prd->count, prd->EOT );
}
// XXX move this to chan init?
temp = (*channel->bm_prdt_address) & 3;
temp |= B_HOST_TO_LENDIAN_INT32(pci->ram_address(device, (void *)channel->prdt_phys)) & ~3;
*channel->bm_prdt_address = temp;
*channel->dev_ctrl; // read altstatus to flush
// reset interrupt and error signal
*(uint8 *)&status = *channel->bm_status_reg;
status.interrupt = 1;
status.error = 1;
*channel->bm_status_reg = *(uint8 *)&status;
*channel->dev_ctrl; // read altstatus to flush
// set data direction
*(uint8 *)&command = *channel->bm_command_reg;
command.from_device = !write;
*channel->bm_command_reg = *(uint8 *)&command;
*channel->dev_ctrl; // read altstatus to flush
FLOW("dma_prepare leave\n");
return B_OK;
} }
static status_t static status_t
dma_start(void *channel_cookie) dma_start(void *channel_cookie)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
ide_bm_command command;
FLOW("dma_start enter\n");
*(uint8 *)&command = *channel->bm_command_reg;
command.start_stop = 1;
channel->dma_active = true;
*channel->bm_command_reg = *(uint8 *)&command;
*channel->dev_ctrl; // read altstatus to flush
FLOW("dma_start leave\n");
return B_OK;
} }
static status_t static status_t
dma_finish(void *channel_cookie) dma_finish(void *channel_cookie)
{ {
return B_ERROR; channel_data *channel = channel_cookie;
ide_bm_command command;
ide_bm_status status, new_status;
FLOW("dma_finish enter\n");
*(uint8 *)&command = *channel->bm_command_reg;
command.start_stop = 0;
channel->dma_active = false;
*channel->bm_command_reg = *(uint8 *)&command;
*(uint8 *)&status = *channel->bm_status_reg;
new_status = status;
new_status.interrupt = 1;
new_status.error = 1;
*channel->bm_status_reg = *(uint8 *)&new_status;
*channel->dev_ctrl; // read altstatus to flush
if (status.error) {
FLOW("dma_finish: failed\n");
return B_ERROR;
}
if (!status.interrupt) {
if (status.active) {
FLOW("dma_finish: transfer aborted\n");
return B_ERROR;
} else {
FLOW("dma_finish: buffer underrun\n");
return B_DEV_DATA_UNDERRUN;
}
} else {
if (status.active) {
FLOW("dma_finish: buffer too large\n");
return B_DEV_DATA_OVERRUN;
} else {
FLOW("dma_finish leave\n");
return B_OK;
}
}
} }
static int32 static int32
handle_interrupt(void *arg) handle_interrupt(void *arg)
{ {
controller_cookie *controller = arg; controller_data *controller = arg;
pci_device_module_info *pci = controller->pci; pci_device_module_info *pci = controller->pci;
pci_device device = controller->device; pci_device device = controller->device;
ide_bm_status bm_status;
uint8 status;
FLOW("handle_interrupt\n");
return B_UNHANDLED_INTERRUPT; return B_UNHANDLED_INTERRUPT;
/*
if (channel->lost)
return B_UNHANDLED_INTERRUPT;
// add test whether this is really our IRQ
if (channel->dma_active) {
// in DMA mode, there is a safe test
// in PIO mode, this doesn't work
*(uint8 *)&bm_status = *channel->bm_status_reg;
if (!bm_status.interrupt)
return B_UNHANDLED_INTERRUPT;
}
// acknowledge IRQ
status = *(channel->command_block + 7);
return channel->ata->irq_handler(channel->ata_bus, status);
*/
} }