/*
 * clf_func.c  -- MATRIX VISION Frame Grabber Driver for mvHyperion series.
 *
 *   Copyright (c) 2006 MATRIX VISION GmbH (info@matrix-vision.de)
 *
 $Id: clf_func.c,v 1.28 2011-02-25 13:11:35 ug Exp $
 *
 */
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "drivermain.h"
#include "hyperion_base.h"
#include "clf_func.h"
#include "dma_sg_list_buffer.h"

static HYPERION_BASE_REGISTER_DEF CLeRegisterBaseA32[ebrhMax] =
{
#include "hyperion_register_a32.h"
};

static HYPERION_BASE_REGISTER_DEF CL4eRegisterBase[ebrhMax] =
{
#include "hyperion_register_cl4e.h"
};
static HYPERION_BASE_REGISTER_DEF HDSDI4eRegisterBase[ebrhMax] =
{
#include "hyperion_register_hdsdi_4e.h"
};

#define SET_BIT(preg,bit,enable)\
    {\
        u32 reg_value = ioread32( (void __iomem *)preg );\
        if( enable )\
            reg_value |= bit;\
        else\
            reg_value &= ~bit;\
        iowrite32( reg_value, (void __iomem *)preg );\
    }

#define _READ_MAILBOX(mailbox) IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, mailbox )
//-------------------------------------------------------------------------------------------
/// \brief item definition
struct SItem
//-------------------------------------------------------------------------------------------
{
    unsigned long status; ///< current interruptstatus
};

//-------------------------------------------------------------------------------------------
void restart_trigger_hrtc( struct hyperion_device_object* dev_obj, int restart, int hrtc_index )
//-------------------------------------------------------------------------------------------
{
    if( restart )
    {
        IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhTriggerHrtController0 + hrtc_index, OFF_HRT_CONTROLLER_CTRL, 0 );
        IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhTriggerHrtController0 + hrtc_index, OFF_HRT_CONTROLLER_CTRL, HRTC_ENABLE | HRTC_INTERRUPT_ENABLE );
    }
}

//-------------------------------------------------------------------------------------------
int prepare_scatter_gather_list( struct hyperion_device_object* dev_obj, struct io_object* ioobj )
//-------------------------------------------------------------------------------------------
{
    volatile dma_addr_t address;
    int xfer, page_length;
    struct dma_sg_list_entry* list_entry = ( struct dma_sg_list_entry* )ioobj->dma_list_entry;
    u64* sg_list = ( u64* )( list_entry->buf );

    xfer = ( int )ioobj->transfer_param.transferlength;
    //PRINTKM(DMA,(PKTD "prep_sg_list() dto p%p xfer 0x%x isg %u max_e %lu\n", ioobj->device_index, dto, xfer, itt ));
    xfer -= ioobj->sg[0].offset;
    //PRINTKM(DMA,(PKTD "xfer 0x%x offset 0x%x\n", ioobj->device_index, xfer, *offset ));

    if( dev_obj->pci_hyperion_page_size != PAGE_SIZE )
    {
        while( xfer > 0 && ioobj->isg < ioobj->do_dio )
        {
            //PRINTKM(DMA,(PKTD " ScatterGatherList next element %d xfer 0x%x\n", ioobj->device_index, ioobj->isg, xfer ));
            address = sg_dma_address( &ioobj->sg[ioobj->isg] ) & ~3;
            if( dma_supported( &dev_obj->pdev->dev, DMA_BIT_MASK( 64 ) ) )
            {
                const u64 highPart = DMA_BIT_MASK( 32 ) << 32;
                address |= ( address & highPart ) ? dev_obj->address_space_encoding : 0;
            }

            page_length = ( int )( ioobj->sg[ioobj->isg].length );
            while( page_length > 0 )
            {
                *sg_list = cpu_to_le64( ( u64 )address );
                //PRINTKM(DMA,(PKTD " %s: xfer 0x%x itranslationtable %d translationtable %p addr 0x%llx len 0x%x\n", ioobj->device_index, __FUNCTION__, xfer, itt, &translation_table[itt], address, page_length ));
                //printk( " %s: xfer 0x%x sg_list[%d] addr 0x%llx  0x%llx len 0x%x\n", __FUNCTION__, xfer, ioobj->isg, *sg_list, address, sg_dma_len(&ioobj->sg[ioobj->isg])  );
                page_length -= dev_obj->pci_hyperion_page_size;
                address += dev_obj->pci_hyperion_page_size;
                ++sg_list;
                /*if( itt++ >= TRANSLATION_TABLE_ELEMENTS )
                {
                    //PRINTKM(DMA,(PKTD " %s itranslationtable %d return dcecTranslationTableElements\n", ioobj->device_index, __FUNCTION__, itt ));
                    return -dcecTranslationTableElements;
                }*/
            }
            xfer -= ( int )( ioobj->sg[ioobj->isg].length );
            ++ioobj->isg;
        }
    }
    else
    {
        while( xfer > 0 && ioobj->isg < ioobj->do_dio )
        {
            //PRINTKM(DMA,(PKTD " ScatterGatherList next element %d xfer 0x%x\n", ioobj->device_index, ioobj->isg, xfer ));
            address = sg_dma_address( &ioobj->sg[ioobj->isg] ) & ~3;
            if( dma_supported( &dev_obj->pdev->dev, DMA_BIT_MASK( 64 ) ) )
            {
                const u64 highPart = DMA_BIT_MASK( 32 ) << 32;
                address |= ( address & highPart ) ? dev_obj->address_space_encoding : 0;
            }
            *sg_list = cpu_to_le64( ( u64 )address );
            //PRINTKM(DMA,(PKTD " %s: [%d] xfer 0x%x addr 0x%x len 0x%x\n", ioobj->device_index, __FUNCTION__, ioobj->isg, xfer, *sg_list, ioobj->sg[ioobj->isg].length ));
            xfer -= ( int )( ioobj->sg[ioobj->isg].length );
            ++ioobj->isg;
            ++sg_list;
        }
    }
    //PRINTKM(DMA,(PKTD " prepare_scatter_gather_list() page_off 0x%lx ioobj->isg %ld\n", ioobj->device_index, PAGE_SIZE + xfer, ioobj->isg ));
    return dcecNoError;
}

