⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma.c

📁 windows ce 6.0 camera driver
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//

#include <windows.h>
#include <ceddk.h>
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <nkintr.h>

#include "qci.h"
#include "qci_private.h"

#define MAX_BUF_NUM 1200
#define MAX_FRAG_NUM 10
#define MAX_EMPTY_NUM 5

#define SINGLE_DESCRIPTOR_TRANSFER_MAX  4096
frame_list_t *current_frame_list;
frame_t *video_frame_tail;


static void frame_dma_link(frame_t *f1, frame_t *f2);
static void free_frame(frame_t* frame);
static frame_list_t* find_frame_list(format_t* format);
static void frame_free_dma_buf(frame_t *frame);



void DMABufAlloc(dma_buf_t *buf, UINT32 size, BOOL cache)
{
    DMA_ADAPTER_OBJECT adapter;
    PHYSICAL_ADDRESS   phy_addr;

    adapter.ObjectSize    = sizeof (DMA_ADAPTER_OBJECT);
    adapter.InterfaceType = Internal;
    adapter.BusNumber     = 0;
    buf->buf = HalAllocateCommonBuffer(&adapter, size, &phy_addr, FALSE);
    buf->phy_addr = phy_addr.LowPart;
    buf->size = size;

    if (!buf->buf)
    {
        ERRORMSG(1,(L"[Camera]: QCI Failed to AllocateBuffer!!!\r\n"));
        return;
    }
    
    if (cache)
        buf->buf = MmMapIoSpace(phy_addr, size, TRUE);
    
}

void DMABufFree(dma_buf_t *buf)
{
    PHYSICAL_ADDRESS phy_addr;

    if (buf->buf == NULL)
        return;

    memset(&phy_addr, 0, sizeof(phy_addr));
    HalFreeCommonBuffer(NULL, 0, phy_addr, (PVOID)buf->buf, 0);
    buf->buf = NULL;
}

#define DMA_DESC_SIZE (sizeof(PXA_CI_DMAC_DESCRIPTOR_T))


// Add the buffer into the buffer pool and generate the DMA chains for the buffer
static BOOL dma_chain_init(plane_t *plane,
                           UINT32 dma_chain)
{
    UINT32 i, n = 0;
    UINT32 size = 0;
    UINT32 remain = 0;
    PXA_CI_DMAC_DESCRIPTOR_T *descs;
    UINT32 descs_n;
    UINT32 phy_addr;
    UINT32 buf_phy_addr;

    descs = (PXA_CI_DMAC_DESCRIPTOR_T*)plane->desc_buf.buf;
    descs_n = plane->desc_buf.size / sizeof(*descs);
    phy_addr = plane->desc_buf.phy_addr;
    remain = plane->buf.size;
    buf_phy_addr = plane->buf.phy_addr;

    for (i = 0; i < descs_n; i++)
    {
        if (remain == 0)
        {
            ERRORMSG(1, (L"[Camera]: DMA buffer is smaller than expected!!!\r\n"));
            return FALSE;
        }

        size = remain > SINGLE_DESCRIPTOR_TRANSFER_MAX?
                SINGLE_DESCRIPTOR_TRANSFER_MAX : remain;

        phy_addr += sizeof(*descs);
        descs[i].ddadr = phy_addr;
        descs[i].dsadr = dma_chain;
        descs[i].dtadr = buf_phy_addr;
        descs[i].dcmd = size | PXA_CI_DMAC_DCMD_INC_TRG_ADDR;

        remain -= size;
        buf_phy_addr += size;
    }
    return TRUE;
}


// calculate frame buffer sizes by frame format and dimension
static void get_buffer_desc_size(int format,
                          UINT32 width,
                          UINT32 height,
                          int plane_size[3],
                          int n_descs[3])
{
    UINT32 frame_size;
    int i;

    plane_size[0] = 0;
    plane_size[1] = 0;
    plane_size[2] = 0;

    switch(format) 
    {
    case PXA_CAMERA_IMAGE_FORMAT_RAW10:
    case PXA_CAMERA_IMAGE_FORMAT_RAW9:
    case PXA_CAMERA_IMAGE_FORMAT_RGB565:
    case PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
        frame_size = width * height * 2;
        plane_size[0] = frame_size;
        break;
    case PXA_CAMERA_IMAGE_FORMAT_RGB888_PACKED:
        frame_size = width * height * 3;
        plane_size[0] = frame_size;
        break;
    case PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
        frame_size = width * height * 2;
        plane_size[0] = frame_size / 2;
        plane_size[1] = frame_size / 4;
        plane_size[2] = frame_size / 4;
        break;
    default:
        break;
    }

    for (i = 0; i < 3; i++)
        n_descs[i] = (plane_size[i] + SINGLE_DESCRIPTOR_TRANSFER_MAX - 1) 
                     / SINGLE_DESCRIPTOR_TRANSFER_MAX;
}

