camera_core.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,174 行 · 第 1/3 页

C
1,174
字号
/*
 * drivers/media/video/omap/camera_core.c
 *
 * Video-for-Linux (Version 2) camera capture driver for
 * the OMAP H2 and H3 camera controller.
 *
 * auther:  
 * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com)
 *
 * Copyright (C) 2004 Texas Instruments.
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2. This program is licensed "as is" without any warranty of any
 * kind, whether express or implied.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/videodev.h>
#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <linux/dma-mapping.h>
#include <linux/fb.h>

#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/hardware/clock.h>
#include "camera_core.h"
#include "camera_sensor_if.h"
#include "omap_camera_if.h"

struct camera_device *camera_dev;
extern struct camera_sensor camera_sensor_if;
extern struct camera_interface omap_camera_if;

static void camera_core_sg_dma_process(struct camera_device *);
static int capture_abort= 0;

/* module parameters */
static int video_nr = -1;	/* video device minor (-1 ==> auto assign) */

/* Maximum amount of memory to use for capture buffers.
 * Default is 4800KB, enough to double-buffer SXGA.
 */
static int capture_mem = 1280*960*2*2;
/*Size of video overlay framebuffer. This determines the maximum image size
 *that can be previewed. Default is 600KB, enough for sxga.
 */
static int overlay_mem = 640*480*2;

int omap_dma_start_linked (struct camera_device *, struct sgdma_state *, void *);

/* DMA completion routine for the scatter-gather DMA fragments. */
/* This function is called when a scatter DMA fragment is completed */
int
camera_core_callback_sg_dma(struct camera_device *cam, void * arg)
{
        struct sgdma_state *sgdma;

	int sgslot = (int) arg;
        spin_lock(&cam->sg_lock);
	sgdma = cam->sgdma + sgslot;
	if(! sgdma->queued_sglist)
	{
		spin_unlock(&cam->sg_lock);
		printk(" ERROR!!!   SGDMA COMPLETED WHEN NONE QUEUED \n");
		return -EINVAL;
	}
	if(!--sgdma->queued_sglist) {
		/* queue for this sglist is empty so check whether transfer
		** of the frame has been completed */
		if(sgdma->next_sglist == sgdma->sglen) {
			dma_callback_t callback = sgdma->callback;
			void *arg = sgdma->arg;
			/* all done with this sglist */
			cam->free_sgdma++;
			if (callback) {
				spin_unlock(&cam->sg_lock);
				(*callback)(cam, arg);
				camera_core_sg_dma_process(cam);
				return 0;
			}

		}
	}
	spin_unlock(&cam->sg_lock);
	camera_core_sg_dma_process(cam);
	return 0;
	

}

/* Initialize the camera DMA driver. */
static void
camera_core_dma_init(struct camera_device *cam)
{
        int sg, ch;

        spin_lock_init(&cam->sg_lock);
	spin_lock_init(&cam->dma_lock);
	cam->free_dmach = 2;
	/* we don't know the next channel number here */
	/* cam->next_dmach = 0;*/
        cam->free_sgdma = NUM_SG_DMA;
        cam->next_sgdma = 0;
        for (sg = 0; sg < NUM_SG_DMA; sg++) {
                cam->sgdma[sg].sglen = 0;
                cam->sgdma[sg].next_sglist = 0;
                cam->sgdma[sg].queued_sglist = 0;
                cam->sgdma[sg].csr = 0;
                cam->sgdma[sg].callback = NULL;
                cam->sgdma[sg].arg = NULL;
        }
	for ( ch = 0; ch < 2; ++ch) {
		cam->camdma[ch].callback = NULL;
		cam->camdma[ch].arg = NULL;
	}
	
}

/*
 * Process the scatter-gather DMA queue by starting queued transfers
 * This function is called to program the dma to start the transfer of an image.
 */
static void
camera_core_sg_dma_process(struct camera_device *cam)
{
        unsigned long irqflags;
        int queued_sgdma, sgslot;
        struct sgdma_state *sgdma;
        const struct scatterlist *sglist;
	
        spin_lock_irqsave(&cam->sg_lock, irqflags);

        queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
        sgslot = (cam->next_sgdma + cam->free_sgdma)%34;
	while ( queued_sgdma >0 ) {
		sgdma = cam->sgdma + sgslot;
		while( sgdma->next_sglist < sgdma->sglen ) {
			sglist = sgdma->sglist + sgdma->next_sglist;
			if (omap_dma_start_linked(cam, sgdma, (void *) sgslot)){
				/* dma start failed */
				spin_unlock_irqrestore(&cam->sg_lock, irqflags);
				return;
			}
			else {
				/* dma start successful */
				sgdma->next_sglist ++;
				sgdma->queued_sglist ++;
			}
		}
		queued_sgdma-- ;
		sgslot=(sgslot+1)%34;	
	}

        spin_unlock_irqrestore(&cam->sg_lock, irqflags);
}

/* Queue a scatter-gather DMA transfer from the camera to memory.
 * Returns zero if the transfer was successfully queued, or
 * non-zero if all of the scatter-gather slots are already in use.
 */