//-------------------------------------------------------------------------------------------
void translate_property32_to_property( TPropertyElement* list, TPropertyElement32* list32, unsigned int prop_count )
//-------------------------------------------------------------------------------------------
{
    int i;
    for( i = 0; i < prop_count; i++ )
    {
        list->PropertyID = le32_to_cpu( list32->PropertyID );
        list->u.intElement =  le32_to_cpu( list32->u.intElement );
        list->Changed =  le32_to_cpu( list32->Changed );
        list->Type =  le32_to_cpu( list32->Type );
        ++list32;
        ++list;
    }
}

//-------------------------------------------------------------------------------------------
void translate_property_to_property32( TPropertyElement* list, TPropertyElement32* list32, unsigned int prop_count )
//-------------------------------------------------------------------------------------------
{
    int i;
    for( i = 0; i < prop_count; i++ )
    {
        list32->PropertyID = cpu_to_le32( list->PropertyID );
        list32->u.intElement =  cpu_to_le32( list->u.intElement );
        list32->Changed =  cpu_to_le32( list->Changed );
        list32->Type =  cpu_to_le32( list->Type );
        ++list32;
        ++list;
    }
}

//-------------------------------------------------------------------------------------------
/// \brief write all results, error, timestamp to requestlist
void write_results_to_rq( struct hyperion_device_object* dev_obj, struct io_object* ioobj )
//-------------------------------------------------------------------------------------------
{
    struct transfer_parameter* tp;
    TPropertyElement32* list_proc_result;
    TPropertyElement* list_request_result;
    u64 proc_timestamp, sec, usec, nsec;
    u32 timestamp_low = 0, timestamp_high = 0;
    unsigned long property_count = 0;
    unsigned int bytes_to_copy = 0;
    u32 changed = 0, /*property_count = 0,*/ request_status = 0, request_id = 0, bytes_transferred_so_far = 0, trigger_frame_start_cnt = 0,
        acquisition_start_cnt = 0, frame_nr = 0;

    tp = &ioobj->transfer_param;
    list_proc_result = ( ( struct dma_sg_list_entry* )( ioobj->dma_list_entry ) )->host_msg;
    list_request_result = ioobj->result_property;
    translate_property32_to_property( list_request_result, list_proc_result, prSnapRequestResultMax );
    _READ_PROPERTYI( list_request_result, 1, prSResPropertyCount, property_count, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSResTimeStampLowPart, timestamp_low, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSResTimeStampHighPart, timestamp_high, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSResRequestID, request_id, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSResStatus, request_status, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSresBytesTransferredSoFar, bytes_transferred_so_far, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSresTriggerFrameStartCounter, trigger_frame_start_cnt, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSresTriggerAcquisitionStartCounter, acquisition_start_cnt, changed );
    _READ_PROPERTYI( list_request_result, property_count, prSResFrameNr, frame_nr, changed );

    PRINTKM( DMA, ( PKTD " %s nios result host_msg %p prop_cnt %lu hi 0x%x lo 0x%x id %u status %u bytestransferred %u\n", ioobj->device_index, __FUNCTION__, ( ( struct dma_sg_list_entry* )( ioobj->dma_list_entry ) )->host_msg, property_count, timestamp_high, timestamp_low, request_id, request_status, bytes_transferred_so_far ) );
    proc_timestamp = timestamp_high;
    proc_timestamp = ( proc_timestamp << 32 ) | timestamp_low;
    sec = proc_timestamp;
    do_div( sec, dev_obj->processor_info.cpu_clk_hz );
    usec = sec * 1000000;
    nsec = ( ( proc_timestamp - sec * dev_obj->processor_info.cpu_clk_hz ) * 1000000 );
    do_div( nsec, dev_obj->processor_info.cpu_clk_hz );
    usec += nsec;
    proc_timestamp = usec;

    list_request_result = ioobj->result_property;
    _SET_PROP_ELEM_I( list_request_result, prSResPropertyCount, prSnapRequestResultMax, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResStatus, request_status, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResRequestID, request_id, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResTimeStampLowPart, ( proc_timestamp & 0xffffffff ), TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResTimeStampHighPart, ( ( proc_timestamp >> 32 ) & 0xffffffff ), TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResScanPixLine0, ioobj->scan_pixel_line0, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResScanPixLine1, ioobj->scan_pixel_line1, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResScanLines, ioobj->scan_lines, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSresBytesTransferredSoFar, bytes_transferred_so_far, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSresTriggerFrameStartCounter, trigger_frame_start_cnt, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSresTriggerAcquisitionStartCounter, acquisition_start_cnt, TRUE );
    _SET_PROP_ELEM_I( list_request_result, prSResFrameNr, frame_nr, TRUE );
    //if( request_status != cerrSuccess )
    //printk( " %s, tstamp %llu, status 0x%x\n", __FUNCTION__, proc_timestamp, request_status );
    //PRINTKM(DMA,(PKTD " %s, tstamp 0x%llx, status 0x%x\n", ioobj->device_index, __FUNCTION__, proc_timestamp, request_status ));
    bytes_to_copy = sizeof( ioobj->result_property ) < ioobj->request_buffer.trailerBufferSize ? sizeof( ioobj->result_property ) : ioobj->request_buffer.trailerBufferSize;
    hyperion_copy_to_trailer( &ioobj->trailerbuf_obj, ( char* )ioobj->result_property, bytes_to_copy );
}

