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

📄 pxa27x_camera.c

📁 该BSP是基于PXA270+WINCE的BSP
💻 C
📖 第 1 页 / 共 5 页
字号:
            VirtAddr_Last_Pn_CH0 = pDescriptorInfo->pVirtAddr_XPn_CH0;
            VirtAddr_Last_Pn_CH1 = pDescriptorInfo->pVirtAddr_XPn_CH1;
            VirtAddr_Last_Pn_CH2 = pDescriptorInfo->pVirtAddr_XPn_CH2;

            VirtAddr_Last_n_CH0 = pDescriptorInfo->pVirtAddr_Xn_CH0;
            VirtAddr_Last_n_CH1 = pDescriptorInfo->pVirtAddr_Xn_CH1;
            VirtAddr_Last_n_CH2 = pDescriptorInfo->pVirtAddr_Xn_CH2;

        } else if (BufferType == STILL_CAPTURE_BUFFER)
        {
            if (bFirstStillBufferSubmitted == FALSE)
            {
                StillCaptureDescriptorPhysicalStartAddress_CH0 = pDescriptorInfo->pPhysAddr_X1_CH0;
                StillCaptureDescriptorPhysicalStartAddress_CH1 = pDescriptorInfo->pPhysAddr_X1_CH1;
                StillCaptureDescriptorPhysicalStartAddress_CH2 = pDescriptorInfo->pPhysAddr_X1_CH2;
                bFirstStillBufferSubmitted = TRUE;

                pXPn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH0;
                pXPn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH1;
                pXPn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH2;

                pXn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH0;
                pXn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH1;
                pXn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH2;

                // Chain last phantom descriptor XPn to the first phantom descriptor XP1.
                //  This loops the phantom descriptor back to itself.
                pXPn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
                if (isYUV_PLANAR) pXPn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
                if (isYUV_PLANAR) pXPn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;

                // Chain the last real descriptor to the start of the phantom descriptor chain
                pXn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
                if (isYUV_PLANAR) pXn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
                if (isYUV_PLANAR) pXn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;
            }
        }
    } else 
    {
        if (!pBufInfo)
            NKDbgPrintfW(TEXT("Buffer is null.  Submit buffer failed.\r\n"));
        else
            NKDbgPrintfW(TEXT("Buffer list had null entry.  Submit buffer failed.  Buffer ID %d\r\n"),pBufInfo->BufferID);
    }
}

