⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cx88-video.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * device driver for Conexant 2388x based TV cards * video4linux video interface * * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/init.h>#include <linux/list.h>#include <linux/module.h>#include <linux/kmod.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <asm/div64.h>#include "cx88.h"#define V4L2_I2C_CLIENTS 1MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");MODULE_LICENSE("GPL");/* ------------------------------------------------------------------ */static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };MODULE_PARM(video_nr,"1-" __stringify(CX88_MAXBOARDS) "i");MODULE_PARM_DESC(video_nr,"video device numbers");static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };MODULE_PARM(vbi_nr,"1-" __stringify(CX88_MAXBOARDS) "i");MODULE_PARM_DESC(vbi_nr,"vbi device numbers");static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };MODULE_PARM(radio_nr,"1-" __stringify(CX88_MAXBOARDS) "i");MODULE_PARM_DESC(radio_nr,"radio device numbers");static unsigned int latency = UNSET;MODULE_PARM(latency,"i");MODULE_PARM_DESC(latency,"pci latency timer");static unsigned int video_debug = 0;MODULE_PARM(video_debug,"i");MODULE_PARM_DESC(video_debug,"enable debug messages [video]");static unsigned int irq_debug = 0;MODULE_PARM(irq_debug,"i");MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");static unsigned int vid_limit = 16;MODULE_PARM(vid_limit,"i");MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };MODULE_PARM(tuner,"1-" __stringify(CX88_MAXBOARDS) "i");MODULE_PARM_DESC(tuner,"tuner type");static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };MODULE_PARM(card,"1-" __stringify(CX88_MAXBOARDS) "i");MODULE_PARM_DESC(card,"card type");static unsigned int nicam = 0;MODULE_PARM(nicam,"i");MODULE_PARM_DESC(nicam,"tv audio is nicam");#define dprintk(level,fmt, arg...)	if (video_debug >= level) \	printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)/* ------------------------------------------------------------------ */static struct list_head  cx8800_devlist;static unsigned int      cx8800_devcount;/* ------------------------------------------------------------------- *//* static data                                                         */static unsigned int inline norm_swidth(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 922 : 754;}static unsigned int inline norm_hdelay(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 186 : 135;}static unsigned int inline norm_vdelay(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;}static unsigned int inline norm_maxw(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 768 : 640;//	return (norm->id & V4L2_STD_625_50) ? 720 : 640;}static unsigned int inline norm_maxh(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 576 : 480;}static unsigned int inline norm_fsc8(struct cx8800_tvnorm *norm){	static const unsigned int ntsc = 28636360;	static const unsigned int pal  = 35468950;		return (norm->id & V4L2_STD_625_50) ? pal : ntsc;}static unsigned int inline norm_notchfilter(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50)		? HLNotchFilter135PAL		: HLNotchFilter135NTSC;}static unsigned int inline norm_htotal(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 1135 : 910;}static unsigned int inline norm_vbipack(struct cx8800_tvnorm *norm){	return (norm->id & V4L2_STD_625_50) ? 511 : 288;}static struct cx8800_tvnorm tvnorms[] = {	{		.name      = "NTSC-M",		.id        = V4L2_STD_NTSC_M,		.cxiformat = VideoFormatNTSC,		.cxoformat = 0x181f0008,	},{		.name      = "NTSC-JP",		.id        = V4L2_STD_NTSC_M_JP,		.cxiformat = VideoFormatNTSCJapan,		.cxoformat = 0x181f0008,#if 0	},{		.name      = "NTSC-4.43",		.id        = FIXME,		.cxiformat = VideoFormatNTSC443,		.cxoformat = 0x181f0008,#endif	},{		.name      = "PAL-BG",		.id        = V4L2_STD_PAL_BG,		.cxiformat = VideoFormatPAL,		.cxoformat = 0x181f0008,	},{		.name      = "PAL-DK",		.id        = V4L2_STD_PAL_DK,		.cxiformat = VideoFormatPAL,		.cxoformat = 0x181f0008,	},{		.name      = "PAL-I",		.id        = V4L2_STD_PAL_I,		.cxiformat = VideoFormatPAL,		.cxoformat = 0x181f0008,        },{		.name      = "PAL-M",		.id        = V4L2_STD_PAL_M,		.cxiformat = VideoFormatPALM,		.cxoformat = 0x1c1f0008,	},{		.name      = "PAL-N",		.id        = V4L2_STD_PAL_N,		.cxiformat = VideoFormatPALN,		.cxoformat = 0x1c1f0008,	},{		.name      = "PAL-Nc",		.id        = V4L2_STD_PAL_Nc,		.cxiformat = VideoFormatPALNC,		.cxoformat = 0x1c1f0008,	},{		.name      = "PAL-60",		.id        = V4L2_STD_PAL_60,		.cxiformat = VideoFormatPAL60,		.cxoformat = 0x181f0008,	},{		.name      = "SECAM-L",		.id        = V4L2_STD_SECAM_L,		.cxiformat = VideoFormatSECAM,		.cxoformat = 0x181f0008,	},{		.name      = "SECAM-DK",		.id        = V4L2_STD_SECAM_DK,		.cxiformat = VideoFormatSECAM,		.cxoformat = 0x181f0008,	}};static struct cx8800_fmt formats[] = {	{		.name     = "8 bpp, gray",		.fourcc   = V4L2_PIX_FMT_GREY,		.cxformat = ColorFormatY8,		.depth    = 8,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "15 bpp RGB, le",		.fourcc   = V4L2_PIX_FMT_RGB555,		.cxformat = ColorFormatRGB15,		.depth    = 16,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "15 bpp RGB, be",		.fourcc   = V4L2_PIX_FMT_RGB555X,		.cxformat = ColorFormatRGB15 | ColorFormatBSWAP,		.depth    = 16,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "16 bpp RGB, le",		.fourcc   = V4L2_PIX_FMT_RGB565,		.cxformat = ColorFormatRGB16,		.depth    = 16,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "16 bpp RGB, be",		.fourcc   = V4L2_PIX_FMT_RGB565X,		.cxformat = ColorFormatRGB16 | ColorFormatBSWAP,		.depth    = 16,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "24 bpp RGB, le",		.fourcc   = V4L2_PIX_FMT_BGR24,		.cxformat = ColorFormatRGB24,		.depth    = 24,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "32 bpp RGB, le",		.fourcc   = V4L2_PIX_FMT_BGR32,		.cxformat = ColorFormatRGB32,		.depth    = 32,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "32 bpp RGB, be",		.fourcc   = V4L2_PIX_FMT_RGB32,		.cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP,		.depth    = 32,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "4:2:2, packed, YUYV",		.fourcc   = V4L2_PIX_FMT_YUYV,		.cxformat = ColorFormatYUY2,		.depth    = 16,		.flags    = FORMAT_FLAGS_PACKED,	},{		.name     = "4:2:2, packed, UYVY",		.fourcc   = V4L2_PIX_FMT_UYVY,		.cxformat = ColorFormatYUY2 | ColorFormatBSWAP,		.depth    = 16,		.flags    = FORMAT_FLAGS_PACKED,	},};static struct cx8800_fmt* format_by_fourcc(unsigned int fourcc){	unsigned int i;		for (i = 0; i < ARRAY_SIZE(formats); i++)		if (formats[i].fourcc == fourcc)			return formats+i;	return NULL;}/* ------------------------------------------------------------------- */static const struct v4l2_queryctrl no_ctl = {	.name  = "42",	.flags = V4L2_CTRL_FLAG_DISABLED,};static struct cx88_ctrl cx8800_ctls[] = {	/* --- video --- */	{		.v = {			.id            = V4L2_CID_BRIGHTNESS,			.name          = "Brightness",			.minimum       = 0x00,			.maximum       = 0xff,			.step          = 1,			.default_value = 0,			.type          = V4L2_CTRL_TYPE_INTEGER,		},		.off                   = 128,		.reg                   = MO_CONTR_BRIGHT,		.mask                  = 0x00ff,		.shift                 = 0,	},{		.v = {			.id            = V4L2_CID_CONTRAST,			.name          = "Contrast",			.minimum       = 0,			.maximum       = 0xff,			.step          = 1,			.default_value = 0,			.type          = V4L2_CTRL_TYPE_INTEGER,		},		.reg                   = MO_CONTR_BRIGHT,		.mask                  = 0xff00,		.shift                 = 8,	},{		.v = {			.id            = V4L2_CID_HUE,			.name          = "Hue",			.minimum       = 0,			.maximum       = 0xff,			.step          = 1,			.default_value = 0,			.type          = V4L2_CTRL_TYPE_INTEGER,		},		.off                   = 0,		.reg                   = MO_HUE,		.mask                  = 0x00ff,		.shift                 = 0,	},{		/* strictly, this only describes only U saturation.		 * V saturation is handled specially through code.		 */		.v = {			.id            = V4L2_CID_SATURATION,			.name          = "Saturation",			.minimum       = 0,			.maximum       = 0xff,			.step          = 1,			.default_value = 0,			.type          = V4L2_CTRL_TYPE_INTEGER,		},		.off                   = 0,		.reg                   = MO_UV_SATURATION,		.mask                  = 0x00ff,		.shift                 = 0,	},{	/* --- audio --- */		.v = {			.id            = V4L2_CID_AUDIO_MUTE,			.name          = "Mute",			.minimum       = 0,			.maximum       = 1,			.type          = V4L2_CTRL_TYPE_BOOLEAN,		},		.reg                   = AUD_VOL_CTL,		.sreg                  = SHADOW_AUD_VOL_CTL,		.mask                  = (1 << 6),		.shift                 = 6,	},{		.v = {			.id            = V4L2_CID_AUDIO_VOLUME,			.name          = "Volume",			.minimum       = 0,			.maximum       = 0x3f,			.step          = 1,			.default_value = 0,			.type          = V4L2_CTRL_TYPE_INTEGER,		},		.reg                   = AUD_VOL_CTL,		.sreg                  = SHADOW_AUD_VOL_CTL,		.mask                  = 0x3f,		.shift                 = 0,	},{		.v = {			.id            = V4L2_CID_AUDIO_BALANCE,			.name          = "Balance",			.minimum       = 0,			.maximum       = 0x7f,			.step          = 1,			.default_value = 0x40,			.type          = V4L2_CTRL_TYPE_INTEGER,		},		.reg                   = AUD_BAL_CTL,		.sreg                  = SHADOW_AUD_BAL_CTL,		.mask                  = 0x7f,		.shift                 = 0,	}};const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);/* ------------------------------------------------------------------- *//* resource management                                                 */static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit){	if (fh->resources & bit)		/* have it already allocated */		return 1;	/* is it free? */	down(&dev->lock);	if (dev->resources & bit) {		/* no, someone else uses it */		up(&dev->lock);		return 0;	}	/* it's free, grab it */	fh->resources  |= bit;	dev->resources |= bit;	dprintk(1,"res: get %d\n",bit);	up(&dev->lock);	return 1;}staticint res_check(struct cx8800_fh *fh, unsigned int bit){	return (fh->resources & bit);}staticint res_locked(struct cx8800_dev *dev, unsigned int bit){	return (dev->resources & bit);}staticvoid res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits){	if ((fh->resources & bits) != bits)		BUG();	down(&dev->lock);	fh->resources  &= ~bits;	dev->resources &= ~bits;	dprintk(1,"res: put %d\n",bits);	up(&dev->lock);}/* ------------------------------------------------------------------ */static const u32 xtal = 28636363;static int set_pll(struct cx8800_dev *dev, int prescale, u32 ofreq){	static u32 pre[] = { 0, 0, 0, 3, 2, 1 };	u64 pll;	u32 reg;	int i;	if (prescale < 2)		prescale = 2;	if (prescale > 5)		prescale = 5;	pll = ofreq * 8 * prescale * (u64)(1 << 20);	do_div(pll,xtal);	reg = (pll & 0x3ffffff) | (pre[prescale] << 26);	if (((reg >> 20) & 0x3f) < 14) {		printk("%s: pll out of range\n",dev->name);		return -1;	}			dprintk(1,"set_pll:    MO_PLL_REG       0x%08x [old=0x%08x,freq=%d]\n",		reg, cx_read(MO_PLL_REG), ofreq);	cx_write(MO_PLL_REG, reg);	for (i = 0; i < 10; i++) {		reg = cx_read(MO_DEVICE_STATUS);		if (reg & (1<<2)) {			dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",				prescale,ofreq);			return 0;		}		dprintk(1,"pll not locked yet, waiting ...\n");		set_current_state(TASK_INTERRUPTIBLE);		schedule_timeout(HZ/10);	}	dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);	return -1;}static int set_tvaudio(struct cx8800_dev *dev){	if (CX88_VMUX_TELEVISION != INPUT(dev->input)->type)		return 0;	if (V4L2_STD_PAL_BG & dev->tvnorm->id) {		dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;	} else if (V4L2_STD_PAL_DK & dev->tvnorm->id) {		dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;	} else if (V4L2_STD_PAL_I & dev->tvnorm->id) {		dev->tvaudio = WW_NICAM_I;	} else if (V4L2_STD_SECAM_L & dev->tvnorm->id) {		dev->tvaudio = WW_SYSTEM_L_AM;	} else if (V4L2_STD_SECAM_DK & dev->tvnorm->id) {		dev->tvaudio = WW_A2_DK;	} else if ((V4L2_STD_NTSC_M & dev->tvnorm->id) ||		   (V4L2_STD_PAL_M  & dev->tvnorm->id)) {		dev->tvaudio = WW_BTSC;	} else if (V4L2_STD_NTSC_M_JP & dev->tvnorm->id) {		dev->tvaudio = WW_EIAJ;	} else {		printk("%s: tvaudio support needs work for this tv norm [%s], sorry\n",		       dev->name, dev->tvnorm->name);		dev->tvaudio = 0;

⌨️ 快捷键说明

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