//-------------------------------------------------------------------------------------------
static unsigned char uart_interrupt( struct hyperion_object* device, uart_object_t* pua )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    u32 int_stat, int_en;
    int_stat = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, pua->register_index, OFF_UART_INTR_CLEAR_STAT );
    IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, pua->register_index, OFF_UART_INTR_CLEAR_STAT, int_stat );
    int_en = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, pua->register_index, OFF_UART_INTR_ENABLE );
    return( ( int_stat & int_en ) != 0 );
}


//-------------------------------------------------------------------------------------------
// our top half interrupt handler, only search about the interrupt source
#if LINUX_VERSION_CODE < KERNEL_VERSION (2,6,19)
irqreturn_t hyperion_interrupt( int irq, void* dev_id, struct pt_regs* fake )
#else
// The prototype for interrupt handler functions has changed in 2.6.19.
// In short, the regs argument has been removed, since almost nobody used it.
// Any interrupt handler which needs the pre-interrupt register state can use get_irq_regs() to obtain it.
irqreturn_t hyperion_interrupt( int irq, void* dev_id )
#endif
//-------------------------------------------------------------------------------------------
{
    struct hyperion_object* device = ( struct hyperion_object* )dev_id;
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    u32 pcie_intr_stat = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_PCI_EXPRESS_INTERRUPT_STATUS );
    u32 pcie_intr_enable = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_PCI_EXPRESS_INTERRUPT_ENABLE );
    irqreturn_t ret = IRQ_NONE;
    int interrupting = 0;
    TItem it;
    unsigned char write_ok;

    if( pcie_intr_stat & pcie_intr_enable )
    {
        IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_PCI_EXPRESS_INTERRUPT_STATUS, ( pcie_intr_stat & pcie_intr_enable ) );
        interrupting = TRUE;
    }
    //printk( " %s int_stat 0x%x int_en 0x%x\n", __FUNCTION__, pcie_intr_stat, pcie_intr_enable );

    if( pcie_intr_stat & pcie_intr_enable & AV_IRQ_ASSERTED )
    {
        switch( pcie_intr_stat & AVL_IRQ_INPUT_VECTOR )
        {
        case UART0_IRQ_VEC:
            {
                uart_interrupt( device, &dev_obj->uart_port[0] );
                break;
            }
        case UART1_IRQ_VEC:
            {
                uart_interrupt( device, &dev_obj->uart_port[1] );
                break;
            }
        }
    }

    if( interrupting )
    {
        it.status = ( pcie_intr_stat & pcie_intr_enable );
        it.status |= ( pcie_intr_stat & AVL_IRQ_INPUT_VECTOR );
        _PIPE_WRITE( dev_obj->interrupt_result_pipe, it, write_ok );
        tasklet_schedule( &device->hyperion_tasklet );
        ret = IRQ_HANDLED;
    }

    return ret;
}

//-------------------------------------------------------------------------------------------
void hyperion_do_tasklet( unsigned long index )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_object* device = get_hyperion_device( index );
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    struct io_object* ioobj = NULL;
    struct dma_transfer_object* dto = NULL;
    TItem isr_result;
    message_item msg_it;
    unsigned char read_ok;
    u32 dto_index;
    unsigned long irqflags;
    msg_it.message = 0;

    do
    {
        _PIPE_READ_LOCK( dev_obj->interrupt_result_pipe, &isr_result, read_ok );
        if( read_ok == 0 )
        {
            break;
        }
        //printk( " %s isr_result.status 0x%x\n", __FUNCTION__, isr_result.status );
        if( isr_result.status & A2P_MAILBOX_INT0 )
        {
            signal_sema( dev_obj->sema_message_received, 1 );
        }

        if( isr_result.status & A2P_MAILBOX_INT1 )
        {
            do
            {
                if( _ITEMS_IN_MSG_PIPE_LE32( dev_obj->request_result_message ) )
                {
                    spin_lock_irqsave( &dev_obj->ioctl_lock.s_tasklet, irqflags );
                    _READ_MSG_PIPE_LE32( dev_obj->request_result_message, msg_it );
                    spin_unlock_irqrestore( &dev_obj->ioctl_lock.s_tasklet, irqflags );
                }
                else
                {
                    break;
                }
                //printk(" %s isr_result.status 0x%x message 0x%x\n", __FUNCTION__, isr_result.status, msg_it.message );
                dto_index = _GET_MESSAGE_QUEUE_ID( msg_it.message );
                dto = dev_obj->pdma_object[dto_index];
                ioobj = get_current_iocb( dto->rw_queue );
                if( ioobj != NULL )
                {
                    // read message from nios
                    write_results_to_rq( dev_obj, ioobj );
                    run_next_iocb( dto->rw_queue );
                    complete_request( ioobj, 0 );
                }
            }
            while( 1 );
        }

        if( isr_result.status & A2P_MAILBOX_INT2 )
        {
            unsigned int mb2 = _READ_MAILBOX( OFF_A2P_MAILBOX2 );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_P2A_MAILBOX2, mb2 );
            PRINTKM( INTR, ( PKTD " msg: 0x%08x\n", device->index, mb2 ) );
        }

        if( isr_result.status & AV_IRQ_ASSERTED )
        {
            switch( isr_result.status & AVL_IRQ_INPUT_VECTOR )
            {
            case UART0_IRQ_VEC:
                {
                    read_serial( &dev_obj->uart_port[0] );
                    break;
                }
            case UART1_IRQ_VEC:
                {
                    read_serial( &dev_obj->uart_port[1] );
                    break;
                }
            }
        }
    }
    while( 1 );
}

