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(&current->mm->mmap_sem);		res = get_user_pages(current, current->mm,				virtp, nr_pages, 1, 0, &pages, NULL);		up_read(&current->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 + -
显示快捷键?