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

📄 zoran_device.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Zoran zr36057/zr36067 PCI controller driver, for the * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux * Media Labs LML33/LML33R10. * * This part handles device access (PCI/I2C/codec/...) *  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> * * Currently maintained by: *   Ronald Bultje    <rbultje@ronald.bitfreak.net> *   Laurent Pinchart <laurent.pinchart@skynet.be> *   Mailinglist      <mjpeg-users@lists.sf.net> * * 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/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/vmalloc.h>#include <linux/byteorder/generic.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>#include <linux/videodev.h>#include <linux/spinlock.h>#include <linux/sem.h>#include <linux/pci.h>#include <linux/video_decoder.h>#include <linux/video_encoder.h>#include <linux/delay.h>#include <linux/wait.h>#include <asm/io.h>#include "videocodec.h"#include "zoran.h"#include "zoran_device.h"#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \		   ZR36057_ISR_GIRQ1 | \		   ZR36057_ISR_JPEGRepIRQ )extern const struct zoran_format zoran_formats[];extern int *zr_debug;#define dprintk(num, format, args...) \	do { \		if (*zr_debug >= num) \			printk(format, ##args); \	} while (0)static int lml33dpath = 0;	/* 1 will use digital path in capture				 * mode instead of analog. It can be				 * used for picture adjustments using				 * tool like xawtv while watching image				 * on TV monitor connected to the output.				 * However, due to absence of 75 Ohm				 * load on Bt819 input, there will be				 * some image imperfections */module_param(lml33dpath, bool, 0);MODULE_PARM_DESC(lml33dpath,		 "Use digital path capture mode (on LML33 cards)");static voidzr36057_init_vfe (struct zoran *zr);/* * General Purpose I/O and Guest bus access *//* * This is a bit tricky. When a board lacks a GPIO function, the corresponding * GPIO bit number in the card_info structure is set to 0. */voidGPIO (struct zoran *zr,      int           bit,      unsigned int  value){	u32 reg;	u32 mask;	/* Make sure the bit number is legal	 * A bit number of -1 (lacking) gives a mask of 0,	 * making it harmless */	mask = (1 << (24 + bit)) & 0xff000000;	reg = btread(ZR36057_GPPGCR1) & ~mask;	if (value) {		reg |= mask;	}	btwrite(reg, ZR36057_GPPGCR1);	udelay(1);}/* * Wait til post office is no longer busy */intpost_office_wait (struct zoran *zr){	u32 por;//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {	while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {		/* wait for something to happen */	}	if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) {		/* In LML33/BUZ \GWS line is not connected, so it has always timeout set */		dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr),			por);		return -1;	}	return 0;}intpost_office_write (struct zoran *zr,		   unsigned int  guest,		   unsigned int  reg,		   unsigned int  value){	u32 por;	por =	    ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |	    ((reg & 7) << 16) | (value & 0xFF);	btwrite(por, ZR36057_POR);	return post_office_wait(zr);}intpost_office_read (struct zoran *zr,		  unsigned int  guest,		  unsigned int  reg){	u32 por;	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);	btwrite(por, ZR36057_POR);	if (post_office_wait(zr) < 0) {		return -1;	}	return btread(ZR36057_POR) & 0xFF;}/* * detect guests */static voiddump_guests (struct zoran *zr){	if (*zr_debug > 2) {		int i, guest[8];		for (i = 1; i < 8; i++) {	// Don't read jpeg codec here			guest[i] = post_office_read(zr, i, 0);		}		printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));		for (i = 1; i < 8; i++) {			printk(" 0x%02x", guest[i]);		}		printk("\n");	}}static inline unsigned longget_time (void){	struct timeval tv;	do_gettimeofday(&tv);	return (1000000 * tv.tv_sec + tv.tv_usec);}voiddetect_guest_activity (struct zoran *zr){	int timeout, i, j, res, guest[8], guest0[8], change[8][3];	unsigned long t0, t1;	dump_guests(zr);	printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",	       ZR_DEVNAME(zr));	for (i = 1; i < 8; i++) {	// Don't read jpeg codec here		guest0[i] = guest[i] = post_office_read(zr, i, 0);	}	timeout = 0;	j = 0;	t0 = get_time();	while (timeout < 10000) {		udelay(10);		timeout++;		for (i = 1; (i < 8) && (j < 8); i++) {			res = post_office_read(zr, i, 0);			if (res != guest[i]) {				t1 = get_time();				change[j][0] = (t1 - t0);				t0 = t1;				change[j][1] = i;				change[j][2] = res;				j++;				guest[i] = res;			}		}		if (j >= 8)			break;	}	printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr));	for (i = 1; i < 8; i++) {		printk(" 0x%02x", guest0[i]);	}	printk("\n");	if (j == 0) {		printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr));		return;	}	for (i = 0; i < j; i++) {		printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr),		       change[i][0], change[i][1], change[i][2]);	}}/* * JPEG Codec access */voidjpeg_codec_sleep (struct zoran *zr,		  int           sleep){	GPIO(zr, zr->card.gpio[GPIO_JPEG_SLEEP], !sleep);	if (!sleep) {		dprintk(3,			KERN_DEBUG			"%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n",			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));		udelay(500);	} else {		dprintk(3,			KERN_DEBUG			"%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n",			ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1));		udelay(2);	}}intjpeg_codec_reset (struct zoran *zr){	/* Take the codec out of sleep */	jpeg_codec_sleep(zr, 0);	if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) {		post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0,				  0);		udelay(2);	} else {		GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 0);		udelay(2);		GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 1);		udelay(2);	}	return 0;}/* *   Set the registers for the size we have specified. Don't bother *   trying to understand this without the ZR36057 manual in front of *   you [AC]. * *   PS: The manual is free for download in .pdf format from *   www.zoran.com - nicely done those folks. */static voidzr36057_adjust_vfe (struct zoran          *zr,		    enum zoran_codec_mode  mode){	u32 reg;	switch (mode) {	case BUZ_MODE_MOTION_DECOMPRESS:		btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);		reg = btread(ZR36057_VFEHCR);		if ((reg & (1 << 10)) && zr->card.type != LML33R10) {			reg += ((1 << 10) | 1);		}		btwrite(reg, ZR36057_VFEHCR);		break;	case BUZ_MODE_MOTION_COMPRESS:	case BUZ_MODE_IDLE:	default:		if (zr->norm == VIDEO_MODE_NTSC ||		    (zr->card.type == LML33R10 &&		     zr->norm == VIDEO_MODE_PAL))			btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);		else			btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);		reg = btread(ZR36057_VFEHCR);		if (!(reg & (1 << 10)) && zr->card.type != LML33R10) {			reg -= ((1 << 10) | 1);		}		btwrite(reg, ZR36057_VFEHCR);		break;	}}/* * set geometry */static voidzr36057_set_vfe (struct zoran              *zr,		 int                        video_width,		 int                        video_height,		 const struct zoran_format *format){	struct tvnorm *tvn;	unsigned HStart, HEnd, VStart, VEnd;	unsigned DispMode;	unsigned VidWinWid, VidWinHt;	unsigned hcrop1, hcrop2, vcrop1, vcrop2;	unsigned Wa, We, Ha, He;	unsigned X, Y, HorDcm, VerDcm;	u32 reg;	unsigned mask_line_size;	tvn = zr->timing;	Wa = tvn->Wa;	Ha = tvn->Ha;	dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n",		ZR_DEVNAME(zr), video_width, video_height);	if (zr->norm != VIDEO_MODE_PAL &&	    zr->norm != VIDEO_MODE_NTSC &&	    zr->norm != VIDEO_MODE_SECAM) {		dprintk(1,			KERN_ERR "%s: set_vfe() - norm = %d not valid\n",			ZR_DEVNAME(zr), zr->norm);		return;	}	if (video_width < BUZ_MIN_WIDTH ||	    video_height < BUZ_MIN_HEIGHT ||	    video_width > Wa || video_height > Ha) {		dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",			ZR_DEVNAME(zr), video_width, video_height);		return;	}	/**** zr36057 ****/	/* horizontal */	VidWinWid = video_width;	X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;	We = (VidWinWid * 64) / X;	HorDcm = 64 - X;	hcrop1 = 2 * ((tvn->Wa - We) / 4);	hcrop2 = tvn->Wa - We - hcrop1;	HStart = tvn->HStart ? tvn->HStart : 1;	/* (Ronald) Original comment:	 * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+"	 * this is false. It inverses chroma values on the LML33R10 (so Cr	 * suddenly is shown as Cb and reverse, really cool effect if you	 * want to see blue faces, not useful otherwise). So don't use |1.	 * However, the DC10 has '0' as HStart, but does need |1, so we	 * use a dirty check...	 */	HEnd = HStart + tvn->Wa - 1;	HStart += hcrop1;	HEnd -= hcrop2;	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);	if (zr->card.vfe_pol.hsync_pol)		reg |= ZR36057_VFEHCR_HSPol;	btwrite(reg, ZR36057_VFEHCR);	/* Vertical */	DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);	VidWinHt = DispMode ? video_height : video_height / 2;	Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;	He = (VidWinHt * 64) / Y;	VerDcm = 64 - Y;	vcrop1 = (tvn->Ha / 2 - He) / 2;	vcrop2 = tvn->Ha / 2 - He - vcrop1;	VStart = tvn->VStart;	VEnd = VStart + tvn->Ha / 2;	// - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP	VStart += vcrop1;	VEnd -= vcrop2;	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);	if (zr->card.vfe_pol.vsync_pol)		reg |= ZR36057_VFEVCR_VSPol;	btwrite(reg, ZR36057_VFEVCR);	/* scaler and pixel format */	reg = 0;	reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);	reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);	reg |= (DispMode << ZR36057_VFESPFR_DispMode);	if (format->palette != VIDEO_PALETTE_YUV422)		reg |= ZR36057_VFESPFR_LittleEndian;	/* RJ: I don't know, why the following has to be the opposite	 * of the corresponding ZR36060 setting, but only this way	 * we get the correct colors when uncompressing to the screen  */	//reg |= ZR36057_VFESPFR_VCLKPol; /**/	/* RJ: Don't know if that is needed for NTSC also */	if (zr->norm != VIDEO_MODE_NTSC)		reg |= ZR36057_VFESPFR_ExtFl;	// NEEDED!!!!!!! Wolfgang	reg |= ZR36057_VFESPFR_TopField;	switch (format->palette) {	case VIDEO_PALETTE_YUV422:		reg |= ZR36057_VFESPFR_YUV422;		break;	case VIDEO_PALETTE_RGB555:		reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;		break;	case VIDEO_PALETTE_RGB565:		reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;		break;	case VIDEO_PALETTE_RGB24:		reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;		break;	case VIDEO_PALETTE_RGB32:		reg |= ZR36057_VFESPFR_RGB888;		break;	default:		dprintk(1,			KERN_INFO "%s: set_vfe() - unknown color_fmt=%x\n",			ZR_DEVNAME(zr), format->palette);		return;	}	if (HorDcm >= 48) {		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */	} else if (HorDcm >= 32) {		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */	} else if (HorDcm >= 16) {		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */	}	btwrite(reg, ZR36057_VFESPFR);	/* display configuration */	reg = (16 << ZR36057_VDCR_MinPix)	    | (VidWinHt << ZR36057_VDCR_VidWinHt)	    | (VidWinWid << ZR36057_VDCR_VidWinWid);	if (pci_pci_problems & PCIPCI_TRITON)		// || zr->revision < 1) // Revision 1 has also Triton support		reg &= ~ZR36057_VDCR_Triton;	else		reg |= ZR36057_VDCR_Triton;	btwrite(reg, ZR36057_VDCR);	/* (Ronald) don't write this if overlay_mask = NULL */	if (zr->overlay_mask) {		/* Write overlay clipping mask data, but don't enable overlay clipping */		/* RJ: since this makes only sense on the screen, we use 		 * zr->overlay_settings.width instead of video_width */		mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;		reg = virt_to_bus(zr->overlay_mask);		btwrite(reg, ZR36057_MMTR);		reg = virt_to_bus(zr->overlay_mask + mask_line_size);		btwrite(reg, ZR36057_MMBR);		reg =		    mask_line_size - (zr->overlay_settings.width +				      31) / 32;		if (DispMode == 0)			reg += mask_line_size;		reg <<= ZR36057_OCR_MaskStride;		btwrite(reg, ZR36057_OCR);	}	zr36057_adjust_vfe(zr, zr->codec_mode);}/* * Switch overlay on or off */voidzr36057_overlay (struct zoran *zr,		 int           on){	u32 reg;	if (on) {		/* do the necessary settings ... */		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */		zr36057_set_vfe(zr,				zr->overlay_settings.width,				zr->overlay_settings.height,				zr->overlay_settings.format);		/* Start and length of each line MUST be 4-byte aligned.		 * This should be allready checked before the call to this routine.		 * All error messages are internal driver checking only! */		/* video display top and bottom registers */		reg = (u32) zr->buffer.base +		    zr->overlay_settings.x *		    ((zr->overlay_settings.format->depth + 7) / 8) +		    zr->overlay_settings.y *		    zr->buffer.bytesperline;		btwrite(reg, ZR36057_VDTR);		if (reg & 3)			dprintk(1,				KERN_ERR				"%s: zr36057_overlay() - video_address not aligned\n",				ZR_DEVNAME(zr));		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)			reg += zr->buffer.bytesperline;		btwrite(reg, ZR36057_VDBR);		/* video stride, status, and frame grab register */		reg = zr->buffer.bytesperline -		    zr->overlay_settings.width *		    ((zr->overlay_settings.format->depth + 7) / 8);		if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)			reg += zr->buffer.bytesperline;		if (reg & 3)			dprintk(1,				KERN_ERR				"%s: zr36057_overlay() - video_stride not aligned\n",				ZR_DEVNAME(zr));		reg = (reg << ZR36057_VSSFGR_DispStride);		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */		btwrite(reg, ZR36057_VSSFGR);		/* Set overlay clipping */		if (zr->overlay_settings.clipcount > 0)			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);		/* ... and switch it on */		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);	} else {		/* Switch it off */		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	}}/* * The overlay mask has one bit for each pixel on a scan line, *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. */voidwrite_overlay_mask (struct file       *file,		    struct video_clip *vp,		    int                count){	struct zoran_fh *fh = file->private_data;	struct zoran *zr = fh->zr;	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;	u32 *mask;	int x, y, width, height;	unsigned i, j, k;

⌨️ 快捷键说明

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