//-------------------------------------------------------------------------------------------
int commit_request_to_mailbox( struct hyperion_device_object* dev_obj, struct io_object* ioobj )
//-------------------------------------------------------------------------------------------
{
    struct dma_sg_list_entry* list_entry = ( struct dma_sg_list_entry* )ioobj->dma_list_entry;
    struct transfer_parameter* tp = &ioobj->transfer_param;
    TPropertyElement* list0, *list1 = ( TPropertyElement* )list_entry->nios_msg;
    unsigned long property_count = 0;
    message_item msg_it;
    u64 dma_address;

    //preset result_buffer
    list1 = ( TPropertyElement* )list_entry->host_msg;
    list0 = list1;
    ++list1;
    _WRITE_PROPERTYI( list1, prSresBytesTransferredSoFar, 0, TRUE );
    ++property_count;
    _WRITE_PROPERTYI( list1, prSResStatus, cerrDMAAborted, TRUE );
    ++property_count;
    ++property_count;
    _WRITE_PROPERTYI( list0, prSResPropertyCount, property_count, TRUE );
    //request parameter

    _SCAN_PROPERTY_LIST( ioobj->request_parameter, list0, tp->property_count, prClScanMode );
    _WRITE_PROPERTYI( list0, prClScanMode, tp->scanmode ? ( SYNC_STATUS_FRAME | SYNC_STATUS_LINE ) : SYNC_STATUS_LINE, TRUE );
    dma_address = cpu_to_le64( list_entry->phy );
    if( dma_address ==  list_entry->phy )
    {
        _SCAN_PROPERTY_LIST( ioobj->request_parameter, list0, tp->property_count, prDMASGListPhysLowAddress );
        _WRITE_PROPERTYI( list0, prDMASGListPhysLowAddress, le32_to_cpu( dma_address & 0xffffffff ), TRUE );
        _SCAN_PROPERTY_LIST( ioobj->request_parameter, list0, tp->property_count, prDMASGListPhysHighAddress );
        _WRITE_PROPERTYI( list0, prDMASGListPhysHighAddress, le32_to_cpu( ( dma_address >> 32 ) & 0xffffffff ), TRUE );
    }
    else
    {
        _SCAN_PROPERTY_LIST( ioobj->request_parameter, list0, tp->property_count, prDMASGListPhysHighAddress );
        _WRITE_PROPERTYI( list0, prDMASGListPhysHighAddress, le32_to_cpu( dma_address & 0xffffffff ), TRUE );
        _SCAN_PROPERTY_LIST( ioobj->request_parameter, list0, tp->property_count, prDMASGListPhysLowAddress );
        _WRITE_PROPERTYI( list0, prDMASGListPhysLowAddress, le32_to_cpu( ( dma_address >> 32 ) & 0xffffffff ), TRUE );
    }
    //write also to nios_msg_buffer
    translate_property_to_property32( ioobj->request_parameter, ( TPropertyElement32* )list_entry->nios_msg, tp->property_count );
    msg_it.message = MESSAGE_TYPE_REQUEST;
    msg_it.message |= ( ( ( tp->property_count * sizeof( TPropertyElement32 ) ) & MESSAGE_SIZE_MSK ) << MB0_MESSAGE_SIZE ) |  ( list_entry->index << MB0_MESSAGE_INDEX ) | _SET_MESSAGE_QUEUE_ID( tp->inputchannel );
    if( _ITEMS_IN_MSG_PIPE_LE32( dev_obj->request_message ) < le32_to_cpu( dev_obj->request_message.shared_def->items_max ) )
    {
        _WRITE_MSG_PIPE_LE32( dev_obj->request_message, msg_it );
        return 0;
    }
    else
    {
        return -ECOMM;
    }
}

//-------------------------------------------------------------------------------------------
void start_transfer_dummy( struct io_object* ioobj, int index )
//-------------------------------------------------------------------------------------------
{
    PRINTKM( MOD, ( PKTD "%s\n", ioobj->device_index, __FUNCTION__ ) );
}

//-------------------------------------------------------------------------------------------
int start_transfer( struct io_object* ioobj, int index )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_object* device = ( struct hyperion_object* )ioobj->iocb->ki_filp->private_data;
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    struct dma_transfer_object* dto = ioobj->dma_transfer_object;
    struct transfer_parameter* tp = &ioobj->transfer_param;
    unsigned int i = 0, result, mux_ctrl = 0;

    if( tp->has_properties_changed )
    {
        PRINTKM( MOD, ( PKTD "%s rewrite transferparameter\n", ioobj->device_index, __FUNCTION__ ) );
        //dto->rewrite_transfer_parameter = FALSE;
        mux_ctrl |= ( tp->datavalidenable > 0 )     ? DATA_VALID_ENABLE : 0;
        mux_ctrl |= ( !tp->scanmode > 0 )       ? LINE_SCAN_ENABLE : 0;
        mux_ctrl |= ( ( tp->medium_mode_ctrl << MEDIUM_MODE_BIT ) & MEDIUM_MODE_ENABLE );
        mux_ctrl |= ( tp->enable_aoimode > 0 )  ? AOI_ENABLE : 0;
        mux_ctrl |= ( ( tp->expand_lval & EXPAND_LVAL_MSK ) << EXPAND_LVAL );
        PRINTKM( MOD, ( PKTD "%s mux_ctrl %x\n", ioobj->device_index, __FUNCTION__, mux_ctrl ) );
        if( tp->medium_mode_ctrl )
        {
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_AOI_XSTART, tp->xstart );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_AOI_XSTOP, tp->xstop );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_AOI_YSTART, tp->ystart );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_AOI_YSTOP, tp->ystop );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController1, OFF_AOI_XSTART, tp->xstart );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController1, OFF_AOI_XSTOP, tp->xstop );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController1, OFF_AOI_YSTART, tp->ystart );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController1, OFF_AOI_YSTOP, tp->ystop );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_MUX_CONTROLLER, mux_ctrl );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController1, OFF_MUX_CONTROLLER, mux_ctrl );
        }
        else
        {
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_AOI_XSTART, tp->xstart );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_AOI_XSTOP, tp->xstop );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_AOI_YSTART, tp->ystart );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_AOI_YSTOP, tp->ystop );
            IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_MUX_CONTROLLER, mux_ctrl );
        }
        //PRINTKM(DMA,(PKTD " mxctrl[0] 0x%x mxctrl[1] 0x%x",  device->index, *device->register_base.MuxCtrl[0], *device->register_base.MuxCtrl[1]  ));
        SET_BIT( REG_POINTER( dev_obj->hyperion_base, dev_obj->reg_def, ebrhSystemRegister, OFF_SYSTEM_CONTROL ), ENABE_BASE_MODE_CH1, ( tp->medium_mode_ctrl == 0 ) );
        IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_EXTENDED_MODE, tp->line_scan_startcondition );
        IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController1, OFF_EXTENDED_MODE, tp->line_scan_startcondition );
    }
    //PRINTKM(DMA,(PKTD "%s ioobj %p reqId %d, timeout %d\n", ioobj->device_index, __FUNCTION__, ioobj, tp->reqid, tp->timeoutmsec ));
    if( tp->medium_mode_ctrl )
    {
        int delay_j = msecs_to_jiffies( 10 );
        do
        {
            mux_ctrl = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_MUX_CONTROLLER );
            if( mux_ctrl & PHASE_ERROR_DETECT )
            {
                mux_ctrl |= RESET_MEDIUM_CHANNELS;
                IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_MUX_CONTROLLER, mux_ctrl );
                mux_ctrl &= ~RESET_MEDIUM_CHANNELS;
                IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhCLController0, OFF_MUX_CONTROLLER, mux_ctrl );
            }
            else
            {
                break;
            }
            ++i;
            wait_jiffies( delay_j );
        }
        while( i < 10 );
    }
    ( *dev_obj->set_mux_data )( device, &dto->mux_seq, tp->inputchannel );
    ioobj->scan_pixel_line0 = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_SCAN_PIX_LINE0 );
    ioobj->scan_pixel_line1 = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_SCAN_PIX_LINE1 );
    ioobj->scan_lines = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, tp->inputchannel + ebrhCLController0, OFF_SCAN_LINES );

    result = commit_request_to_mailbox( dev_obj, ioobj );
    if( result < 0 )
    {
        PRINTKM( DMA, ( PKTD " commit_request_to_mailbox( ) result %d", dev_obj->index, result ) );
    }
    return result;
}

//-------------------------------------------------------------------------------------------
void hyperion_func_abort_transfer( struct hyperion_object* device )
//-------------------------------------------------------------------------------------------
{
    DECLARE_WAIT_QUEUE_HEAD( wq );
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    struct io_object* ioobj;
    struct dma_transfer_object* dto;
    TPropertyElement* list_request_result;
    int i;
    const int timeout_msec = 100;
    unsigned int message = MESSAGE_TYPE_ABORT_REQUESTS;
    unsigned int bytes_to_copy;

    PRINTKM( DMA, ( PKTD " >%s %lu\n", device->index, __FUNCTION__, jiffies ) );
    for( i = 0; i < MAX_PARALLEL_TRANSFER; i++ )
    {
        dto = dev_obj->pdma_object[i];
        if( get_current_iocb( dto->rw_queue ) )
        {
            dev_obj->aborting_in_process = TRUE;
            transmit_message( dev_obj, message, timeout_msec, NULL, 0, NULL );
            while( ( ioobj = run_next_iocb( dto->rw_queue ) ) != NULL )
            {
                list_request_result = ioobj->result_property;
                _SET_PROP_ELEM_I( list_request_result, prSResPropertyCount, prSnapRequestResultMax, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResStatus, cerrDMAAborted, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResRequestID, ioobj->transfer_param.reqid, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResTimeStampLowPart, 0, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResTimeStampHighPart, 0, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResScanPixLine0, ioobj->scan_pixel_line0, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResScanPixLine1, ioobj->scan_pixel_line1, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSResScanLines, ioobj->scan_lines, TRUE );
                _SET_PROP_ELEM_I( list_request_result, prSresBytesTransferredSoFar, 0, TRUE );
                bytes_to_copy = sizeof( ioobj->result_property ) < ioobj->request_buffer.trailerBufferSize ? sizeof( ioobj->result_property ) : ioobj->request_buffer.trailerBufferSize;
                hyperion_copy_to_trailer( &ioobj->trailerbuf_obj, ( char* )ioobj->result_property, bytes_to_copy );
                complete_request( ioobj, 0 );
            }
        }
    }
    dev_obj->aborting_in_process = FALSE;
    PRINTKM( DMA, ( PKTD " <%s %lu\n", device->index, __FUNCTION__, jiffies ) );
}//abort_transfer

//-------------------------------------------------------------------------------------------
int hyperion_func_async_read( struct hyperion_object* device, struct io_object* ioobj )
//-------------------------------------------------------------------------------------------
{
    int result = 0;
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    struct dma_sg_list_entry* dma_list_entry = NULL;

    if( dev_obj->user_flash_enabled == FALSE )
    {
        printk( MODULE_NAME " %s userflash with correct firmware file not programmed, read access cancelled\n", __FUNCTION__ );
        return -1010;
    }

    if( ioobj->transfer_param.reqaction == raiSnapRequest && !dev_obj->aborting_in_process )
    {
        struct dma_transfer_object* dto = dev_obj->pdma_object[ioobj->transfer_param.inputchannel];
        ioobj->dma_transfer_object = ( void* )dto;
        //iocb->ki_cancel = cancel_async_read_write;
        if( dev_obj->mux_seq.changed )
        {
            dev_obj->mux_seq.changed = FALSE;
            dto->mux_seq.changed = TRUE;
            dto->mux_seq.size = dev_obj->mux_seq.size;
            memcpy( ( void* )dto->mux_seq.muxdata, ( void* )dev_obj->mux_seq.muxdata, MUX_CONTROLLER_SEQUENCE_SIZE_BYTES );
        }
        if( ioobj->ubuf_obj->dma_list_entry == NULL )
        {
            dma_list_entry = get_sg_list_buffer( dev_obj );
            if( dma_list_entry == NULL )
            {
                return -ENOMEM;
            }
            ioobj->dma_list_entry = ( void* )dma_list_entry;
            if( prepare_scatter_gather_list( dev_obj, ioobj ) < 0 )
            {
                return -ENOMEM;
            }
            ioobj->ubuf_obj->dma_list_entry = ( void* )dma_list_entry;
        }
        else
        {
            ioobj->dma_list_entry = ioobj->ubuf_obj->dma_list_entry;
        }
        PRINTKM( DMA, ( PKTD " %s reqid %d\n", device->index, __FUNCTION__, ioobj->transfer_param.reqid ) );
        run_iocb( dto->rw_queue, ioobj );
        result = start_transfer( ioobj, 0 );
        return result;
    }
    else
    {
        return -EFAULT;
    }
}

