From b7c4739649794bbabee35864378a872d13793b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 7 Jun 2004 00:37:08 +0000 Subject: [PATCH] Added a generic PCI IDE driver, a specialised one for the Promise TX chips, and an ISA IDE driver. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7774 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/busses/Jamfile | 1 + src/add-ons/kernel/busses/ide/Jamfile | 5 + .../kernel/busses/ide/generic_ide_pci/Jamfile | 7 + .../ide/generic_ide_pci/generic_ide_pci.c | 221 +++++++++ .../busses/ide/generic_ide_pci/wrapper.h | 89 ++++ src/add-ons/kernel/busses/ide/ide_isa/Jamfile | 7 + .../kernel/busses/ide/ide_isa/ide_isa.c | 457 ++++++++++++++++++ .../kernel/busses/ide/ide_isa/wrapper.h | 89 ++++ .../kernel/busses/ide/promise_tx2/Jamfile | 7 + .../busses/ide/promise_tx2/promise_tx2.c | 385 +++++++++++++++ .../kernel/busses/ide/promise_tx2/wrapper.h | 89 ++++ 11 files changed, 1357 insertions(+) create mode 100644 src/add-ons/kernel/busses/ide/Jamfile create mode 100644 src/add-ons/kernel/busses/ide/generic_ide_pci/Jamfile create mode 100644 src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c create mode 100644 src/add-ons/kernel/busses/ide/generic_ide_pci/wrapper.h create mode 100644 src/add-ons/kernel/busses/ide/ide_isa/Jamfile create mode 100644 src/add-ons/kernel/busses/ide/ide_isa/ide_isa.c create mode 100644 src/add-ons/kernel/busses/ide/ide_isa/wrapper.h create mode 100644 src/add-ons/kernel/busses/ide/promise_tx2/Jamfile create mode 100644 src/add-ons/kernel/busses/ide/promise_tx2/promise_tx2.c create mode 100644 src/add-ons/kernel/busses/ide/promise_tx2/wrapper.h diff --git a/src/add-ons/kernel/busses/Jamfile b/src/add-ons/kernel/busses/Jamfile index 1127e58cae..94369eaee2 100644 --- a/src/add-ons/kernel/busses/Jamfile +++ b/src/add-ons/kernel/busses/Jamfile @@ -1,3 +1,4 @@ SubDir OBOS_TOP src add-ons kernel busses ; +SubInclude OBOS_TOP src add-ons kernel busses ide ; SubInclude OBOS_TOP src add-ons kernel busses usb ; diff --git a/src/add-ons/kernel/busses/ide/Jamfile b/src/add-ons/kernel/busses/ide/Jamfile new file mode 100644 index 0000000000..be1f964ccb --- /dev/null +++ b/src/add-ons/kernel/busses/ide/Jamfile @@ -0,0 +1,5 @@ +SubDir OBOS_TOP src add-ons kernel busses ide ; + +SubInclude OBOS_TOP src add-ons kernel busses ide generic_ide_pci ; +SubInclude OBOS_TOP src add-ons kernel busses ide ide_isa ; +SubInclude OBOS_TOP src add-ons kernel busses ide promise_tx2 ; diff --git a/src/add-ons/kernel/busses/ide/generic_ide_pci/Jamfile b/src/add-ons/kernel/busses/ide/generic_ide_pci/Jamfile new file mode 100644 index 0000000000..00a5a04326 --- /dev/null +++ b/src/add-ons/kernel/busses/ide/generic_ide_pci/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP src add-ons kernel busses ide generic_ide_pci ; + +UsePrivateHeaders kernel ; + +KernelAddon generic_ide_pci : kernel busses ide : + generic_ide_pci.c + ; diff --git a/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c b/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c new file mode 100644 index 0000000000..d504063239 --- /dev/null +++ b/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c @@ -0,0 +1,221 @@ +/* +** Copyright 2002/03, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + +/* + Generic IDE PCI controller driver + + Generic PCI bus mastering IDE driver. +*/ + +#include +#include +#include + +#include + +#define debug_level_flow 0 +#define debug_level_error 3 +#define debug_level_info 3 + +#define DEBUG_MSG_PREFIX "GENERIC IDE PCI -- " + +#include "wrapper.h" + +#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/" PCI_DEVICE_TYPE_NAME +#define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1" + +#define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller" + +ide_for_controller_interface *ide; +static ide_adapter_interface *ide_adapter; +device_manager_info *pnp; + + +static int write_command_block_regs( ide_adapter_channel_info *channel, ide_task_file *tf, + ide_reg_mask mask ) +{ + return ide_adapter->write_command_block_regs( channel, tf, mask ); +} + +static status_t read_command_block_regs( ide_adapter_channel_info *channel, ide_task_file *tf, + ide_reg_mask mask ) +{ + return ide_adapter->read_command_block_regs( channel, tf, mask ); +} + +static uint8 get_altstatus( ide_adapter_channel_info *channel) +{ + return ide_adapter->get_altstatus( channel ); +} + +static status_t write_device_control( ide_adapter_channel_info *channel, uint8 val ) +{ + return ide_adapter->write_device_control( channel, val ); +} + +static status_t write_pio( ide_adapter_channel_info *channel, uint16 *data, int count, + bool force_16bit ) +{ + return ide_adapter->write_pio( channel, data, count, force_16bit ); +} + +static status_t read_pio( ide_adapter_channel_info *channel, uint16 *data, int count, + bool force_16bit ) +{ + return ide_adapter->read_pio( channel, data, count, force_16bit ); +} + +static status_t prepare_dma( ide_adapter_channel_info *channel, + const physical_entry *sg_list, size_t sg_list_count, + bool to_device ) +{ + return ide_adapter->prepare_dma( channel, sg_list, sg_list_count, to_device ); +} + +static status_t start_dma( ide_adapter_channel_info *channel ) +{ + return ide_adapter->start_dma( channel ); +} + + +static status_t finish_dma( ide_adapter_channel_info *channel ) +{ + return ide_adapter->finish_dma( channel ); +} + + +static status_t init_channel( pnp_node_handle node, ide_channel ide_channel, + ide_adapter_channel_info **cookie ) +{ + return ide_adapter->init_channel( node, ide_channel, cookie, + sizeof( ide_adapter_channel_info ), ide_adapter->inthand ); +} + + +static status_t uninit_channel( ide_adapter_channel_info *channel ) +{ + return ide_adapter->uninit_channel( channel ); +} + + +static void channel_removed( pnp_node_handle node, ide_adapter_channel_info *channel ) +{ + return ide_adapter->channel_removed( node, channel ); +} + + +static status_t init_controller( pnp_node_handle node, void *user_cookie, + ide_adapter_controller_info **cookie ) +{ + return ide_adapter->init_controller( node, user_cookie, cookie, + sizeof( ide_adapter_controller_info )); +} + + +static status_t uninit_controller( ide_adapter_controller_info *controller ) +{ + return ide_adapter->uninit_controller( controller ); +} + + +static void controller_removed( + pnp_node_handle node, ide_adapter_controller_info *controller ) +{ + return ide_adapter->controller_removed( node, controller ); +} + + +static status_t probe_controller( pnp_node_handle parent ) +{ + return ide_adapter->probe_controller( parent, + GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME, "generic_ide_pci", + "Generic IDE PCI Controller", + GENERIC_IDE_PCI_CHANNEL_MODULE_NAME, + true, + true, // assume that command queuing works + 1, // assume 16 bit alignment is enough + 0xffff, // boundary is on 64k according to spec + 0x10000, // up to 64k per S/G block according to spec + true // by default, compatibility mode is used + ); +} + + +static status_t +module_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + + default: + return B_ERROR; + } +} + + +module_dependency module_dependencies[] = { + { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, + { DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, + { IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter }, + {} +}; + + +// exported interface +static ide_controller_interface channel_interface = { + { + { + GENERIC_IDE_PCI_CHANNEL_MODULE_NAME, + 0, + module_std_ops + }, + + (status_t (*)( pnp_node_handle , void *, void ** )) init_channel, + (status_t (*)( void * )) uninit_channel, + NULL, + (void (*)( pnp_node_handle , void * )) channel_removed + }, + + (status_t (*)(ide_channel_cookie, + ide_task_file*,ide_reg_mask)) &write_command_block_regs, + (status_t (*)(ide_channel_cookie, + ide_task_file*,ide_reg_mask)) &read_command_block_regs, + + (uint8 (*)(ide_channel_cookie)) &get_altstatus, + (status_t (*)(ide_channel_cookie,uint8)) &write_device_control, + + (status_t (*)(ide_channel_cookie,uint16*,int,bool)) &write_pio, + (status_t (*)(ide_channel_cookie,uint16*,int,bool)) &read_pio, + + (status_t (*)(ide_channel_cookie, + const physical_entry *,size_t,bool)) &prepare_dma, + (status_t (*)(ide_channel_cookie)) &start_dma, + (status_t (*)(ide_channel_cookie)) &finish_dma, +}; + + +static pnp_driver_info controller_interface = { + { + GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME, + 0, + module_std_ops + }, + + (status_t (*)( pnp_node_handle, void *, void ** )) init_controller, + (status_t (*)( void * )) uninit_controller, + probe_controller, + (void (*)( pnp_node_handle, void * )) controller_removed +}; + +#if !_BUILDING_kernel && !BOOT +_EXPORT +module_info *modules[] = { + (module_info *)&controller_interface, + (module_info *)&channel_interface, + NULL +}; +#endif diff --git a/src/add-ons/kernel/busses/ide/generic_ide_pci/wrapper.h b/src/add-ons/kernel/busses/ide/generic_ide_pci/wrapper.h new file mode 100644 index 0000000000..6793cb73be --- /dev/null +++ b/src/add-ons/kernel/busses/ide/generic_ide_pci/wrapper.h @@ -0,0 +1,89 @@ +#ifndef _WRAPPER_H +#define _WRAPPER_H + +#include +#include + + +// benaphores + +#define INIT_BEN(x, prefix) benaphore_init(x, prefix) +#define DELETE_BEN(x) benaphore_destroy(x) +#define ACQUIRE_BEN(x) benaphore_lock(x) +#define RELEASE_BEN(x) benaphore_unlock(x) + +// debug output + +#ifdef DEBUG_WAIT_ON_MSG +# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG ); +#else +# define DEBUG_WAIT +#endif + +#ifdef DEBUG_WAIT_ON_ERROR +# define DEBUG_WAIT_ERROR snooze( DEBUG_WAIT_ON_ERROR ); +#else +# define DEBUG_WAIT_ERROR +#endif + +#ifndef DEBUG_MAX_LEVEL_FLOW +# define DEBUG_MAX_LEVEL_FLOW 4 +#endif + +#ifndef DEBUG_MAX_LEVEL_INFO +# define DEBUG_MAX_LEVEL_INFO 4 +#endif + +#ifndef DEBUG_MAX_LEVEL_ERROR +# define DEBUG_MAX_LEVEL_ERROR 4 +#endif + +#ifndef DEBUG_MSG_PREFIX +# define DEBUG_MSG_PREFIX "" +#endif + +#ifndef debug_level_flow +# define debug_level_flow 3 +#endif + +#ifndef debug_level_info +# define debug_level_info 2 +#endif + +#ifndef debug_level_error +# define debug_level_error 1 +#endif + +#define FUNC_NAME DEBUG_MSG_PREFIX __FUNCTION__ ": " + +#define SHOW_FLOW(seriousness, format, param...) \ + do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_FLOW0(seriousness, format) \ + do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_INFO(seriousness, format, param...) \ + do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_INFO0(seriousness, format) \ + do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_ERROR(seriousness, format, param...) \ + do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT_ERROR \ + }} while( 0 ) + +#define SHOW_ERROR0(seriousness, format) \ + do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \ + }} while( 0 ) + +#endif /* _BENAPHORE_H */ diff --git a/src/add-ons/kernel/busses/ide/ide_isa/Jamfile b/src/add-ons/kernel/busses/ide/ide_isa/Jamfile new file mode 100644 index 0000000000..beb5e8d0f6 --- /dev/null +++ b/src/add-ons/kernel/busses/ide/ide_isa/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP src add-ons kernel busses ide ide_isa ; + +UsePrivateHeaders kernel ; + +KernelAddon ide_isa : kernel busses ide : + ide_isa.c + ; diff --git a/src/add-ons/kernel/busses/ide/ide_isa/ide_isa.c b/src/add-ons/kernel/busses/ide/ide_isa/ide_isa.c new file mode 100644 index 0000000000..060c511e76 --- /dev/null +++ b/src/add-ons/kernel/busses/ide/ide_isa/ide_isa.c @@ -0,0 +1,457 @@ +/* +** Copyright 2002/03, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + +/* + IDE ISA controller driver + + This is a testing-only driver. In reality, you want to use + the IDE PCI controller driver, but at least under Bochs, there's not + much choice as PCI support is very limited there. +*/ + +#include +#include +#include + +#include +#include +#include +#include + +#define debug_level_flow 4 +#define debug_level_error 4 +#define debug_level_info 4 + +#define DEBUG_MSG_PREFIX "IDE ISA -- " + +#include "wrapper.h" + +#define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/"ISA_DEVICE_TYPE_NAME + +// private node item: +// io address of command block +#define IDE_ISA_COMMAND_BLOCK_BASE "ide_isa/command_block_base" +// io address of control block +#define IDE_ISA_CONTROL_BLOCK_BASE "ide_isa/control_block_base" +// interrupt number +#define IDE_ISA_INTNUM "ide_isa/irq" + +//isa2_module_info *isa; +ide_for_controller_interface *ide; +device_manager_info *pnp; + + +// info about one channel +typedef struct channel_info { + isa2_module_info *isa; + uint16 command_block_base; // io address command block + uint16 control_block_base; // io address control block + int intnum; // interrupt number + + uint32 lost; // != 0 if device got removed, i.e. if it must not + // be accessed anymore + + ide_channel ide_channel; + pnp_node_handle node; +} channel_info; + + +static int +write_command_block_regs(channel_info *channel, ide_task_file *tf, ide_reg_mask mask) +{ + int i; + uint16 ioaddr = channel->command_block_base; + + if( channel->lost ) + return B_ERROR; + + for( i = 0; i < 7; i++ ) { + if( ((1 << (i-7)) & mask) != 0 ) { + SHOW_FLOW( 3, "%x->HI(%x)", tf->raw.r[i + 7], i ); + channel->isa->write_io_8( ioaddr + 1 + i, tf->raw.r[i + 7] ); + } + + if( ((1 << i) & mask) != 0 ) { + SHOW_FLOW( 3, "%x->LO(%x)", tf->raw.r[i], i ); + channel->isa->write_io_8( ioaddr + 1 + i, tf->raw.r[i] ); + } + } + + return B_OK; +} + + +static status_t +read_command_block_regs(channel_info *channel, ide_task_file *tf, ide_reg_mask mask) +{ + int i; + uint16 ioaddr = channel->command_block_base; + + if( channel->lost ) + return B_ERROR; + + for( i = 0; i < 7; i++ ) { + if( ((1 << i) & mask) != 0 ) { + tf->raw.r[i] = channel->isa->read_io_8( ioaddr + 1 + i ); + SHOW_FLOW( 3, "%x: %x", i, (int)tf->raw.r[i] ); + } + } + + return B_OK; +} + + +static uint8 +get_altstatus(channel_info *channel) +{ + uint16 altstatusaddr = channel->control_block_base; + + if (channel->lost) + return B_ERROR; + + return channel->isa->read_io_8(altstatusaddr); +} + + +static status_t +write_device_control(channel_info *channel, uint8 val) +{ + uint16 device_control_addr = channel->control_block_base; + + SHOW_FLOW( 3, "%x", (int)val ); + + if (channel->lost) + return B_ERROR; + + channel->isa->write_io_8(device_control_addr, val); + + return B_OK; +} + + +static status_t +write_pio_16(channel_info *channel, uint16 *data, int count, bool force_16bit) +{ + uint16 ioaddr = channel->command_block_base; + + if( channel->lost ) + return B_ERROR; + + // Bochs doesn't support 32 bit accesses; + // no real performance impact as this driver is for Bochs only anyway + force_16bit = true; + + if( (count & 1) != 0 || force_16bit ) { + for( ; count > 0; --count ) + channel->isa->write_io_16( ioaddr, *(data++) ); + + } else { + uint32 *cur_data = (uint32 *)data; + + for( ; count > 0; count -= 2 ) + channel->isa->write_io_32( ioaddr, *(cur_data++) ); + } + + return B_OK; +} + + +static status_t +read_pio_16(channel_info *channel, uint16 *data, int count, bool force_16bit) +{ + uint16 ioaddr = channel->command_block_base; + + if( channel->lost ) + return B_ERROR; + + force_16bit = true; + + if( (count & 1) != 0 || force_16bit ) { + for( ; count > 0; --count ) + *(data++) = channel->isa->read_io_16( ioaddr ); + + } else { + uint32 *cur_data = (uint32 *)data; + + for( ; count > 0; count -= 2 ) + *(cur_data++) = channel->isa->read_io_32( ioaddr ); + } + + return B_OK; +} + + +static int32 +inthand(void *arg) +{ + channel_info *channel = (channel_info *)arg; + uint8 status; + + SHOW_FLOW0( 3, "" ); + + if (channel->lost) + return B_UNHANDLED_INTERRUPT; + + // acknowledge IRQ + status = channel->isa->read_io_8(channel->command_block_base + 7); + + return ide->irq_handler(channel->ide_channel, status); +} + + +static status_t +prepare_dma(channel_info *channel, const physical_entry *sg_list, size_t sg_list_count, + uint32 startbyte, uint32 blocksize, size_t *numBytes, bool to_device) +{ + return B_NOT_ALLOWED; +} + + +static status_t +start_dma(void *channel) +{ + return B_NOT_ALLOWED; +} + + +static status_t +finish_dma(void *channel) +{ + return B_NOT_ALLOWED; +} + + +static status_t +init_channel(pnp_node_handle node, ide_channel ide_channel, channel_info **cookie) +{ + channel_info *channel; + isa2_module_info *isa; + void *dummy; + uint16 command_block_base, control_block_base; + uint8 irq; + status_t res; + + // get device data + if (pnp->get_attr_uint16(node, IDE_ISA_COMMAND_BLOCK_BASE, &command_block_base, false) != B_OK + || pnp->get_attr_uint16(node, IDE_ISA_CONTROL_BLOCK_BASE, &control_block_base, false) != B_OK + || pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK) + return B_ERROR; + + if (pnp->load_driver(pnp->get_parent(node), NULL, (pnp_driver_info **)&isa, &dummy) != B_OK) + return B_ERROR; + + channel = (channel_info *)malloc(sizeof(channel_info)); + if (channel == NULL) { + res = B_NO_MEMORY; + goto err0; + } + + channel->isa = isa; + channel->node = node; + channel->lost = false; + channel->command_block_base = command_block_base; + channel->control_block_base = control_block_base; + channel->intnum = irq; + channel->ide_channel = ide_channel; + + res = install_io_interrupt_handler(channel->intnum, + inthand, channel, 0); + + if (res < 0) { + SHOW_ERROR( 0, "couldn't install irq handler @%d", irq); + goto err; + } + + // enable interrupts so the channel is ready to run + write_device_control(channel, ide_devctrl_bit3); + + *cookie = channel; + + return B_OK; + +err: + free(channel); + +err0: + pnp->unload_driver(pnp->get_parent(node)); + return res; +} + + +static status_t +uninit_channel(channel_info *channel) +{ + // disable IRQs + write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien); + + // catch spurious interrupt + // (some controllers generate an IRQ when you _disable_ interrupts, + // they are delayed by less then 40 µs, so 1 ms is safe) + snooze(1000); + + remove_io_interrupt_handler(channel->intnum, inthand, channel); + + pnp->unload_driver(pnp->get_parent(channel->node)); + + free(channel); + + return B_OK; +} + + +// publish node of ide channel +static status_t +publish_channel(pnp_node_handle parent, io_resource_handle *resources, uint16 command_block_base, + uint16 control_block_base, uint8 intnum, const char *name) +{ + pnp_node_attr attrs[] = { + // info about ourself and our consumer + { PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }}, + { PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }}, + { PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }}, + { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }}, + { PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "ide_isa" }}, + // don't scan if loaded as we own I/O resources + { PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }}, + + // properties of this controller for ide bus manager + { IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }}, + { IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: 0 }}, + { IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: 1 }}, + { IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: name }}, + + // DMA properties; the 16 bit alignment is not necessary as + // the ide bus manager handles that very efficiently, but why + // not use the block device manager for doing that? + { BLKDEV_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }}, + + // private data to identify device + { IDE_ISA_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }}, + { IDE_ISA_CONTROL_BLOCK_BASE, B_UINT16_TYPE, { ui16: control_block_base }}, + { IDE_ISA_INTNUM, B_UINT8_TYPE, { ui8: intnum }}, + { NULL } + }; + pnp_node_handle node; + + SHOW_FLOW0( 2, "" ); + + return pnp->register_device(parent, attrs, resources, &node); +} + + +// detect IDE channel +static status_t +probe_channel(pnp_node_handle parent, + uint16 command_block_base, uint16 control_block_base, + int intnum, const char *name) +{ + io_resource resources[3] = { + { IO_PORT, command_block_base, 8 }, + { IO_PORT, control_block_base, 1 }, + {} + }; + io_resource_handle resource_handles[3]; + + SHOW_FLOW(3, "name = \"%s\"", name); + + // we aren't upset if io-ports are in use already - only + // the PCI IDE driver can own them, and if it does, we exit silently + if (pnp->acquire_io_resources(resources, resource_handles) != B_OK) + return B_OK; + + // we assume that every modern PC has an IDE controller, so no + // further testing is done (well - I don't really know how to detect the + // controll, but who cares ;) + return publish_channel(parent, resource_handles, command_block_base, + control_block_base, intnum, name); +} + + +static status_t +scan_parent(pnp_node_handle node) +{ + SHOW_FLOW0( 3, "" ); + + // our parent device is the isa bus and all device drivers are Universal, + // so the pnp_manager tries each ISA driver in turn + probe_channel(node, 0x1f0, 0x3f6, 14, "primary IDE channel"); + probe_channel(node, 0x170, 0x376, 15, "secondary IDE channel"); + + return B_OK; +} + + +static void +channel_removed(pnp_node_handle node, channel_info *channel) +{ + SHOW_FLOW0( 3, "" ); + + if (channel != NULL) + // disable access instantly + atomic_or(&channel->lost, 1); + + return; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + + default: + return B_ERROR; + } +} + + +module_dependency module_dependencies[] = { + { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, + { DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, + {} +}; + +// exported interface +ide_controller_interface isa_controller_interface = { + { + { + IDE_ISA_MODULE_NAME, + 0, + std_ops + }, + + (status_t (*)( pnp_node_handle, void *, void ** )) init_channel, + (status_t (*)( void * )) uninit_channel, + scan_parent, + (void (*)( pnp_node_handle, void * )) channel_removed + }, + + (status_t (*)(ide_channel_cookie, + ide_task_file*,ide_reg_mask)) &write_command_block_regs, + (status_t (*)(ide_channel_cookie, + ide_task_file*,ide_reg_mask)) &read_command_block_regs, + + (uint8 (*)(ide_channel_cookie)) &get_altstatus, + (status_t (*)(ide_channel_cookie,uint8)) &write_device_control, + + (status_t (*)(ide_channel_cookie,uint16*,int,bool)) &write_pio_16, + (status_t (*)(ide_channel_cookie,uint16*,int,bool)) &read_pio_16, + + (status_t (*)(ide_channel_cookie, + const physical_entry *,size_t,bool)) &prepare_dma, + (status_t (*)(ide_channel_cookie)) &start_dma, + (status_t (*)(ide_channel_cookie)) &finish_dma, +}; + +#if !_BUILDING_kernel && !BOOT +_EXPORT +module_info *modules[] = { + (module_info *)&isa_controller_interface, + NULL +}; +#endif diff --git a/src/add-ons/kernel/busses/ide/ide_isa/wrapper.h b/src/add-ons/kernel/busses/ide/ide_isa/wrapper.h new file mode 100644 index 0000000000..6793cb73be --- /dev/null +++ b/src/add-ons/kernel/busses/ide/ide_isa/wrapper.h @@ -0,0 +1,89 @@ +#ifndef _WRAPPER_H +#define _WRAPPER_H + +#include +#include + + +// benaphores + +#define INIT_BEN(x, prefix) benaphore_init(x, prefix) +#define DELETE_BEN(x) benaphore_destroy(x) +#define ACQUIRE_BEN(x) benaphore_lock(x) +#define RELEASE_BEN(x) benaphore_unlock(x) + +// debug output + +#ifdef DEBUG_WAIT_ON_MSG +# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG ); +#else +# define DEBUG_WAIT +#endif + +#ifdef DEBUG_WAIT_ON_ERROR +# define DEBUG_WAIT_ERROR snooze( DEBUG_WAIT_ON_ERROR ); +#else +# define DEBUG_WAIT_ERROR +#endif + +#ifndef DEBUG_MAX_LEVEL_FLOW +# define DEBUG_MAX_LEVEL_FLOW 4 +#endif + +#ifndef DEBUG_MAX_LEVEL_INFO +# define DEBUG_MAX_LEVEL_INFO 4 +#endif + +#ifndef DEBUG_MAX_LEVEL_ERROR +# define DEBUG_MAX_LEVEL_ERROR 4 +#endif + +#ifndef DEBUG_MSG_PREFIX +# define DEBUG_MSG_PREFIX "" +#endif + +#ifndef debug_level_flow +# define debug_level_flow 3 +#endif + +#ifndef debug_level_info +# define debug_level_info 2 +#endif + +#ifndef debug_level_error +# define debug_level_error 1 +#endif + +#define FUNC_NAME DEBUG_MSG_PREFIX __FUNCTION__ ": " + +#define SHOW_FLOW(seriousness, format, param...) \ + do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_FLOW0(seriousness, format) \ + do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_INFO(seriousness, format, param...) \ + do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_INFO0(seriousness, format) \ + do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_ERROR(seriousness, format, param...) \ + do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT_ERROR \ + }} while( 0 ) + +#define SHOW_ERROR0(seriousness, format) \ + do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \ + }} while( 0 ) + +#endif /* _BENAPHORE_H */ diff --git a/src/add-ons/kernel/busses/ide/promise_tx2/Jamfile b/src/add-ons/kernel/busses/ide/promise_tx2/Jamfile new file mode 100644 index 0000000000..fc9821d368 --- /dev/null +++ b/src/add-ons/kernel/busses/ide/promise_tx2/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP src add-ons kernel busses ide promise_tx2 ; + +UsePrivateHeaders kernel ; + +KernelAddon promise_tx2 : kernel busses ide : + promise_tx2.c + ; diff --git a/src/add-ons/kernel/busses/ide/promise_tx2/promise_tx2.c b/src/add-ons/kernel/busses/ide/promise_tx2/promise_tx2.c new file mode 100644 index 0000000000..4c6f34c124 --- /dev/null +++ b/src/add-ons/kernel/busses/ide/promise_tx2/promise_tx2.c @@ -0,0 +1,385 @@ +/* +** Copyright 2002-04, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + +/* + Promise TX2 series IDE controller driver +*/ + +#include +#include +#include + +#include +#include + +#define debug_level_flow 0 +#define debug_level_error 3 +#define debug_level_info 3 + +#define DEBUG_MSG_PREFIX "PROMISE TX2 -- " + +#include "wrapper.h" + +#define PROMISE_TX2_CONTROLLER_MODULE_NAME "busses/ide/promise_tx2/" PCI_DEVICE_TYPE_NAME +#define PROMISE_TX2_CHANNEL_MODULE_NAME "busses/ide/promise_tx2/channel/v1" + +#define PROMISE_TX2_CONTROLLER_TYPE_NAME "promise tx2 controller" + + +static ide_for_controller_interface *ide; +static ide_adapter_interface *ide_adapter; +static device_manager_info *pnp; + + +static int +write_command_block_regs(ide_adapter_channel_info *channel, + ide_task_file *tf, ide_reg_mask mask) +{ + return ide_adapter->write_command_block_regs(channel, tf, mask); +} + + +static status_t +read_command_block_regs(ide_adapter_channel_info *channel, + ide_task_file *tf, ide_reg_mask mask) +{ + return ide_adapter->read_command_block_regs(channel, tf, mask); +} + + +static uint8 +get_altstatus(ide_adapter_channel_info *channel) +{ + return ide_adapter->get_altstatus(channel); +} + + +static status_t +write_device_control(ide_adapter_channel_info *channel, uint8 val) +{ + return ide_adapter->write_device_control(channel, val); +} + + +static status_t +write_pio(ide_adapter_channel_info *channel, uint16 *data, int count, + bool force_16bit) +{ + return ide_adapter->write_pio(channel, data, count, force_16bit); +} + + +static status_t +read_pio(ide_adapter_channel_info *channel, uint16 *data, int count, + bool force_16bit) +{ + return ide_adapter->read_pio(channel, data, count, force_16bit); +} + + +static int32 +inthand(void *arg) +{ + ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg; + pci_device_module_info *pci = channel->pci; + pci_device device = channel->device; + ide_bm_status bm_status; + uint8 status; + + SHOW_FLOW0( 3, "" ); + + if (channel->lost) + return B_UNHANDLED_INTERRUPT; + + // the controller always tells us whether it generated the IRQ, so ask it first + pci->write_io_8(device, channel->bus_master_base + 1, 0x0b); + if ((pci->read_io_8(device, channel->bus_master_base + 3) & 0x20) == 0) + return B_UNHANDLED_INTERRUPT; + + if (channel->dmaing) { + // in DMA mode, there is a safe test + // in PIO mode, this doesn't work + *(uint8 *)&bm_status = pci->read_io_8( device, + channel->bus_master_base + ide_bm_status_reg ); + + if (!bm_status.interrupt) + return B_UNHANDLED_INTERRUPT; + } + + // acknowledge IRQ + status = pci->read_io_8(device, channel->command_block_base + 7); + + return ide->irq_handler(channel->ide_channel, status); +} + + +static status_t +prepare_dma(ide_adapter_channel_info *channel, const physical_entry *sg_list, + size_t sg_list_count, bool to_device) +{ + return ide_adapter->prepare_dma(channel, sg_list, sg_list_count, to_device); +} + + +static status_t +start_dma(ide_adapter_channel_info *channel) +{ + return ide_adapter->start_dma(channel); +} + + +static status_t +finish_dma(ide_adapter_channel_info *channel) +{ + return ide_adapter->finish_dma(channel); +} + + +static status_t +init_channel(pnp_node_handle node, ide_channel ide_channel, + ide_adapter_channel_info **cookie) +{ + return ide_adapter->init_channel(node, ide_channel, cookie, + sizeof( ide_adapter_channel_info ), inthand); +} + + +static status_t +uninit_channel(ide_adapter_channel_info *channel) +{ + return ide_adapter->uninit_channel(channel); +} + + +static void channel_removed(pnp_node_handle node, ide_adapter_channel_info *channel) +{ + return ide_adapter->channel_removed(node, channel); +} + + +static status_t +init_controller(pnp_node_handle node, void *user_cookie, + ide_adapter_controller_info **cookie) +{ + return ide_adapter->init_controller(node, user_cookie, cookie, + sizeof(ide_adapter_controller_info)); +} + + +static status_t +uninit_controller(ide_adapter_controller_info *controller) +{ + return ide_adapter->uninit_controller(controller); +} + + +static void +controller_removed(pnp_node_handle node, ide_adapter_controller_info *controller) +{ + return ide_adapter->controller_removed(node, controller); +} + + +// publish node of ide controller + +static status_t +publish_controller(pnp_node_handle parent, uint16 bus_master_base, uint8 intnum, + io_resource_handle *resources, pnp_node_handle *node) +{ + pnp_node_attr attrs[] = { + // info about ourself and our consumer + { PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }}, + { PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_TYPE_NAME }}, + // don't scan if loaded as we own I/O resources + { PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }}, + + // properties of this controller for ide bus manager + // there are always max. 2 devices + { IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }}, + // of course we can DMA + { IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: 1 }}, + // command queuing always works + { IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: 1 }}, + // choose any name here + { IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: "Promise TX2" }}, + + // DMA properties + // some say it must be dword-aligned, others that it can be byte-aligned; + // stay on the safe side + { BLKDEV_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 3 }}, + // one S/G block must not cross 64K boundary + { BLKDEV_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }}, + // size of S/G block is 16 bits with zero being 64K + { BLKDEV_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE, { ui32: 0x10000 }}, + // see definition of MAX_SG_COUNT + { BLKDEV_MAX_SG_BLOCKS, B_UINT32_TYPE, { ui32: IDE_ADAPTER_MAX_SG_COUNT }}, + + // private data to find controller + { IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }}, + // store interrupt in controller node + { IDE_ADAPTER_INTNUM, B_UINT8_TYPE, { ui8: intnum }}, + { NULL } + }; + + SHOW_FLOW0(2, ""); + + return pnp->register_device(parent, attrs, resources, node); +} + + +// detect pure IDE controller, i.e. without channels + +static status_t +detect_controller(pci_device_module_info *pci, pci_device pci_device, + pnp_node_handle parent, uint16 bus_master_base, int8 intnum, + pnp_node_handle *node) +{ + io_resource_handle resource_handles[2]; + + SHOW_FLOW0(3, ""); + + if ((bus_master_base & PCI_address_space) != 1) + return B_OK; + + bus_master_base &= ~PCI_address_space; + + { + io_resource resources[2] = { + { IO_PORT, bus_master_base, 16 }, + {} + }; + + if (pnp->acquire_io_resources(resources, resource_handles) != B_OK) + return B_ERROR; + } + + return publish_controller(parent, bus_master_base, intnum, resource_handles, node); +} + + +static status_t +probe_controller(pnp_node_handle parent) +{ + pci_device_module_info *pci; + pci_device device; + uint16 command_block_base[2]; + uint16 control_block_base[2]; + uint16 bus_master_base; + pnp_node_handle controller_node, channels[2]; + uint8 intnum; + status_t res; + + SHOW_FLOW0(3, ""); + + if (pnp->load_driver(parent, NULL, (pnp_driver_info **)&pci, (void **)&device) != B_OK) + return B_ERROR; + + command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4); + control_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 4, 4); + command_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 8, 4); + control_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 12, 4); + bus_master_base = pci->read_pci_config(device, PCI_base_registers + 16, 4); + intnum = pci->read_pci_config(device, PCI_interrupt_line, 1); + + res = detect_controller(pci, device, parent, bus_master_base, intnum, &controller_node); + if (res != B_OK || controller_node == NULL) + goto err; + + ide_adapter->detect_channel(pci, device, controller_node, + PROMISE_TX2_CHANNEL_MODULE_NAME, true, + command_block_base[0], control_block_base[0], bus_master_base, intnum, true, + "Primary Channel", &channels[0], false); + + ide_adapter->detect_channel(pci, device, controller_node, + PROMISE_TX2_CHANNEL_MODULE_NAME, true, + command_block_base[1], control_block_base[1], bus_master_base, intnum, false, + "Secondary Channel", &channels[1], false); + + pnp->unload_driver(parent); + + return B_OK; + +err: + pnp->unload_driver(parent); + return res; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + + default: + return B_ERROR; + } +} + + +module_dependency module_dependencies[] = { + { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, + { DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, + { IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter }, + {} +}; + + +// exported interface +static ide_controller_interface channel_interface = { + { + { + PROMISE_TX2_CHANNEL_MODULE_NAME, + 0, + std_ops + }, + + (status_t (*)( pnp_node_handle , void *, void ** )) init_channel, + (status_t (*)( void * )) uninit_channel, + NULL, + (void (*)( pnp_node_handle , void * )) channel_removed + }, + + (status_t (*)(ide_channel_cookie, + ide_task_file*,ide_reg_mask)) &write_command_block_regs, + (status_t (*)(ide_channel_cookie, + ide_task_file*,ide_reg_mask)) &read_command_block_regs, + + (uint8 (*)(ide_channel_cookie)) &get_altstatus, + (status_t (*)(ide_channel_cookie,uint8)) &write_device_control, + + (status_t (*)(ide_channel_cookie,uint16*,int,bool)) &write_pio, + (status_t (*)(ide_channel_cookie,uint16*,int,bool)) &read_pio, + + (status_t (*)(ide_channel_cookie, + const physical_entry *,size_t,bool)) &prepare_dma, + (status_t (*)(ide_channel_cookie)) &start_dma, + (status_t (*)(ide_channel_cookie)) &finish_dma, +}; + + +static pnp_driver_info controller_interface = { + { + PROMISE_TX2_CONTROLLER_MODULE_NAME, + 0, + std_ops + }, + + (status_t (*)( pnp_node_handle, void *, void ** )) init_controller, + (status_t (*)( void * )) uninit_controller, + probe_controller, + (void (*)( pnp_node_handle, void * )) controller_removed +}; + +#if !_BUILDING_kernel && !BOOT +_EXPORT +module_info *modules[] = { + (module_info *)&controller_interface, + (module_info *)&channel_interface, + NULL +}; +#endif diff --git a/src/add-ons/kernel/busses/ide/promise_tx2/wrapper.h b/src/add-ons/kernel/busses/ide/promise_tx2/wrapper.h new file mode 100644 index 0000000000..6793cb73be --- /dev/null +++ b/src/add-ons/kernel/busses/ide/promise_tx2/wrapper.h @@ -0,0 +1,89 @@ +#ifndef _WRAPPER_H +#define _WRAPPER_H + +#include +#include + + +// benaphores + +#define INIT_BEN(x, prefix) benaphore_init(x, prefix) +#define DELETE_BEN(x) benaphore_destroy(x) +#define ACQUIRE_BEN(x) benaphore_lock(x) +#define RELEASE_BEN(x) benaphore_unlock(x) + +// debug output + +#ifdef DEBUG_WAIT_ON_MSG +# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG ); +#else +# define DEBUG_WAIT +#endif + +#ifdef DEBUG_WAIT_ON_ERROR +# define DEBUG_WAIT_ERROR snooze( DEBUG_WAIT_ON_ERROR ); +#else +# define DEBUG_WAIT_ERROR +#endif + +#ifndef DEBUG_MAX_LEVEL_FLOW +# define DEBUG_MAX_LEVEL_FLOW 4 +#endif + +#ifndef DEBUG_MAX_LEVEL_INFO +# define DEBUG_MAX_LEVEL_INFO 4 +#endif + +#ifndef DEBUG_MAX_LEVEL_ERROR +# define DEBUG_MAX_LEVEL_ERROR 4 +#endif + +#ifndef DEBUG_MSG_PREFIX +# define DEBUG_MSG_PREFIX "" +#endif + +#ifndef debug_level_flow +# define debug_level_flow 3 +#endif + +#ifndef debug_level_info +# define debug_level_info 2 +#endif + +#ifndef debug_level_error +# define debug_level_error 1 +#endif + +#define FUNC_NAME DEBUG_MSG_PREFIX __FUNCTION__ ": " + +#define SHOW_FLOW(seriousness, format, param...) \ + do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_FLOW0(seriousness, format) \ + do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_INFO(seriousness, format, param...) \ + do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_INFO0(seriousness, format) \ + do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \ + }} while( 0 ) + +#define SHOW_ERROR(seriousness, format, param...) \ + do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \ + dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT_ERROR \ + }} while( 0 ) + +#define SHOW_ERROR0(seriousness, format) \ + do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \ + dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \ + }} while( 0 ) + +#endif /* _BENAPHORE_H */