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

📄 dma.c

📁 wince 6.0 摄像头(ov7670)驱动,已在ce6测试通过
💻 C
字号:
//
// 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;
int still_skips;

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 (cache)
        buf->buf = MmMapIoSpace(phy_addr, size, TRUE);
    
    if (!buf->buf)
        DEBUGMSG( ZONE_IOCTL, ( _T("CAM: qci failed to alloc buffer %d!\r\n"), size) );        
    else
    DEBUGMSG( ZONE_IOCTL, ( _T("CAM: dma_buf_alloc: Size:%d     VirtualAddr:0x%x     PhyAddr:0x%x\r\n"),size,buf->buf,buf->phy_addr) );
    
}

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)
        {
            DEBUGMSG( ZONE_IOCTL, ( _T("CAM: 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 = PXA_CI_REGBASE_PHY + dma_chain;
        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 int chain_tbl[3] = { PXA_CIBR0, PXA_CIBR1, PXA_CIBR2 };



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};
	
    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);
    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);

    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);

    frame->list->tail = frame;
}

static frame_t *frame_take()
{
    frame_t *frame;

    frame = current_frame_list->head;

    if (frame == NULL)
        return NULL;

    /* to keep DMA running
    * the last frame should not be removed
    */
    if (frame->next == NULL)
        return NULL;

    if (frame_check_mark(frame))
        return NULL;

    current_frame_list->head = frame->next;

    return frame;
}

static frame_t* alloc_frame(frame_list_t *list)
{
    frame_t *frame;

    frame = malloc(sizeof(frame_t));
    
    if (frame == NULL)
        return FALSE;

    memset(frame, 0, sizeof(frame_t));

    frame->list = list;

    if (!frame_alloc_dma_buf(frame))
            goto err_alloc_frame;

    return frame;

err_alloc_frame:
    free_frame(frame);
    return NULL;
}

static void free_frame(frame_t* frame)
{
    frame_free_dma_buf(frame);
    free(frame);
}

static void free_frame_list(frame_list_t* list)
{
    frame_t* i;
    frame_t* next;
    for (i = list->head; i; i = next)
    {
        next = i->next;
        free_frame(i);
    }
}

#define N_STILL_FRAMES 1
#define N_VIDEO_FRAMES 4

static BOOL alloc_frame_list(frame_list_t *list)
{
    int i;
    int n;

    if (list->format.is_still)
        n = N_STILL_FRAMES;
    else
        n = N_VIDEO_FRAMES;

    for (i = 0; i < n; i++)
    {
        frame_t* tmp = alloc_frame(list);
        if (!tmp)
        {
            free_frame_list(list);
            return FALSE;
        }

        frame_append(tmp);
    }

    return TRUE;
}

#define MAX_FRAM_LIST 20
frame_list_t frame_list_tbl[MAX_FRAM_LIST];
UINT32 n_frame_list = 0;

BOOL QCIDMAPrepareFormat(format_t* format)
{
    frame_list_t *list = find_frame_list(format);

    if (list)
        return TRUE;
    
    memset(&frame_list_tbl[n_frame_list], 0, sizeof(frame_list_t));

    memcpy(&frame_list_tbl[n_frame_list].format, format, sizeof(*format));

    alloc_frame_list(&frame_list_tbl[n_frame_list]);
    if (frame_list_tbl[n_frame_list].head != NULL)
    {
        if (!video_frame_tail && !format->is_still)
            video_frame_tail = frame_list_tbl[n_frame_list].tail;

        n_frame_list++;
        return TRUE;
    }

    memset(&frame_list_tbl[n_frame_list], 0, sizeof(frame_list_t));
    return FALSE;
}

static frame_list_t* find_frame_list(format_t* format)
{
    UINT32 i;

    for (i = 0; i < n_frame_list; i++)
    {
        frame_list_t* list = &frame_list_tbl[i];

        if (!list->head)
            continue;

        if (memcmp(&list->format, format, sizeof(format_t)) == 0)
            return list;
    }

    return NULL;
}

BOOL QCIDMASetFrameFormat(format_t* format)
{
    current_frame_list = find_frame_list(format);    
    return current_frame_list != NULL;
}
void DMALoad()

{
    int i;
    frame_t* f;

    if (!current_frame_list)
        return;

    if (!current_frame_list->head)
        return;

    for (f = current_frame_list->head; f; f = f->next)
    {
        frame_mark(f);
        frame_clean_cache(f);
    }

    for (i = 0; i < 3; i++)
        PXA_CIDMALoadDescriptor(g_pCIRegs,
                                current_frame_list->head->plane[i].desc_buf.phy_addr,
                                PXA_CI_DMA_CHANNEL_0 + i);
                                
}

#ifdef DEBUG

static void dump_dma_chain(plane_t *plane)
{
    UINT32 i;
    PXA_CI_DMAC_DESCRIPTOR_T *descs;
    UINT32 descs_n;

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

    for (i = 0; i < descs_n; i++)
    {
        DEBUGMSG(ZONE_IOCTL,(L"%d ddadr 0x%08x, dsadr 0x%08x, dtadr 0x%08x, dcmd 0x%08x\r\n",
            i, descs[i].ddadr, descs[i].dsadr, descs[i].dtadr, descs[i].dcmd));                
    }
}

static void dump_frame(frame_t *frame)
{
    int i;
    
    short *buf;
    DEBUGMSG(ZONE_IOCTL,(L"dumping frame 0x%08x\r\n",frame));
    

    if (!frame)
        return;

    for (i = 0; i < 3; i++)
    {
        DEBUGMSG(ZONE_IOCTL,(L"descriptor 0x%08x, phyiscal address 0x%08x\r\n",
            frame->plane[i].desc_buf.buf,
            frame->plane[i].desc_buf.phy_addr));        
        dump_dma_chain(&frame->plane[i]);
    }

    for (i = 0; i < 10; i++)        
        DEBUGMSG(ZONE_IOCTL,(L"0x%02x ",frame->plane[0].buf.buf[i]));
            
    DEBUGMSG(ZONE_IOCTL,(L"dumping frame mark\r\n"));
    buf = (short*)get_mark_ptr(frame);

    for (i = 0; i < 4; i++)
        DEBUGMSG(ZONE_IOCTL,(L"0x%04x \r\n",buf[i]));
        
}

void dump_frame_list(frame_list_t *frame_list)
{
    frame_t *i;
    DEBUGMSG(ZONE_IOCTL,(L"format %d\r\n", frame_list->format.format));
    DEBUGMSG(ZONE_IOCTL,(L"width %d\r\n", frame_list->format.width));
    DEBUGMSG(ZONE_IOCTL,(L"height %d\r\n", frame_list->format.height));
    DEBUGMSG(ZONE_IOCTL,(L"head 0x%08x\r\n", frame_list->head));
    DEBUGMSG(ZONE_IOCTL,(L"tail 0x%08x\r\n", frame_list->tail));
    
    for (i = frame_list->head; i; i = i->next)
        dump_frame(i);
}

#endif

int still_skips;

DWORD WINAPI QciIntrThread()
{
    int prio = 0;
#define MAX_READY_FRAME 10
    frame_t *frames[MAX_READY_FRAME];
    int n = 0;
    int i;

    prio = CeGetThreadPriority(GetCurrentThread());

    while(1) 
    {
        int status;
        //void qci_dump_regs();
        format_t* format;

        status = WaitForSingleObject(qci_intr_event, INFINITE);
        DEBUGMSG( ZONE_IOCTL, ( _T("CAM: Receive a complete frame!\r\n")));
        if (status == WAIT_FAILED)           
           DEBUGMSG( ZONE_IOCTL, ( _T("CAM: QciIntrThread: wait failed!\r\n")) );
        
        if (current_frame_list == NULL)
        {            
            DEBUGMSG( ZONE_IOCTL, ( _T("CAM: Error no DMA frames!!!\r\n")) );
            continue;
        }

        format = &current_frame_list->format;
        if (format->is_still)
        {
            if (still_skips)
            {
                DEBUGMSG( ZONE_IOCTL, ( _T("CAM: Still capture shoule skip %d frames!\r\n"),still_skips));
                still_skips--;
            } else
            {         
                DEBUGMSG( ZONE_IOCTL, ( _T("CAM: Receive a still frame!\r\n")));
                QciCallBack(current_frame_list->head);
            }
            PXA_CIClearInterruptStatus(g_pCIRegs, 0xFFFFFFFF);
            InterruptDone(qci_sys_intr);
            continue;
        }

        n = 0;
        while (1) 
        {
            frames[n] = frame_take();

            if (!frames[n])
                break;
            n++;
            if (n >= MAX_READY_FRAME)
                break;
        }

        for (i = 0; i < n; i++)
        {
            QciCallBack(frames[i]);
            frame_append(frames[i]);
        }
        
  
        PXA_CIClearInterruptStatus(g_pCIRegs, 0xFFFFFFFF);
        InterruptDone(qci_sys_intr);
    }


    return TRUE;
}

⌨️ 快捷键说明

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