//-------------------------------------------------------------------------------------------
void prepare_communication_buffer( struct hyperion_device_object* dev_obj )
//-------------------------------------------------------------------------------------------
{
    u64* comm_buffer = ( u64* )REG_POINTER( dev_obj->hyperion_base, dev_obj->reg_def, ebrhOnChipMemData, 0 );
    int i;

    PRINTKM( MOD, ( PKTD " %s hyperion base %p\n", dev_obj->index, __FUNCTION__, dev_obj->hyperion_base.base ) );
    for( i = 0; i < MAX_COUNT_REQUEST_OBJECT; i++ )
    {
        *comm_buffer = cpu_to_le64( dev_obj->dma_sg_list_pool[i].nios_msg_phy );
        PRINTKM( MOD, ( PKTD " %s %p %llx\n", dev_obj->index, __FUNCTION__, comm_buffer, ( long long unsigned int )( *comm_buffer ) ) );
        ++comm_buffer;
        *comm_buffer = cpu_to_le64( dev_obj->dma_sg_list_pool[i].host_msg_phy );
        PRINTKM( MOD, ( PKTD " %s %p %llx\n", dev_obj->index, __FUNCTION__, comm_buffer, ( long long unsigned int )( *comm_buffer ) ) );
        ++comm_buffer;
    }
}


//-------------------------------------------------------------------------------------------
void initialize_message_pipe( struct hyperion_device_object* dev_obj, message_pipe* msg_pipe, unsigned long off_shared, unsigned long off_pipe, unsigned long size_pipe )
//-------------------------------------------------------------------------------------------
{
    msg_pipe->shared_def = ( message_pipe_shared_def* )( REG_POINTER( dev_obj->hyperion_base, dev_obj->reg_def, ebrhOnChipMemData, off_shared ) );
    msg_pipe->data = ( message_item* )( REG_POINTER( dev_obj->hyperion_base, dev_obj->reg_def, ebrhOnChipMemData, off_pipe ) );
    msg_pipe->head = msg_pipe->data;
    msg_pipe->tail = msg_pipe->data;
    msg_pipe->shared_def->items_r = 0;
    msg_pipe->shared_def->items_w = 0;
    msg_pipe->shared_def->items_max = cpu_to_le32( size_pipe / sizeof( message_item ) ); // will be overwritte from fpga processor
    msg_pipe->shared_def->host_initialized = 1;
}

