camera_core.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,206 行 · 第 1/2 页
C
1,206 行
/* * drivers/media/video/omap/camera_core.c * * Copyright (C) 2004 Texas Instruments, Inc. * * Video-for-Linux (Version 2) camera capture driver for * the OMAP H2 and H3 camera controller. * * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com) * Copyright (C) 2003-2004 MontaVista Software, Inc. * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #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 "sensor_if.h"#include "camera_hw_if.h"#include "camera_core.h" struct camera_device *camera_dev;extern struct camera_sensor camera_sensor_if;extern struct camera_hardware camera_hardware_if; static void camera_core_sgdma_process(struct camera_device *cam);/* 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; /* DMA completion routine for the scatter-gather DMA fragments. *//* This function is called when a scatter DMA fragment is completed */static voidcamera_core_callback_sgdma(void *arg1, void *arg2){ struct camera_device *cam = (struct camera_device *)arg1; int sgslot = (int)arg2; struct sgdma_state *sgdma; spin_lock(&cam->sg_lock); sgdma = cam->sgdma + sgslot; if (!sgdma->queued_sglist) { spin_unlock(&cam->sg_lock); printk(KERN_ERR CAM_NAME ": SGDMA completed when none queued\n"); return; } 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_sgdma_process(cam); return; } } } spin_unlock(&cam->sg_lock); camera_core_sgdma_process(cam); return;}static voidcamera_core_sgdma_init(struct camera_device *cam){ int sg; /* Initialize the underlying camera DMA */ cam->cam_hardware->init_dma(cam->hardware_data); spin_lock_init(&cam->sg_lock); 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; }}/* * 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 voidcamera_core_sgdma_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) % (NUM_SG_DMA); while (queued_sgdma > 0) { sgdma = cam->sgdma + sgslot; while (sgdma->next_sglist < sgdma->sglen) { sglist = sgdma->sglist + sgdma->next_sglist; if (cam->cam_hardware->start_dma(sgdma, camera_core_callback_sgdma, (void *)cam, (void *)sgslot, cam->hardware_data)) { /* 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) % (NUM_SG_DMA); } 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 intcamera_core_sgdma_queue(struct camera_device *cam, const struct scatterlist *sglist, int sglen, dma_callback_t callback, void *arg){ unsigned long irqflags; struct sgdma_state *sgdma; 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; cam->next_sgdma = (cam->next_sgdma + 1) % (NUM_SG_DMA); cam->free_sgdma--; spin_unlock_irqrestore(&cam->sg_lock, irqflags); camera_core_sgdma_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 voidcamera_core_overlay_callback(void *arg1, void *arg){ struct camera_device *cam = (struct camera_device *)arg1; 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 || cam->overlay_cnt == 0) { spin_unlock_irqrestore(&cam->overlay_lock, irqflags); return; } --cam->overlay_cnt; sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys; sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage; 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; } while (cam->overlay_cnt < 2) { err = camera_core_sgdma_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 voidcamera_core_start_overlay(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_sgdma_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 voidcamera_core_vbq_complete(void *arg1, void *arg){ struct camera_device *cam = (struct camera_device *)arg1; 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 voidcamera_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 intcamera_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 intcamera_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 voidcamera_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; vb->state = STATE_QUEUED; err = camera_core_sgdma_queue(cam, vb->dma.sglist, vb->dma.sglen, camera_core_vbq_complete, vb); if (err) { /* Oops. We're not supposed to get any errors here. The only * way we could get an error is if we ran out of scatter-gather * DMA slots, but we are supposed to have at least as many * scatter-gather DMA slots as video buffers so that can't * happen. */ printk(KERN_DEBUG CAM_NAME ": Failed to queue a video buffer for SGDMA\n"); vb->state = state; }}/* ------------------ videobuf_queue_ops ---------------------------------------- */static intcamera_core_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct camera_fh *fh = file->private_data; struct camera_device *cam = fh->cam; int err; switch (cmd) { case VIDIOC_ENUMINPUT: { /* default handler assumes 1 video input (the camera) */ struct v4l2_input *input = (struct v4l2_input *)arg; int index = input->index; memset(input, 0, sizeof(*input)); input->index = index; if (index > 0) return -EINVAL; strlcpy(input->name, "camera", sizeof(input->name)); input->type = V4L2_INPUT_TYPE_CAMERA; return 0; } case VIDIOC_G_INPUT: { unsigned int *input = arg; *input = 0; return 0; } case VIDIOC_S_INPUT: { unsigned int *input = arg; if (*input > 0) return -EINVAL; return 0; } case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *fmt = arg; return cam->cam_sensor->enum_pixformat(fmt, cam->sensor_data); } case VIDIOC_TRY_FMT: { struct v4l2_format *fmt = arg; return cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data); } case VIDIOC_G_FMT: { struct v4l2_format *fmt = arg; /* get the current format */ memset(&fmt->fmt.pix, 0, sizeof (fmt->fmt.pix)); fmt->fmt.pix = cam->pix; return 0; } case VIDIOC_S_FMT: { struct v4l2_format *fmt = arg; unsigned int temp_sizeimage = 0; temp_sizeimage = cam->pix.sizeimage; cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data); cam->pix = fmt->fmt.pix; cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix, &cam->nominal_timeperframe, cam->sensor_data); cam->cparm.timeperframe = cam->nominal_timeperframe; cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data); return cam->cam_sensor->configure(&cam->pix, cam->xclk, &cam->cparm.timeperframe, cam->sensor_data); } case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; return cam->cam_sensor->query_control(qc, cam->sensor_data); } case VIDIOC_G_CTRL: { struct v4l2_control *vc = arg; return cam->cam_sensor->get_control(vc, cam->sensor_data); } case VIDIOC_S_CTRL: { struct v4l2_control *vc = arg; return cam->cam_sensor->set_control(vc, cam->sensor_data); } case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = (struct v4l2_capability *) arg; memset(cap, 0, sizeof(*cap)); strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver)); strlcpy(cap->card, cam->vfd->name, sizeof(cap->card)); cap->bus_info[0] = '\0'; cap->version = KERNEL_VERSION(0, 0, 0); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; return 0; } case VIDIOC_G_FBUF: /* Get the frame buffer parameters */ { struct v4l2_framebuffer *fbuf = (struct v4l2_framebuffer *) arg; spin_lock(&cam->img_lock); *fbuf = cam->fbuf; spin_unlock(&cam->img_lock); return 0; } case VIDIOC_S_FBUF: /* set the frame buffer parameters */ { struct v4l2_framebuffer *fbuf = (struct v4l2_framebuffer *) arg; spin_lock(&cam->img_lock); if (cam->previewing) { spin_unlock(&cam->img_lock); return -EBUSY; } cam->fbuf.base = fbuf->base; cam->fbuf.fmt = fbuf->fmt; spin_unlock(&cam->img_lock); return 0; } case VIDIOC_OVERLAY: { int enable = *((int *) arg); /* * check whether the capture format and ** the display format matches * return failure if they are different */ if (cam->pix.pixelformat != cam->fbuf.fmt.pixelformat) { return -EINVAL; } /* If the camera image size is greater ** than LCD size return failure */ if ((cam->pix.width > cam->fbuf.fmt.height) || (cam->pix.height > cam->fbuf.fmt.width)) { return -EINVAL; } if (!cam->previewing && enable) { cam->previewing = fh; cam->overlay_cnt = 0; camera_core_start_overlay(cam); } else if (!enable) { cam->previewing = NULL; } return 0; } case VIDIOC_REQBUFS: return videobuf_reqbufs(file, &fh->vbq, arg); case VIDIOC_QUERYBUF: return videobuf_querybuf(&fh->vbq, arg); case VIDIOC_QBUF: return videobuf_qbuf(file, &fh->vbq, arg); case VIDIOC_DQBUF: return videobuf_dqbuf(file, &fh->vbq, arg); case VIDIOC_STREAMON:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?