/*
 * clf_func.c  -- MATRIX VISION Frame Grabber Driver for mvHyperion series.
 *
 *   Copyright (c) 2006 MATRIX VISION GmbH (info@matrix-vision.de)
 *
 $Id: user_buffer.c,v 1.9 2009-08-20 06:59:15 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"

//-------------------------------------------------------------------------------------------
void free_ubuf( struct hyperion_object* device, struct user_buffer_list** ubuf_obj )
//-------------------------------------------------------------------------------------------
{
    unsigned long irqflags;
    /*  int i;
        struct scatterlist *sgl;*/
    if( *ubuf_obj != NULL )
    {
        struct user_buffer_list* puo = *ubuf_obj;
        spin_lock_irqsave( &device->s_lock, irqflags );
        list_del_init( &puo->list );
        hyperion_release_dma( device, puo );
        spin_unlock_irqrestore( &device->s_lock, irqflags );
        if( puo->sg )
        {
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 26 )
            dma_unmap_sg_attrs( &device->pdev->dev, puo->sg, puo->nr_pages, PCI_DMA_FROMDEVICE, ( struct dma_attrs* )device->pdma_attrs );
#else //KERNEL_VERSION( 2, 6, 26 )
            dma_unmap_sg( &device->pdev->dev, puo->sg, puo->nr_pages, PCI_DMA_FROMDEVICE );
#endif

            /*
                        sgl = ubuf_obj->sg;
                            for (i=0; i < ubuf_obj->nr_pages; i++)
                            {
                                    pci_unmap_page( device->pdev, sgl[i].dma_address, PAGE_SIZE, PCI_DMA_FROMDEVICE );
                            }
            */
            sgl_unmap_user_pages( puo->sg, puo->nr_pages, 0 );
            vfree( puo->sg );
        }
        vfree( puo );
        *ubuf_obj = NULL;
    }
}

//-------------------------------------------------------------------------------------------
void free_ubuf_obj( struct hyperion_object* device, char __user* buffer, size_t count )
//-------------------------------------------------------------------------------------------
{
    struct user_buffer_list* ubuf_obj;
    ubuf_obj = get_user_buffer_obj( device, buffer, count );
    PRINTKM( DMA, ( PKTD "%s ubuf p%p obj p%p\n", device->index, __FUNCTION__, buffer, ubuf_obj ) );
    free_ubuf( device, &ubuf_obj );
}

//-------------------------------------------------------------------------------------------
void free_all_ubuf( struct hyperion_object* device )
//-------------------------------------------------------------------------------------------
{
    struct list_head* lh = device->head_uaddr.next;
    struct user_buffer_list* ubuf_obj = NULL;
    unsigned long irqflags;

    printk( " %d %s\n", device->index, __FUNCTION__ );
    while ( lh != &device->head_uaddr )
    {
        spin_lock_irqsave( &device->s_lock, irqflags );
        ubuf_obj = list_entry( lh, struct user_buffer_list, list );
        lh = lh->next;
        spin_unlock_irqrestore( &device->s_lock, irqflags );
        free_ubuf( device, &ubuf_obj );
    }
    INIT_LIST_HEAD( &device->head_uaddr );
}

//-------------------------------------------------------------------------------------------
struct user_buffer_list* get_user_buffer_obj( struct hyperion_object* device, char __user* buf, size_t count )
//-------------------------------------------------------------------------------------------
{
    struct list_head* lh;
    struct user_buffer_list* ubuf_obj = NULL;
    unsigned long irqflags;

    spin_lock_irqsave( &device->s_lock, irqflags );
    for( lh = device->head_uaddr.next; ; lh = lh->next )
    {
        if( lh == &device->head_uaddr )
        {
            PRINTKM( MEM, ( PKTD " %s buf %p not found in ubuf_obj list add new\n", device->index, __FUNCTION__, buf ) );
            break;
        }
        if( list_entry( lh, struct user_buffer_list, list )->buf == buf )
        {
            ubuf_obj = list_entry( lh, struct user_buffer_list, list );
            PRINTKM( MEM, ( PKTD " %s sg_list found entry ubuf_obj %p buf %p\n", device->index, __FUNCTION__, ubuf_obj, buf ) );
            break;
        }
    }
    spin_unlock_irqrestore( &device->s_lock, irqflags );
    return ubuf_obj;
}
