omap24xxvout.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,498 行 · 第 1/5 页
C
2,498 行
/* * drivers/media/video/omap24xx/omap24xxvout.c * * Copyright (C) 2005-2006 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. * * Leveraged code from the OMAP2 camera driver * Video-for-Linux (Version 2) camera capture driver for * the OMAP24xx camera controller. * * Author: Andy Lowe (source@mvista.com) * * Copyright (C) 2004 MontaVista Software, Inc. * Copyright (C) 2004 Texas Instruments. * * History: * 20-APR-2006 Khasim Modified VRFB based Rotation, * The image data is always read from 0 degree * view and written * to the virtual space of desired rotation angle * 4-DEC-2006 Jian Changed to support better memory management * */#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kdev_t.h>#include <linux/types.h>#include <linux/wait.h>#include <linux/videodev.h>#include <linux/pci.h>#include <linux/platform_device.h>#include <media/videobuf-dma-sg.h>#include <linux/input.h>#include <linux/dma-mapping.h>#include <media/v4l2-dev.h> #include <linux/notifier.h>#include <linux/pm.h>#include <asm/arch/display.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/semaphore.h>#include <asm/processor.h>#include <asm/arch/dma.h>#include "omap24xxlib.h"/* * Un-comment this to use Debug Write call *//* #define DEBUG_ALLOW_WRITE */#include "omap24xxvoutdef.h"unsigned long timeout;/* * Uncomment this if debugging support needs to be enabled *//* #define DEBUG */#undef DEBUG#define DPRINTK( x... )/* * -1 means rotation support is disabled * 0/90/180/270 are initial rotation angles */static int rotation_support = -1;/* configuration macros */#define VOUT_NAME "omap24xxvout"#define V1OUT_NAME "omap24xxvout1"#define V2OUT_NAME "omap24xxvout2"#define D1_PAL_WIDTH 720#define D1_PAL_HEIGHT 576#define D1_NTSC_WIDTH 720#define D1_NTSC_HEIGHT 486#define D1_PAL_VSTAT_WIDTH 832#define D1_PAL_VSTAT_HEIGHT 672#define D1_NTSC_VSTAT_WIDTH 832#define D1_NTSC_VSTAT_HEIGHT 560#define WVGA_WIDTH 854#define WVGA_HEIGHT 480#define VGA_WIDTH 640#define VGA_HEIGHT 480#define QQVGA_WIDTH 160#define QQVGA_HEIGHT 120#define BYTESPERPIXEL 2#define DMA_CHAN_ALLOTED 1#define DMA_CHAN_NOT_ALLOTED 0#define NUM_OF_VIDEO_CHANNELS 2#define VRF_SIZE MAX_PIXELS_PER_LINE * MAX_LINES * 4#define SMS_RGB_PIXSIZE 2#define SMS_YUYV_PIXSIZE 4#define VRFB_TX_TIMEOUT 1000#define VID_MAX_WIDTH D1_PAL_WIDTH /* Largest width */#define VID_MAX_HEIGHT D1_PAL_HEIGHT /* Largest height */#define OMAP35XVOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)#define OMAP35XVOUT_VIDEO1_SMS_START (0xE0000000)#define OMAP35XVOUT_VIDEO2_SMS_START (0xF0000000)static struct omap24xxvout_device *saved_v1out, *saved_v2out;#define STREAMING_IS_ON() ((saved_v1out && saved_v1out->streaming) || \ (saved_v2out && saved_v2out->streaming))/* * this is the layer being linked to (slave layer). possible values are: * OMAP2_VIDEO1: V1 is linked to V2. V1 uses V2's pix and crop. * OMAP2_VIDEO2: V2 is linked to V1. V2 uses V1's pix and crop. * -1: no link. */static int vout_linked;static spinlock_t vout_link_lock;static struct videobuf_queue_ops video_vbq_ops;static u32 video1_numbuffers = 3;static u32 video2_numbuffers = 3;static u32 video1_bufsize = OMAP35XVOUT_MAX_BUF_SIZE;static u32 video2_bufsize = OMAP35XVOUT_MAX_BUF_SIZE;module_param(video1_numbuffers, uint, S_IRUGO);module_param(video2_numbuffers, uint, S_IRUGO);module_param(video1_bufsize, uint, S_IRUGO);module_param(video2_bufsize, uint, S_IRUGO);/* module parameters *//* * Maximum amount of memory to use for rendering buffers. * Default is enough to four (RGB24) VGA buffers. */#define MAX_ALLOWED_VIDBUFFERS 4/*static int render_mem = VID_MAX_WIDTH * VID_MAX_HEIGHT * 4 * MAX_ALLOWED_VIDBUFFERS;*/static struct tvlcd_status_t tvlcd_status;/* list of image formats supported by OMAP2 video pipelines */const static struct v4l2_fmtdesc omap2_formats[] = { { /* Note: V4L2 defines RGB565 as: * * Byte 0 Byte 1 * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 * * We interpret RGB565 as: * * Byte 0 Byte 1 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 */ .description = "RGB565, le", .pixelformat = V4L2_PIX_FMT_RGB565, }, { /* Note: V4L2 defines RGB565X as: * * Byte 0 Byte 1 * b4 b3 b2 b1 b0 g5 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0 * * We interpret RGB565X as: * * Byte 0 Byte 1 * r4 r3 r2 r1 r0 g5 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0 */ .description = "RGB565, be", .pixelformat = V4L2_PIX_FMT_RGB565X, }, { /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use * this for RGB24 unpack mode, the last 8 bits are ignored * */ .description = "RGB32, le", .pixelformat = V4L2_PIX_FMT_RGB32, }, { /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use * this for RGB24 packed mode * */ .description = "RGB24, le", .pixelformat = V4L2_PIX_FMT_RGB24, }, { .description = "YUYV (YUV 4:2:2), packed", .pixelformat = V4L2_PIX_FMT_YUYV, }, { .description = "UYVY, packed", .pixelformat = V4L2_PIX_FMT_UYVY, },};#define NUM_OUTPUT_FORMATS (sizeof(omap2_formats)/sizeof(omap2_formats[0]))/* CONFIG_PM */#define omap24xxvout_suspend_lockout(s,f) \ if ((s)->suspended) {\ if ((f)->f_flags & O_NONBLOCK)\ return -EBUSY;\ wait_event_interruptible((s)->suspend_wq,\ (s)->suspended == 0);\ }static inline unsigned long omap35xvout_alloc_buffer(u32 buf_size, u32 *phys_addr){ return (unsigned long)dma_alloc_coherent(NULL, buf_size, (dma_addr_t *)phys_addr, GFP_KERNEL | GFP_DMA);}static void omap35xvout_free_buffer(unsigned long virtaddr, u32 phys_addr, u32 buf_size){ dma_free_coherent(NULL, buf_size, (void *)virtaddr, phys_addr);}static int try_format (struct v4l2_pix_format *pix){ int ifmt,bpp =0; if (pix->width > VID_MAX_WIDTH) pix->width = VID_MAX_WIDTH; if (pix->height > VID_MAX_HEIGHT) pix->height = VID_MAX_HEIGHT; for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++){ if (pix->pixelformat == omap2_formats[ifmt].pixelformat) break; } if (ifmt == NUM_OUTPUT_FORMATS) ifmt = 0; pix->pixelformat = omap2_formats[ifmt].pixelformat; pix->field = /*V4L2_FIELD_NONE*/V4L2_FIELD_ANY; pix->priv = 0; switch (pix->pixelformat){ case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: default: pix->colorspace = V4L2_COLORSPACE_JPEG; bpp = YUYV_BPP; break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: pix->colorspace = V4L2_COLORSPACE_SRGB; bpp = RGB565_BPP; break; case V4L2_PIX_FMT_RGB24: pix->colorspace = V4L2_COLORSPACE_SRGB; bpp = RGB24_BPP; break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: pix->colorspace = V4L2_COLORSPACE_SRGB; bpp = RGB32_BPP; break; } pix->bytesperline = pix->width * bpp; pix->sizeimage = pix->bytesperline * pix->height; return(bpp);}/* * omap24xxvout_uservirt_to_phys: This inline function is used to convert user * space virtual address to physical address. */static inline u32 omap35x_uservirt_to_phys(u32 virtp){ unsigned long physp = 0; struct mm_struct *mm = current->mm; struct vm_area_struct *vma; /* For kernel direct-mapped memory, take the easy way */ if (virtp >= PAGE_OFFSET) { physp = virt_to_phys((void *)virtp); } else if ((vma = find_vma(mm, virtp)) && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { /* this will catch, kernel-allocated, mmaped-to-usermode addresses */ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); } else { /* otherwise, use get_user_pages() for general userland pages */ int res, nr_pages = 1; struct page *pages; down_read(¤t->mm->mmap_sem); res = get_user_pages(current, current->mm, virtp, nr_pages, 1, 0, &pages, NULL); up_read(¤t->mm->mmap_sem); if (res == nr_pages) { physp = __pa(page_address(&pages[0]) + (virtp & ~PAGE_MASK)); } else { printk("omap24xxvout_uservirt_to_phys:\ get_user_pages failed\n"); return 0; } } return physp;}static void vrfb_dma_tx_callback (int lch, u16 ch_status, void *data){ struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data; t->tx_status = 1; wake_up_interruptible (&t->wait);}static void omap24xxvout_sync (struct omap24xxvout_device *dest, struct omap24xxvout_device *src){ int rotation = -1; if(dest->rotation > 0) rotation = dest->rotation; /* * once linked, dest shares src's framebuffer, pix and crop */ dest->pix = src->pix; dest->crop = src->crop; if (src->streaming) omap2_disp_config_vlayer (dest->vid, &dest->pix, &dest->crop, &dest->win, rotation, dest->mirror);}/* Buffer setup function is called by videobuf layer when REQBUF ioctl is * called. This is used to setup buffers and return size and count of * buffers allocated. After the call to this buffer, videobuf layer will * setup buffer queue depending on the size and count of buffers */static int omap35x_buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){ struct omap24xxvout_fh *fh = (struct omap24xxvout_fh *)q->priv_data; struct omap24xxvout_device *vout = fh->vout; int startindex = 0, i, j; u32 phy_addr, virt_addr; if(!vout) { return -EINVAL; } if(V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) return -EINVAL; if(vout->rotation != -1 && *count > 4) *count = 4; /* If rotation is enabled, allocate memory for VRFB space also */ if(vout->rotation > 0) { for(i = 0; i < *count ; i ++) { if (!vout->smsshado_virt_addr[i]) { vout->smsshado_virt_addr[i] = omap35xvout_alloc_buffer( vout->smsshado_size, &vout->smsshado_phy_addr[i]); } if (!vout->smsshado_virt_addr[i]) { for(j = 0 ; j < i ; j ++) { omap35xvout_free_buffer( vout->smsshado_virt_addr[j], vout->smsshado_phy_addr[j], vout->smsshado_size); vout->smsshado_virt_addr[j]=0; vout->smsshado_phy_addr[j]=0; } for(j = startindex ; j < *count ; j ++) { omap35xvout_free_buffer( vout->buf_virt_addr[j], vout->buf_phy_addr[j], vout->buffer_size); vout->buf_virt_addr[j]=0; vout->buf_phy_addr[j]=0; } return -ENOMEM; } memset((void *) vout->smsshado_virt_addr[i], 0, vout->smsshado_size); if(vout->rotation == 90 || vout->rotation == 270) { omap2_disp_set_vrfb (vout->vrfb_context[i], vout->smsshado_phy_addr[i], vout->pix.height, vout->pix.width, vout->bpp * vout->vrfb_bpp); } else { omap2_disp_set_vrfb (vout->vrfb_context[i], vout->smsshado_phy_addr[i], vout->pix.width, vout->pix.height, vout->bpp * vout->vrfb_bpp); } } } if(V4L2_MEMORY_MMAP != vout->memory) return 0; *size = vout->buffer_size; startindex = (vout->vid == OMAP2_VIDEO1) ? video1_numbuffers : video2_numbuffers; for(i = startindex ; i < *count ; i ++) { vout->buffer_size = *size; virt_addr = omap35xvout_alloc_buffer(vout->buffer_size, &phy_addr); if(!virt_addr) break; vout->buf_virt_addr[i] = virt_addr; vout->buf_phy_addr[i] = phy_addr; } *count = vout->buffer_allocated = i; return 0;}/* This function will be called when VIDIOC_QBUF ioctl is called. * It prepare buffers before give out for the display. This function * user space virtual address into physical address if userptr memory * exchange mechanism is used. If rotation is enabled, it copies entire * buffer into VRFB memory space before giving it to the DSS. */static int omap35x_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field){ struct omap24xxvout_fh *fh = (struct omap24xxvout_fh *)q->priv_data; struct omap24xxvout_device *vout = fh->vout; u32 dest_frame_index = 0, src_element_index = 0; u32 dest_element_index = 0, src_frame_index = 0; u32 elem_count = 0, frame_count = 0, pixsize = 2,mir_rot_deg = 0; struct videobuf_dmabuf *dmabuf=NULL; if (VIDEOBUF_NEEDS_INIT == vb->state) { vb->width = vout->pix.width; vb->height = vout->pix.height; vb->size = vb->width * vb->height * vout->bpp; vb->field = field; } vb->state = VIDEOBUF_PREPARED; /* if user pointer memory mechanism is used, get the physical * address of the buffer */ if (V4L2_MEMORY_USERPTR == vb->memory) { if (0 == vb->baddr) { return -EINVAL; } /* Virtual address */ /* priv points to struct videobuf_pci_sg_memory. But we went * pointer to videobuf_dmabuf, which is member of * videobuf_pci_sg_memory */ dmabuf = videobuf_to_dma(q->bufs[vb->i]); dmabuf->vmalloc = (void*)vb->baddr; /* Physical address */ dmabuf->bus_addr = (dma_addr_t)omap35x_uservirt_to_phys( vb->baddr); } if (vout->rotation > 0) { dmabuf = videobuf_to_dma(q->bufs[vb->i]); /* If rotation is enabled, copy input buffer into VRFB * memory space using DMA. We are copying input buffer * into VRFB memory space of desired angle and DSS will * read image VRFB memory for 0 degree angle */ pixsize = vout->bpp * vout->vrfb_bpp; /* * DMA transfer in double index mode */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?