//-------------------------------------------------------------------------------------------
int hyperion_func_init( struct hyperion_object* device, unsigned long control )
//-------------------------------------------------------------------------------------------
{
    int i, result = 0;
    u32 system_ctrl_reg;
    struct hyperion_device_object* dev_obj = kmalloc( sizeof( struct hyperion_device_object ), GFP_KERNEL );

    PRINTKM( MOD, ( PKTD " >%s\n", device->index, __FUNCTION__ ) );
    if( dev_obj == NULL )
    {
        return -ENOMEM;
    }
    memset( dev_obj, 0, sizeof( struct hyperion_device_object ) );
    device->hyperion_device_object = ( void* )dev_obj;
    dev_obj->index = device->index;
    spin_lock_init( &dev_obj->ioctl_lock.s_message );
    spin_lock_init( &dev_obj->ioctl_lock.s_tasklet );
    spin_lock_init( &dev_obj->ioctl_lock.s_generic );
    spin_lock_init( &dev_obj->ioctl_lock.s_request );
    spin_lock_init( &dev_obj->ioctl_lock.s_digital_io );
    dev_obj->sema_message_received = create_sema ( 0, 1 );
    dev_obj->pdev = device->pdev;
    dev_obj->address_space_encoding = DMA_ADDRESS_SPACE_ENCODING_32BIT;
    if( !pci_set_dma_mask( device->pdev, DMA_BIT_MASK( 64 ) ) )
    {
        dev_obj->address_space_encoding = DMA_ADDRESS_SPACE_ENCODING_64BIT;
        pci_set_consistent_dma_mask( device->pdev, DMA_BIT_MASK( 64 ) );
    }
    else if( !pci_set_dma_mask( device->pdev, DMA_BIT_MASK( 32 ) ) )
    {
        pci_set_consistent_dma_mask( device->pdev, DMA_BIT_MASK( 32 ) );
    }
    else
    {
        printk( KERN_WARNING " %s: No suitable DMA available.\n", __FUNCTION__ );
        return -1000;
    }
    result = init_sg_buffer_list( device );
    if( result < 0 )
    {
        return result;
    }
    for( i = 0; i < MAX_PARALLEL_TRANSFER; i++ )
    {
        dev_obj->pqueues[i] = &dev_obj->dq_read_write[i];
        dev_obj->pdma_object[i] = &dev_obj->dma_transfer_object[i];
        initialize_queue( dev_obj->pqueues[i], start_transfer_dummy, i );
        //serialOK = CreateSerialCommunication( &device->UartPort[i], (PUCHAR)device->Register.UARTReg[i].UARTRead, i );
        ///< todo check result queue and communication
    }
    dev_obj->pqueue_result = &dev_obj->dq_result;
    initialize_queue( dev_obj->pqueue_result, start_transfer_dummy, 0 );
    switch( device->vd_id.deviceId )
    {
    case PCI_DEVICE_ID_HYPERION_CL4E:
        PRINTKM( MOD, ( PKTD " initialize PCI_DEVICE_ID_HYPERION_CL4E\n", device->index ) );
        dev_obj->hyperion_base.base = device->memory_base[2].base;
        dev_obj->hyperion_base.size = device->memory_base[2].size;
        dev_obj->reg_def = CL4eRegisterBase;
        break;
    case PCI_DEVICE_ID_HYPERION_HDSDI_4X:
        PRINTKM( MOD, ( PKTD " initialize PCI_DEVICE_ID_HYPERION_HDSDI_4X\n", device->index ) );
        dev_obj->hyperion_base.base = device->memory_base[2].base;
        dev_obj->hyperion_base.size = device->memory_base[2].size;
        dev_obj->reg_def = HDSDI4eRegisterBase;
        break;
    default:
    case PCI_DEVICE_ID_HYPERION_CLE:
        PRINTKM( MOD, ( PKTD " initialize PCI_DEVICE_ID_HYPERION_CLE\n", device->index ) );
        dev_obj->hyperion_base.base = device->memory_base[0].base;
        dev_obj->hyperion_base.size = device->memory_base[0].size;
        dev_obj->reg_def = CLeRegisterBaseA32;
        break;
    }

    system_ctrl_reg = IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhSystemRegister, OFF_SYSTEM_CONTROL );
    dev_obj->pci_hyperion_page_size = system_ctrl_reg & HYPERION_PCI_PAGE_SIZE_64K ? PAGE_SIZE_64K : PAGE_SIZE_4K;
    PRINTKM( MOD, ( PKTD " hyperion page_size %d kB sys_ctrl 0x%x\n",  dev_obj->index, dev_obj->pci_hyperion_page_size / KB, system_ctrl_reg ) );

    if( IO_READ_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhSystemRegister, OFF_SYSTEM_VERSION ) == 0 )
    {
        printk( "hyperion2 module" " %s default flash found, grabber functionality reduced to flashupdate\n", __FUNCTION__ );
        dev_obj->user_flash_enabled = FALSE;
        return 0;
    }
    else
    {
        dev_obj->user_flash_enabled = TRUE;
    }

    // initialize DMA_TRANSFER_OBJECT's
    for( i = 0; i < MAX_PARALLEL_TRANSFER; i++ )
    {
        dev_obj->pdma_object[i]->index = i;
        SET_BIT( REG_POINTER( dev_obj->hyperion_base, dev_obj->reg_def, i + ebrhCLController0, OFF_MUX_CONTROLLER ), AOI_ENABLE, TRUE );
        dev_obj->pdma_object[i]->rw_queue = dev_obj->pqueues[i];
        dev_obj->pdma_object[i]->init_done = FALSE;
        CreatePoCLObject( &dev_obj->pocl[i], dev_obj->hyperion_base.base, dev_obj->reg_def, i + ebrhPoCLCtrl0 );
        if( control & _Ctrl( POCL ) )
        {
            PoCLChanged( &dev_obj->pocl[i], TRUE );
        }
    }

    dev_obj->reg_def[ebrhOnChipMemData].offset = ONCHIP_MEM_DATA_BASE;
    dev_obj->reg_def[ebrhOnChipMemData].offset = ONCHIP_MEM_DATA_BASE;
    prepare_communication_buffer( dev_obj );
    _PIPE_INITIALIZE( dev_obj->interrupt_result_pipe, DMA_RESULT_QUEUE_LEN );

    //this are our communication path to the fpga processor. The pipes initialized here are located in a shared buffer from fpga.
    initialize_message_pipe( dev_obj, &dev_obj->request_message, OFF_ONCHIP_MEM_DATA_NIOS_MSG_HEADER, OFF_ONCHIP_MEM_DATA_NIOS_MSG_PIPE, SIZE_ONCHIP_MEM_DATA_NIOS_MSG_PIPE );
    initialize_message_pipe( dev_obj, &dev_obj->request_result_message, OFF_ONCHIP_MEM_DATA_HOST_MSG_HEADER, OFF_ONCHIP_MEM_DATA_HOST_MSG_PIPE, SIZE_ONCHIP_MEM_DATA_HOST_MSG_PIPE );
    hold_nios_in_reset( ( unsigned char* )dev_obj->hyperion_base.base );
    dev_obj->processor_info.cpu_clk_hz = 100 * 1000000;
    dev_obj->processor_status = cnerrNiosStopped;
    dev_obj->processor_app_size = 0;
    dev_obj->eeprom_write_access = -1;
    //PRINTKM(MOD,(PKTB " <%s --> irqlin %d\n", dev_obj->index, __FUNCTION__, device->irqlin));
    PRINTKM( MOD, ( PKTD " <%s\n", device->index, __FUNCTION__ ) );
    return result;
}

//-------------------------------------------------------------------------------------------
int hyperion_func_close( struct hyperion_object* device )
//-------------------------------------------------------------------------------------------
{
    int i;
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;

    IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_PCI_EXPRESS_INTERRUPT_ENABLE, 0 );
    for( i = 0; i < UART_NUM; i++ )
    {
        ClosePoCL( &dev_obj->pocl[i] );
    }
    _PIPE_DESTROY( dev_obj->interrupt_result_pipe );
    release_sg_buffer_list( device );
    hyperion_halt_processor( device );
    kfree( dev_obj );
    return 0;
}

//-------------------------------------------------------------------------------------------
int hyperion_func_enable_interrupt( struct hyperion_object* device )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_PCI_EXPRESS_INTERRUPT_ENABLE, AVL_IRQ | A2P_MAILBOX_INT0 | A2P_MAILBOX_INT1 | A2P_MAILBOX_INT2 );
    return 0;
}