static int
camera_core_sg_dma_queue(struct camera_device *cam,
        const struct scatterlist *sglist, int sglen, dma_callback_t callback,
        void *arg)
{
        unsigned long irqflags;
        struct sgdma_state *sgdma;
	int count1, count2;

	if ((sglen < 0)  || ((sglen > 0) & !sglist))
                return -EINVAL;

        spin_lock_irqsave(&cam->sg_lock, irqflags);

        if (!cam->free_sgdma) {
                spin_unlock_irqrestore(&cam->sg_lock, irqflags);
                return -EBUSY;
        }

        sgdma = cam->sgdma + cam->next_sgdma;
	sgdma->sglist = sglist;
        sgdma->sglen = sglen;
        sgdma->next_sglist = 0;
        sgdma->queued_sglist = 0;
        sgdma->csr = 0;
        sgdma->callback = callback;
        sgdma->arg = arg;

	count1 = (cam->next_sgdma + 1);
	count2 = count1%34;
        cam->next_sgdma = count2; 
        cam->free_sgdma--;

	spin_unlock_irqrestore(&cam->sg_lock, irqflags);

	camera_core_sg_dma_process(cam);

        return 0;
}


/* -------------------overlay routines ------------------------------*/
/* callback routine for overlay DMA completion. We just start another DMA
 * transfer unless overlay has been turned off
 */

static void
camera_core_overlay_callback(struct camera_device *cam, void *arg)
{
	int err;
	unsigned long irqflags;
        int i, j;
	int count, index;
        unsigned char *fb_buf = phys_to_virt ((unsigned long)camera_dev->fbuf.base);
	spin_lock_irqsave(&cam->overlay_lock, irqflags);
	if(!cam->previewing) {
		spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
		return;
	}


	count = 0;
	j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline);

	for (i = 0 ; i < cam->pix.sizeimage; i+= cam->pix.bytesperline) {
		for (index = 0; index <  cam->pix.bytesperline; index ++) {
			fb_buf[j] = *(((unsigned char *) cam->overlay_base) +
								 i + index);
			index ++;
			fb_buf[j + 1] = *(((unsigned char *) cam->overlay_base) + i + index);
			j = j - cam->fbuf.fmt.bytesperline;
		}
		count += 2;
		j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline) + count;
	}

	if (cam->overlay_cnt > 0)
		--cam->overlay_cnt;
	sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
	sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
	while (cam->overlay_cnt < 2) {
		err = camera_core_sg_dma_queue(cam, &cam->overlay_sglist, 1,
			camera_core_overlay_callback, NULL);
		if (err)
			break;
		++cam->overlay_cnt;
	}

	spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
}

 
static void
camera_core_start_overlay_dma(struct camera_device *cam)
{
	int err;
	unsigned long irqflags;

	if (!cam->previewing) 
		return;

	spin_lock_irqsave(&cam->overlay_lock, irqflags);
	sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
	sg_dma_len(&cam->overlay_sglist)= cam->pix.sizeimage;
	while(cam->overlay_cnt < 2){
		err = camera_core_sg_dma_queue(cam, &cam->overlay_sglist, 1,
				camera_core_overlay_callback, NULL);
		if (err)
			break;
		++cam->overlay_cnt;
	}
	spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
	
}

/* ------------------ videobuf_queue_ops ---------------------------------------- */

/* This routine is called from interrupt context when a scatter-gather DMA
 * transfer of a videobuf_buffer completes.
 */
static void
camera_core_vbq_complete(struct camera_device *cam, void *arg)
{
        struct videobuf_buffer *vb = (struct videobuf_buffer *) arg;

        spin_lock(&cam->vbq_lock);

        do_gettimeofday(&vb->ts);
        vb->field_count = cam->field_count;
        cam->field_count += 2;

        vb->state = STATE_DONE;

        wake_up(&vb->done);
        spin_unlock(&cam->vbq_lock);
}

static void
camera_core_vbq_release(struct file *file, struct videobuf_buffer *vb)
{
        videobuf_waiton(vb, 0, 0);
        videobuf_dma_pci_unmap(NULL, &vb->dma);
        videobuf_dma_free(&vb->dma);

        vb->state = STATE_NEEDS_INIT;
}

/* Limit the number of available kernel image capture buffers based on the
 * number requested, the currently selected image size, and the maximum
 * amount of memory permitted for kernel capture buffers.
 */
static int
camera_core_vbq_setup(struct file *file, unsigned int *cnt, unsigned int *size)
{
        struct camera_fh *fh = file->private_data;
        struct camera_device *cam = fh->cam;

        if (*cnt <= 0)
                *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */

        if (*cnt > VIDEO_MAX_FRAME)
                *cnt = VIDEO_MAX_FRAME;

        spin_lock(&cam->img_lock);

        *size = cam->pix.sizeimage;

        spin_unlock(&cam->img_lock);

        while (*size * *cnt > capture_mem)
                (*cnt)--;

        return 0;
}

static int
camera_core_vbq_prepare(struct file *file, struct videobuf_buffer *vb,
        enum v4l2_field field)
{
        struct camera_fh *fh = file->private_data;
        struct camera_device *cam = fh->cam;
        int err = 0;

        spin_lock(&cam->img_lock);

        if (cam->pix.sizeimage > vb->bsize) {
                spin_unlock(&cam->img_lock);
                return -EINVAL;
        }

        vb->size = cam->pix.sizeimage; 
        vb->width = cam->pix.width;
        vb->height = cam->pix.height;
        vb->field = field;

        spin_unlock(&cam->img_lock);

        if (vb->state == STATE_NEEDS_INIT)
                err = videobuf_iolock(NULL, vb, NULL);

        if (!err)
                vb->state = STATE_PREPARED;
        else
                camera_core_vbq_release (file, vb);

        return err;
}

static void
camera_core_vbq_queue(struct file *file, struct videobuf_buffer *vb)
{
        struct camera_fh *fh = file->private_data;
        struct camera_device *cam = fh->cam;
        enum videobuf_state state = vb->state;
        int err;

⌨️ 快捷键说明

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