UINT32 round(UINT32 x, UINT32 y)
{
    return ((x + y - 1) / y) * y;
}

#define MIN(x, y) ((x) > (y)? (y) : (x))



static BOOL frame_alloc_dma_buf(frame_t *frame)
{
    int plane_size[3];
    int n_descs[3];
    int i;
    //UINT32 chain_tbl[3] = {g_pCIRegs->PXA_CIBR0, g_pCIRegs->PXA_CIBR1, g_pCIRegs->PXA_CIBR2};
    
    UINT32 chain_tbl[3] = {(PXA_CI_REGBASE_PHY+0x28), (PXA_CI_REGBASE_PHY+0x30), (PXA_CI_REGBASE_PHY+0x38)};
    
    format_t* format = &frame->list->format;
  
    get_buffer_desc_size(format->format, format->width, format->height,
                         plane_size, n_descs);

    for (i = 0; i < 3; i++)
    {
        plane_t *plane = &frame->plane[i];
        int desc_buf_size;
        int rev = 0;

        if (!plane_size[i])
            break;

        desc_buf_size = n_descs[i] * sizeof(PXA_CI_DMAC_DESCRIPTOR_T);
        DMABufAlloc(&plane->desc_buf, desc_buf_size, 0);
        if (!plane->desc_buf.buf)
            goto clean;

        DMABufAlloc(&plane->buf, round(plane_size[i], 16), 1);

        if (!plane->buf.buf)
            goto clean;

        if (!dma_chain_init(plane, chain_tbl[i]))
            goto clean;
    }

    return TRUE;

clean:
    frame_free_dma_buf(frame);
    ERRORMSG(1, (L"[Camera]: Failed to Allocate DMABuffer!!!"));
    
    return FALSE;
}

static void frame_free_dma_buf(frame_t *frame)
{
    UINT32 i;

    for (i = 0; i < 3; i++)
    {
        plane_t *plane = &frame->plane[i];

        DMABufFree(&plane->buf);
        DMABufFree(&plane->desc_buf);
    }
}

static void frame_link(frame_t *f1, frame_t *f2)
{
    f1->next = f2;
    frame_dma_link(f1, f2);
}

// mark a frame before dma transfer.
// if a mark is overwritten, it means the frame is ready
const short dma_mark[4] = { 0x0, 0xffff, 0x0, 0xffff };

static char *get_mark_ptr(frame_t *frame)
{
    plane_t *plane = &frame->plane[0];
    dma_buf_t *buf = &plane->buf;
    return buf->buf + buf->size - sizeof(dma_mark);
}

static void frame_clean_cache(frame_t *frame)
{
    UINT32 i;

    for (i = 0; i < 3; i++)
        CacheRangeFlush(frame->plane[i].buf.buf, frame->plane[i].buf.size, CACHE_SYNC_DISCARD);
}
static void frame_mark(frame_t *frame)
{
    char *mark = get_mark_ptr(frame);

    memcpy(mark, dma_mark, sizeof(dma_mark));
}

static BOOL frame_check_mark(frame_t *frame)
{
    //char *mark = get_mark_ptr(frame);
    short *mark = (short*)get_mark_ptr(frame);
    if ( dma_mark[0] == mark[0]
      && dma_mark[1] == mark[1]
      && dma_mark[2] == mark[2]
      && dma_mark[3] == mark[3] )
    {
        return TRUE;
    }
    return FALSE;    
    //return memcmp(mark, dma_mark, sizeof(dma_mark)) == 0;
}

static void frame_dma_link(frame_t *f1, frame_t *f2)
{
    UINT32 i;

    for (i = 0; i < 3; i++)
    {
        PXA_CI_DMAC_DESCRIPTOR_T *descs;
        UINT32 descs_n;
        plane_t *p1 = &f1->plane[i];
        plane_t *p2 = &f2->plane[i];

        if (!p1->buf.buf)
            return;

        descs = (PXA_CI_DMAC_DESCRIPTOR_T*)p1->desc_buf.buf;
        descs_n = p1->desc_buf.size / sizeof(*descs);

        descs[descs_n - 1].ddadr = p2->desc_buf.phy_addr;
    }
}

static void frame_append(frame_t *frame)
{
    if (!frame->list)
        return;

    frame->next = NULL;
    frame_mark(frame);
    frame_clean_cache(frame);
    frame_dma_link(frame, frame);

    if (!frame->list->head)
        frame->list->head = frame;
    else
        frame_link(frame->list->tail, frame);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -