📄 dma.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 = ¤t_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 + -