// Given a buffer allocated by the application, this function maps the buffer into discreet 4K chunks in the physical
// address space, then builds a DMA descriptor chain that performs a scatter gather DMA sequence using these 
// 4K chunks as individual target buffers.  It also builds a phantom descriptor chain which is executed after
// the primary descriptor chain completes.  The phantom descriptor chain is created so that the DMA can run
// continuously in the background, even if there is no client ready to read the data from the primary chain.  This 
// way primary buffers will remain untouched, the dma activity is undisturbed, the sensor is unaware of the flow control,
// and the primary buffers remain ready for their consumption by the application that submitted them.
// Buffers are chained together based on the order in which they are submitted by the application.  In this way,
// the application can now manage the buffer memory according to its own needs.  If an application needs to lock
// down a buffer, it simply chooses not to resubmit that buffer until it has completed using it.
int CameraPrepareBuffer(P_CAMERA_DMA_BUFFER_INFO pBufInfo, int BufferType)
{
        int limit = 0;
        int i = 0;
        int j = 0;
        int num_descriptors;
        int memory_required;
        int planes_number;

        DESCRIPTOR_INFO_T *pDescriptorInfo;
        DWORD *pPhysicalBufferAddress;
        DWORD *pPhysicalDescriptorBufferAddress;
        DWORD *VirtAddr;

        int fifo0_num_descriptors = 0;
        int fifo1_num_descriptors = 0;
        int fifo2_num_descriptors = 0;

        int fifo0_transfer_size = 0;
        int fifo1_transfer_size = 0;
        int fifo2_transfer_size = 0;
        int frame_size = (VIDEO_CAPTURE_BUFFER == BufferType ? g_HwContext.XllpCAMERA.Video_capture_width : g_HwContext.XllpCAMERA.Still_capture_width) * \
                                         (VIDEO_CAPTURE_BUFFER == BufferType ? g_HwContext.XllpCAMERA.Video_capture_height : g_HwContext.XllpCAMERA.Still_capture_height) * 2;

        // Determine the length of the image transfer.  This is the sum of each fifo transfer length.
        switch(g_HwContext.XllpCAMERA.capture_output_format) 
        {
                case XLLP_CAMERA_IMAGE_FORMAT_RGB555:
                case XLLP_CAMERA_IMAGE_FORMAT_RGB565:
                        fifo0_transfer_size = frame_size;
                        planes_number = 1;
                        break;
                case XLLP_CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
                        fifo0_transfer_size = frame_size;
                        planes_number = 1;
                        break;
                case XLLP_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
                        fifo0_transfer_size = frame_size / 2;
                        fifo1_transfer_size = frame_size / 4;
                        fifo2_transfer_size = frame_size / 4;
                        planes_number = 3;
                        break;
                default:
                        NKDbgPrintfW(TEXT("Unsupported capture format.\r\n"));
                        return FALSE;
                        break;
        }

        // Allocate some memory to store the physical address of each descriptor used to map each 4K segment
        // We need one set of descriptors to DMA the data to a real buffer.  We need another set of descriptors
        // (phantom descriptors) to DMA the data to non-incrementing address that will be used only for flow control.
        // Therefore, twice as many descriptors are required for the whole chain, than for just the primary DMA sequence.
        // We can obtain physical addresses with 4K granularity.  And the pages are not guaranteed to be contiguous.  
        // Therefore, we'll dedicate one descriptor for every 4K of image data.

        fifo0_num_descriptors = (( fifo0_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                                 / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
        fifo1_num_descriptors = (( fifo1_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                                 / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
        fifo2_num_descriptors = (( fifo2_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                                 / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;

        num_descriptors = fifo0_num_descriptors + fifo1_num_descriptors + fifo2_num_descriptors;
        
        memory_required = ((num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX);
        
        if (pBufInfo->size < memory_required)
        {
                pBufInfo->size = memory_required;
                //NKDbgPrintfW(TEXT("Memory size inadequate.  Need %d bytes\r\n"),pBufInfo->size);
                return FALSE;
        }

        if (NumBuffers >= MAX_CAMERA_DMA_BUFFERS)
        {
                NKDbgPrintfW(TEXT("Max number of buffers reached.\r\n"));
                return FALSE;
        }

        MasterBufferList[NumBuffers] = (DESCRIPTOR_INFO_T *)malloc(sizeof(DESCRIPTOR_INFO_T));
        if (MasterBufferList[NumBuffers] == NULL)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for entry into MasterBufferList.\r\n"));
                return FALSE;
        }

        pDescriptorInfo = MasterBufferList[NumBuffers];
        memset(pDescriptorInfo, 0x0, sizeof(DESCRIPTOR_INFO_T));
        
        // Assign a unique frame ID
        pDescriptorInfo->FrameID = NumBuffers;
        pBufInfo->BufferID = NumBuffers;

        pDescriptorInfo->dwPlanesNumber = planes_number;


        VirtAddr = (DWORD *)MapCallerPtr((void *)pBufInfo->VirtAddr,  pBufInfo->size);
        if (VirtAddr == 0x0)
        {
                NKDbgPrintfW(TEXT("Unable to map application buffer 0x%x into driver's address space.\r\n"), pBufInfo->VirtAddr);
                return FALSE;
        }

        // Set the memory to uncached, unbuffered
        VirtualSetAttributes((void *)VirtAddr, memory_required, 0, 0xC, NULL);

        pBufInfo->pY = (DWORD *)pBufInfo->VirtAddr;
        pBufInfo->pCb = (DWORD *)pBufInfo->VirtAddr + (((fifo0_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4);
        pBufInfo->pCr = (DWORD *)pBufInfo->VirtAddr + (((fifo0_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4)
                                                    + (((fifo1_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4);

        // This list holds a pointer to each physical destination buffer
        pDescriptorInfo->pBufferPhyAddress = (DWORD *)malloc(num_descriptors * sizeof(DWORD));
        if (pDescriptorInfo->pBufferPhyAddress == NULL)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pBufferPhyAddress.\r\n"));
                return FALSE;
        }

        pDescriptorInfo->pBufferVirtAddress = VirtAddr;


        // Allocate memory for the descriptor buffer list, plus one dummy entry in order to simplify the buffer chaining logic
        // The last entry in the descriptor chain needs an entry for the DDADR register, and if we allocate an extra unused entry
        // in this list, we can assign the dummy value without any harm.
        pDescriptorInfo->pDescriptorBufferPhyAddress = (DWORD *)malloc((num_descriptors + 1) * sizeof(DWORD));
        if (!pDescriptorInfo->pDescriptorBufferPhyAddress)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pDescriptorBufferPhyAddress\r\n"));
                return FALSE;
        }


        pDescriptorInfo->pDescriptorBufferVirtAddress = (DWORD *)malloc((num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
        if (!pDescriptorInfo->pDescriptorBufferVirtAddress)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pDescriptorBufferVirtAddress\r\n"));
                return FALSE;
        }

        memset(pDescriptorInfo->pDescriptorBufferVirtAddress, 0x0, (num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));

        // Set the descriptor memory to uncached, unbuffered so that the descriptors have valid data in them when read by the DMA engine later.
        VirtualSetAttributes((void *)pDescriptorInfo->pDescriptorBufferVirtAddress, (num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T), 0, 0xC, NULL);

        // Create the lookup table that maps the user allocated virtual buffer address to the corresponding physical address.
        // We know that buffers are contiguous within each 4K segment.

        pPhysicalBufferAddress = pDescriptorInfo->pBufferPhyAddress;
        limit = (DWORD)VirtAddr + pBufInfo->size;
        // Now determine the physical addresses for each 4K segment and store them in the array maintained for this descriptor chain
        for (i = (DWORD)VirtAddr; i < limit; i+= SINGLE_DESCRIPTOR_TRANSFER_MAX)
        {
                getPhyAddress ((DWORD *)i, pPhysicalBufferAddress);
                //NKDbgPrintfW(TEXT("Target Buffer Virtual Address 0x%x has Physical address 0x%x\r\n"),i, *pPhysicalBufferAddress);
                pPhysicalBufferAddress++;
        }

        // Create the lookup table that maps the virtual address space that was just allocated for the descriptors to the corresponding physical address.
        pPhysicalDescriptorBufferAddress = pDescriptorInfo->pDescriptorBufferPhyAddress;        
        limit = (DWORD)(pDescriptorInfo->pDescriptorBufferVirtAddress) + ((num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
        // Now determine the physical addresses for each descriptor address and store them in the array maintained for this descriptor chain
        for (i = (DWORD)(pDescriptorInfo->pDescriptorBufferVirtAddress); i < limit; i+= sizeof(XLLP_DMA_DESCRIPTOR_T))
        {
                getPhyAddress ((DWORD *)i, pPhysicalDescriptorBufferAddress);
                //NKDbgPrintfW(TEXT("Descriptor Virtual Address 0x%x has Physical address 0x%x\r\n"),i, *pPhysicalDescriptorBufferAddress);
                pPhysicalDescriptorBufferAddress++;
        }

        // Make sure we align the buffer
        if (VirtAddr_Phantom_Buffer == 0x0)
        {
                VirtAddr_Phantom_Buffer_Base_Address = (DWORD)((DWORD *)malloc(SINGLE_DESCRIPTOR_TRANSFER_MAX + 0xFFF));
                if (VirtAddr_Phantom_Buffer_Base_Address == 0x0)
                {
                        NKDbgPrintfW(TEXT("Unable to allocate memory for VirtAddr_Phantom_Buffer\r\n"));
                        return FALSE;
                }

                VirtAddr_Phantom_Buffer = VirtAddr_Phantom_Buffer_Base_Address;

                if (VirtAddr_Phantom_Buffer & 0xFFF)
                {
                        VirtAddr_Phantom_Buffer += 0x1000 - (VirtAddr_Phantom_Buffer & 0xFFF);
                }

                getPhyAddress ((DWORD *)VirtAddr_Phantom_Buffer, &((DWORD)PhysAddr_Phantom_Buffer));
                //NKDbgPrintfW(TEXT("Phantom buffer Virtual Address 0x%x has Physical address 0x%x\r\n"),VirtAddr_Phantom_Buffer, PhysAddr_Phantom_Buffer);
        }

        pDescriptorInfo->pPhysAddr_Phantom = PhysAddr_Phantom_Buffer;

        GenerateDMAChain( pDescriptorInfo, fifo0_transfer_size, fifo1_transfer_size, fifo2_transfer_size);

        NumBuffers++;

//      return (int)pDescriptorInfo->FrameID;
        return TRUE;
}

// Generate a primary descriptor chain that fills the provided buffers.
// Generate a phantom descriptor chain that executes after the primary chain.
// When buffers are chained together, each primary chain is linked to the next primary
// descriptor chain.  The last primary descriptor chain is linked to the phantom descriptor chain.
int GenerateDMAChain(
    DESCRIPTOR_INFO_T *pDescriptorInfo,
    int fifo0_transfer_size,
    int fifo1_transfer_size,
    int fifo2_transfer_size
    )
{
    XLLP_DMAC_DESCRIPTOR_T *cur_des_virtual;
    int des_transfer_size, remain_size;
    unsigned int i,j,k,l;
    unsigned int fifo0_num_descriptors = 0;
    unsigned int fifo1_num_descriptors = 0;
    unsigned int fifo2_num_descriptors = 0;

    // calculate how many descriptors are needed per frame
    fifo0_num_descriptors = (( fifo0_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                            / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
    fifo1_num_descriptors = (( fifo1_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                            / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
    fifo2_num_descriptors = (( fifo2_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                            / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;

    cur_des_virtual = (XLLP_DMAC_DESCRIPTOR_T*)pDescriptorInfo->pDescriptorBufferVirtAddress;

    // First iteration, build the real chain.
    // Second iteration, build the phantom chain.
    k = 0;
    l = 0;
    for(i=0; i < 2; i++) {
    
        remain_size = fifo0_transfer_size;

        for(j=0; j < fifo0_num_descriptors >> 1; j++) {
            // set descriptor
            if (remain_size > SINGLE_DESCRIPTOR_TRANSFER_MAX) 
                des_transfer_size = SINGLE_DESCRIPTOR_TRANSFER_MAX;
            else
                des_transfer_size = remain_size;

            // Build the primary DMA chain
            if (i == 0)
            {
                    cur_des_virtual->DDADR = (unsigned)pDescriptorInfo->pDescriptorBufferPhyAddress[++l];
                    cur_des_virtual->DSADR = XLLP_CI_REGBASE_PHY + XLLP_CIBR0;                      // FIFO0 physical address

⌨️ 快捷键说明

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