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 + -
显示快捷键?