//-------------------------------------------------------------------------------------------
int query_processor_system_infos( struct hyperion_device_object* dev_obj )
//-------------------------------------------------------------------------------------------
{
    int result = 0;
    unsigned long cpu_clk_hz, message = MESSAGE_TYPE_SYSTEM_INFO;
    message |= QUERY_CPU_CLK_HZ;
    result = transmit_message( dev_obj, message, 500, NULL, 0, &cpu_clk_hz );
    if( result < 0 || cpu_clk_hz == 0 )
    {
        cpu_clk_hz = 100 * 1000000;
    }
    dev_obj->processor_info.cpu_clk_hz = cpu_clk_hz;
    printk( " %s  fpga processor cpuclk_hz %d status %x", __FUNCTION__, dev_obj->processor_info.cpu_clk_hz, result );
    return result;
}

//-------------------------------------------------------------------------------------------
void hyperion_halt_processor( struct hyperion_object* device )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    hold_nios_in_reset( ( unsigned char* )dev_obj->hyperion_base.base );
}

//-------------------------------------------------------------------------------------------
int hyperion_boot_processor( struct hyperion_device_object* dev_obj, void* apps, unsigned int size )
//-------------------------------------------------------------------------------------------
{
    int i, result = -ENODEV;
    const int retries = 10;
    for( i = 0; i < retries; i++ )
    {
        if( start_nios_cpu( ( unsigned char* )dev_obj->hyperion_base.base, apps, size ) )
        {
            wait_jiffies( msecs_to_jiffies( 100 ) );
            result = query_processor_system_infos( dev_obj );
            printk( " %s, hyperion board fpga processor started successfully status 0x%x\n", __FUNCTION__, result );
        }
        else
        {
            result = -ENXIO;
            printk( " %s, hyperion board fpga processor not started status 0x%x\n", __FUNCTION__, result );
        }
        if( result == 0 )
        {
            break;
        }
    }
    return result;
}

//-------------------------------------------------------------------------------------------
int transmit_message( struct hyperion_device_object* dev_obj, unsigned int message, unsigned int timeout_msec, void* buffer, unsigned int size, unsigned long* processor_result )
//-------------------------------------------------------------------------------------------
{
    unsigned long irqflags;
    int wait, result = -ENODATA;
    spin_lock_irqsave( &dev_obj->ioctl_lock.s_message, irqflags );
    if( buffer != NULL && size > 0 && size <= SIZE_ONCHIP_MEM_DATA_SHARED_BUFFER_NIOS )
    {
        memcpy( ( void* )( ( char* )dev_obj->hyperion_base.base + ONCHIP_MEM_DATA_BASE + OFF_ONCHIP_MEM_DATA_SHARED_BUFFER_NIOS ), buffer, size );
    }
    reset_sema ( dev_obj->sema_message_received );
    IO_WRITE_32( dev_obj->hyperion_base, dev_obj->reg_def, ebrhPCICore, OFF_P2A_MAILBOX0, message );
    wait = msecs_to_jiffies( timeout_msec );
    while( wait > 0 )
    {
        wait_jiffies( 1 );
        result = wait_sema ( dev_obj->sema_message_received, 0 );
        if( result == ObjSignaled )
        {
            break;
        }
        --wait;
    }
//  result = wait_sema ( dev_obj->sema_message_received, timeout_msec );
    if( result == ObjSignaled )
    {
        if( processor_result != NULL )
        {
            *processor_result = _READ_MAILBOX( OFF_A2P_MAILBOX0 );
            PRINTKM( MOD, ( PKTD " %s result %x " " mailbox0 0x%lx" "\n", dev_obj->index, __FUNCTION__, result, *processor_result ) );
            result = 0;
        }
    }
    else
    {
        result = -ETIME;
    }

    spin_unlock_irqrestore( &dev_obj->ioctl_lock.s_message, irqflags );
    return result;
}

//-------------------------------------------------------------------------------------------
void hyperion_func_complete( struct io_object* ioobj )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_object* device = ( struct hyperion_object* )ioobj->iocb->ki_filp->private_data;
#ifdef REMOVE_REQUEST_BUFFER_MAPPING
    free_ubuf( device, &ioobj->ubuf_obj );
#else
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    if( dev_obj->aborting_in_process )
    {
        free_ubuf( device, &ioobj->ubuf_obj );
    }
    else
    {
        run_iocb( dev_obj->pqueue_result, ioobj );
    }
#endif
}

//-------------------------------------------------------------------------------------------
void hyperion_func_release_dma( struct hyperion_object* device, void* dma_list_entry )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
    free_sg_list_buffer( dev_obj, ( struct dma_sg_list_entry* )dma_list_entry );
}

//-------------------------------------------------------------------------------------------
void hyperion_func_release_hw( struct hyperion_object* device )
//-------------------------------------------------------------------------------------------
{
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;
#ifdef REMOVE_REQUEST_BUFFER_MAPPING
    struct io_object* ioobj = NULL;
#endif
    hyperion_func_abort_transfer( device );
    hyperion_halt_processor( device );
#ifdef REMOVE_REQUEST_BUFFER_MAPPING
    while( ( ioobj = run_next_iocb( dev_obj->pqueue_result ) ) != NULL )
    {
        free_ubuf( device, &ioobj->ubuf_obj );
    }
#endif
    free_all_ubuf( device );
}

//-------------------------------------------------------------------------------------------
void hyperion_func_camera_power( struct hyperion_object* device, int state )
//-------------------------------------------------------------------------------------------
{
    int i;
    struct hyperion_device_object* dev_obj = ( struct hyperion_device_object* )device->hyperion_device_object;

    for( i = 0; i < MAX_PARALLEL_TRANSFER; i++ )
    {
        PoCLChanged( &dev_obj->pocl[i], state );
    }

}

