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

📄 cyberpro.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * CyberPro 2000 video capture driver for the Rebel.com NetWinder * * (C) 1999-2000 Russell King * *  Re-written from Rebel.com's vidcap driver. * * Architecture * ------------ *  The NetWinder video capture consists of a SAA7111 video decoder chip *  connected to the CyberPro feature bus.  The video data is captured to *  the VGA memory, where the CyberPro can overlay (by chromakeying) the *  data onto the VGA display. * *  The CyberPro also has some nifty features, including a second overlay *  and picture in picture mode.  We do not currently use these features. * * Power Saving * ------------ *  Please note that rev.5 NetWinders have the ability to hold the SAA7111 *  decoder chip into reset, which saves power.  The only time at which *  this is done is when the driver is unloaded, which implies that this *  is compiled as a module. * *  In this case, you will want the kernel to automatically load this *  driver when required.  Place the following line in /etc/modules.conf *  to enable this: * *   alias char-major-81-0 cyberpro * *  The relevant modules will be automatically loaded by modprobe on a *  as and when needed basis. * * Capture resolution * ------------------ *  The maximum useful capture resolution is: *     625-line UK: 716x576 *     525-line US: ? * * Bugs * ---- *  1. The CyberPro chip seems to be prone to randomly scribbling over VGA *     memory [hopefully fixed with new capture enable/freeze stuff] *  2. read()ing pauses video capture, and sometimes triggers bug 1. *  3. mmap() is not supported (requires BM-DMA - see bug 4) *  4. Really, we want to do scatter BM-DMA.  Is the CyberPro capable of this? *     The Cyberpro seems to randomly scribble to various PCI addresses if you *     transfer >16 words. *  5. We shouldn't ignore O_NONBLOCK when reading a frame. *  6. The incoming stream on the NetWinder is CCIR656, which is YUV422. *     CyberPro docs also call the format we capture and overlay "YUV422", *     but we actually seem to have Y, U, Y, V bytes (is this YUYV format?) */#include <linux/config.h>#include <linux/module.h>#include <linux/videodev.h>#include <linux/video_decoder.h>#include <linux/mm.h>#include <linux/i2c-old.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/kmod.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/pgalloc.h>MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");MODULE_DESCRIPTION("CyberPro v4l video grabber");MODULE_LICENSE("GPL");#include "../../video/cyber2000fb.h"/* * These enable various experimental features.  Most of these * are just plain broken or just don't work at the moment. *//* * Enable this if you want mmap() access. (see bug 4) */#undef USE_MMAP/* * Enable this if you want mmio access. (slow) */#define USE_MMIO/* * The V4L API is unclear whether VIDIOCSCAPTURE call is allowed while * capture is running.  The default is to disallow the call. * * Define this if you do want to allow the call while capture is active. */#undef	ALLOW_SCAPTURE_WHILE_CAP/* * We capture two frames */#define NR_FRAMES	2/* * One frame of video is 202 pages, assuming YUV422 format, 716x576 */#define NR_PAGES	202struct src_info {	unsigned int	offset;		/* offset of source data	*/	unsigned int	x;		/* source x			*/	unsigned int	y;		/* source y			*/	unsigned int	width;		/* source width			*/	unsigned int	height;		/* source height		*/	unsigned int	format;		/* source format		*/};struct dst_info {	unsigned int	x;		/* destination x		*/	unsigned int	y;		/* destination y		*/	unsigned int	width;		/* destination width		*/	unsigned int	height;		/* destination height		*/	unsigned int	chromakey;	/* chromakey			*/	unsigned int	flags;		/* flags (eg, chromakey enable)	*/};struct cyberpro_vidinfo;struct win_info {	void (*init)(struct cyberpro_vidinfo *dp, struct win_info *wi);	void (*set_src)(struct cyberpro_vidinfo *dp, struct win_info *wi);	void (*set_win)(struct cyberpro_vidinfo *dp, struct win_info *wi);	void (*ctl)(struct cyberpro_vidinfo *dp, struct win_info *wi, int on_off);	/* public */	struct src_info	src;	struct dst_info	dst;	/* private */	unsigned short	vid_fifo_ctl;	unsigned char	vid_fmt;	unsigned char	vid_disp_ctl1;	unsigned char	vid_fifo_ctl1;	unsigned char	vid_misc_ctl1;};struct framebuf {	unsigned int		offset;		/* mmap offset for this frame	*/	unsigned int		status;#define FRAME_FREE	0#define FRAME_DONE	1#define FRAME_WAITING	2#define FRAME_GRABBING	3	/*	 * Bus-Master DMA stuff.  Note that we should	 * probably use the kiovec stuff instead.	 */	unsigned long		bus_addr[NR_PAGES];	/* list of pages		*/	struct page		*pages[NR_PAGES];	void			*buffer;	int dbg;};struct cyberpro_vidinfo {	struct video_device	*dev;	struct i2c_bus		*bus;	struct cyberpro_info	info;		/* host information		*/	unsigned char		*regs;	unsigned int		irq;		/* PCI interrupt number		*/	/* hardware configuration */	unsigned int		stream_fmt;	/* format of stream from decoder*/	/* software settings */	unsigned int		decoder:1;	/* decoder loaded		*/	unsigned int		interlace:1;	/* interlace			*/	unsigned int		buf_set:1;	/* VIDIOCSFBUF has been issued	*/	unsigned int		win_set:1;	/* VIDIOCSWIN has been issued 	*/	unsigned int		cap_active:1;	/* capture is active		*/	unsigned int		ovl_active:1;	/* overlay is active		*/	unsigned int		mmaped:1;	/* buffer is mmap()d		*/	unsigned int		unused:25;	unsigned int		users;		/* number of users		*/	unsigned long		cap_mem_offset;	/* capture framebuffer offset	*/	void *			buffer;		/* kernel capture buffer	*/	unsigned int		norm;		/* video standard		*/	struct video_capability	cap;		/* capabilities			*/	struct video_picture	pic;		/* current picture settings	*/	struct video_buffer	buf;		/* display parameters		*/	struct video_capture	capt;		/* video capture params		*/	struct win_info		*ovl;		/* overlay window set		*/	struct win_info		ext;		/* "Extended" window info	*/	struct win_info		v2;		/* "V2" window info		*/	struct win_info		x2;		/* "X2" window info		*/	unsigned int		bm_offset;	/* Cap memory bus master offset	*/	unsigned int		bm_index;	/* Cap page index		*/#ifdef USE_MMAP	unsigned int		frame_idx;	/* currently grabbing frame	*/	unsigned int		frame_size;	struct framebuf	frame[NR_FRAMES];	wait_queue_head_t	frame_wait;#endif	wait_queue_head_t	vbl_wait;	/*	 * cyberpro registers	 */	unsigned char	cap_mode1;	unsigned char	cap_mode2;	unsigned char	cap_miscctl;	unsigned char	vfac1;	unsigned char	vfac3;};/* * Our access methods. */#define cyberpro_writel(val,reg,dp)	writel(val, (dp)->regs + (reg))#define cyberpro_writew(val,reg,dp)	writew(val, (dp)->regs + (reg))#define cyberpro_writeb(val,reg,dp)	writeb(val, (dp)->regs + (reg))#define cyberpro_readb(reg,dp)	readb((dp)->regs + (reg))static inline voidcyberpro_grphw(unsigned int reg, unsigned int val, struct cyberpro_vidinfo *dp){	cyberpro_writew((reg & 255) | val << 8, 0x3ce, dp);}static void cyberpro_grphw8(unsigned int reg, unsigned int val, struct cyberpro_vidinfo *dp){	cyberpro_grphw(reg, val, dp);}static unsigned char cyberpro_grphr8(int reg, struct cyberpro_vidinfo *dp){	cyberpro_writeb(reg, 0x3ce, dp);	return cyberpro_readb(0x3cf, dp);}static void cyberpro_grphw16(int reg, unsigned int val, struct cyberpro_vidinfo *dp){	cyberpro_grphw(reg, val, dp);	cyberpro_grphw(reg + 1, val >> 8, dp);}static void cyberpro_grphw24(int reg, unsigned int val, struct cyberpro_vidinfo *dp){	cyberpro_grphw(reg, val, dp);	cyberpro_grphw(reg + 1, val >> 8, dp);	cyberpro_grphw(reg + 2, val >> 16, dp);}#if 0static voidcyberpro_dbg_dump(void){	int i;	unsigned char idx[] =		{ 0x30, 0x3e, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d,		  0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad };	printk(KERN_DEBUG);	for (i = 0; i < sizeof(idx); i++)		printk("%02x ", idx[i]);	printk("\n" KERN_DEBUG);	for (i = 0; i < sizeof(idx); i++)		printk("%02x ", cyberpro_grphr8(idx[i]));	printk("\n");}#endif/* * On the NetWinder, we can put the SAA7111 to sleep by holding * it in reset. * * Note: once we have initialised the SAA7111, we can't put it back to * sleep and expect it to keep its settings.  Maybe a better solution * is to register/de-register the i2c bus in open/release? */static voiddecoder_sleep(int sleep){#ifdef CONFIG_ARCH_NETWINDER	extern spinlock_t gpio_lock;	spin_lock_irq(&gpio_lock);	cpld_modify(CPLD_7111_DISABLE, sleep ? CPLD_7111_DISABLE : 0);	spin_unlock_irq(&gpio_lock);	if (!sleep) {		/*		 * wait 20ms for device to wake up		 */		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(HZ / 50);	}#endif}/* -------------------------------- I2C support ---------------------------- */#define I2C_DELAY	100static voidcyberpro_i2c_setlines(struct i2c_bus *bus, int ctrl, int data){	struct cyberpro_vidinfo *dp = bus->data;	int v;	v = (ctrl ? EXT_LATCH2_I2C_CLKEN : 0x00) | (data ? EXT_LATCH2_I2C_DATEN : 0x00);	cyberpro_grphw8(EXT_LATCH2, v, dp);	udelay(I2C_DELAY);}static intcyberpro_i2c_getdataline(struct i2c_bus *bus){	struct cyberpro_vidinfo *dp = bus->data;	unsigned long flags;	int v;	save_flags(flags);	cli();	v = cyberpro_grphr8(EXT_LATCH2, dp);	restore_flags(flags);	return v & EXT_LATCH2_I2C_DAT ? 1 : 0;}static voidcyberpro_i2c_attach(struct i2c_bus *bus, int id){	struct cyberpro_vidinfo *dp = bus->data;	int zero = 0;	if (id == I2C_DRIVERID_VIDEODECODER) {		__u16 norm = dp->norm;		i2c_control_device(bus, id, DECODER_SET_NORM, &norm);		i2c_control_device(bus, id, DECODER_SET_PICTURE, &dp->pic);		i2c_control_device(bus, id, DECODER_ENABLE_OUTPUT, &zero);		dp->decoder = 1;	}}static voidcyberpro_i2c_detach(struct i2c_bus *bus, int id){	struct cyberpro_vidinfo *dp = bus->data;	if (id == I2C_DRIVERID_VIDEODECODER)		dp->decoder = 0;}static struct i2c_bus cyberpro_i2c_bus = {	name:			"",	id:			I2C_BUSID_CYBER2000,	bus_lock:		SPIN_LOCK_UNLOCKED,	attach_inform:		cyberpro_i2c_attach,	detach_inform:		cyberpro_i2c_detach,	i2c_setlines:		cyberpro_i2c_setlines,	i2c_getdataline:	cyberpro_i2c_getdataline,};/*------------------------- Extended Overlay Window ------------------------- * Initialise 1st overlay window (works) */static voidcyberpro_ext_init(struct cyberpro_vidinfo *dp, struct win_info *wi){	wi->vid_fifo_ctl  = 0xf87c;	wi->vid_fmt       = EXT_VID_FMT_YUV422;	wi->vid_disp_ctl1 = EXT_VID_DISP_CTL1_VINTERPOL_OFF |			    EXT_VID_DISP_CTL1_NOCLIP;	wi->vid_fifo_ctl1 = EXT_VID_FIFO_CTL1_INTERLEAVE |			    EXT_VID_FIFO_CTL1_OE_HIGH;	wi->vid_misc_ctl1 = 0;	cyberpro_grphw8 (EXT_VID_DISP_CTL1,  wi->vid_disp_ctl1, dp);	cyberpro_grphw16(EXT_DDA_X_INIT,     0x0800, dp);	cyberpro_grphw16(EXT_DDA_Y_INIT,     0x0800, dp);	cyberpro_grphw16(EXT_VID_FIFO_CTL,   wi->vid_fifo_ctl, dp);	cyberpro_grphw8 (EXT_VID_FIFO_CTL1,  wi->vid_fifo_ctl1, dp);}/* * Set the source parameters for the extended window */static voidcyberpro_ext_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi){	unsigned int phase, pitch;	pitch = (wi->src.width >> 2) & 0x0fff;	phase = (wi->src.width + 3) >> 2;	wi->vid_fmt &= ~7;	switch (wi->src.format) {	case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565;    break;	case VIDEO_PALETTE_RGB24:  wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break;	case VIDEO_PALETTE_RGB32:  wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break;	case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555;    break;	case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422;    break;	}	cyberpro_grphw24(EXT_MEM_START, wi->src.offset, dp);	cyberpro_grphw16(EXT_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp);	cyberpro_grphw8 (EXT_SRC_WIN_WIDTH, phase, dp);	cyberpro_grphw8 (EXT_VID_FMT, wi->vid_fmt, dp);}/* * Set overlay1 window */static voidcyberpro_ext_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi){	unsigned int xscale, yscale;	unsigned int xoff, yoff;	/*	 * Note: the offset does not appear to be influenced by	 * hardware scrolling.	 */	xoff = yoff = 0;	xoff += wi->dst.x;	yoff += wi->dst.y;	xscale = wi->src.width;	if (wi->dst.width >= wi->src.width * 2) {		wi->vid_fmt |= EXT_VID_FMT_DBL_H_PIX;		xscale *= 2;	} else {		wi->vid_fmt &= ~EXT_VID_FMT_DBL_H_PIX;	}	xscale = ((xscale - /*2*/0) * 4096) / wi->dst.width;	yscale = ((wi->src.height - /*2*/0) * 4096) / wi->dst.height;	cyberpro_grphw16(EXT_X_START, xoff, dp);	cyberpro_grphw16(EXT_X_END,   xoff + wi->dst.width, dp);	cyberpro_grphw16(EXT_Y_START, yoff, dp);	cyberpro_grphw16(EXT_Y_END,   yoff + wi->dst.height, dp);	cyberpro_grphw24(EXT_COLOUR_COMPARE, wi->dst.chromakey, dp);	cyberpro_grphw16(EXT_DDA_X_INC, xscale, dp);	cyberpro_grphw16(EXT_DDA_Y_INC, yscale, dp);	cyberpro_grphw8(EXT_VID_FMT, wi->vid_fmt, dp);	if (wi->dst.flags & VIDEO_WINDOW_CHROMAKEY)		wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_IGNORE_CCOMP;	else		wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_IGNORE_CCOMP;}/* * Enable or disable the 1st overlay window.  Note that for anything * useful to be displayed, we must have capture enabled. */static voidcyberpro_ext_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on){	if (on)		wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW;	else		wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW;	cyberpro_grphw8(EXT_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);}/*------------------------------- V2 Overlay Window ------------------------- * Initialise 2nd overlay window (guesswork) */static voidcyberpro_v2_init(struct cyberpro_vidinfo *dp, struct win_info *wi){	wi->vid_fifo_ctl  = 0xf87c;	wi->vid_fmt       = EXT_VID_FMT_YUV422;	wi->vid_disp_ctl1 = EXT_VID_DISP_CTL1_VINTERPOL_OFF |			    EXT_VID_DISP_CTL1_NOCLIP;	wi->vid_fifo_ctl1 = 0x06;	wi->vid_misc_ctl1 = 0;	cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp);	cyberpro_grphw8 (Y_V2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);	/* No DDA init values */	cyberpro_grphw16(Y_V2_VID_FIFO_CTL,  wi->vid_fifo_ctl, dp);	cyberpro_grphw8 (Y_V2_VID_FIFO_CTL1, wi->vid_fifo_ctl1, dp);}/* * Set the source parameters for the v2 window */static voidcyberpro_v2_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi){	unsigned int phase, pitch;	pitch = (wi->src.width >> 2) & 0x0fff;	phase = (wi->src.width + 3) >> 2;	wi->vid_fmt &= ~7;	switch (wi->src.format) {	case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565;    break;	case VIDEO_PALETTE_RGB24:  wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break;	case VIDEO_PALETTE_RGB32:  wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break;	case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555;    break;	case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422;    break;	}

⌨️ 快捷键说明

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