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

📄 planb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/*     planb - PlanB frame grabber driver    PlanB is used in the 7x00/8x00 series of PowerMacintosh    Computers as video input DMA controller.    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)    Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)    Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)    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.*//* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */#include <linux/init.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/videodev.h>#include <linux/wait.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/dbdma.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/irq.h>#include <asm/semaphore.h>#include "planb.h"#include "saa7196.h"/* Would you mind for some ugly debugging? */#if 0#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */#else#define DEBUG(x...) 		/* Don't debug driver */#endif#if 0#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */#else#define IDEBUG(x...) 		/* Don't debug interrupt part */#endif/* Ever seen a Mac with more than 1 of these? */#define PLANB_MAX 1static int planb_num;static struct planb planbs[PLANB_MAX];static volatile struct planb_registers *planb_regs;static int def_norm = PLANB_DEF_NORM;	/* default norm */static int video_nr = -1;MODULE_PARM(def_norm, "i");MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");MODULE_PARM(video_nr,"i");MODULE_LICENSE("GPL");/* ------------------ PlanB Exported Functions ------------------ */static long planb_write(struct video_device *, const char *, unsigned long, int);static long planb_read(struct video_device *, char *, unsigned long, int);static int planb_open(struct video_device *, int);static void planb_close(struct video_device *);static int planb_ioctl(struct video_device *, unsigned int, void *);static int planb_init_done(struct video_device *);static int planb_mmap(struct video_device *, const char *, unsigned long);static void planb_irq(int, void *, struct pt_regs *);static void release_planb(void);int init_planbs(struct video_init *);/* ------------------ PlanB Internal Functions ------------------ */static int planb_prepare_open(struct planb *);static void planb_prepare_close(struct planb *);static void saa_write_reg(unsigned char, unsigned char);static unsigned char saa_status(int, struct planb *);static void saa_set(unsigned char, unsigned char, struct planb *);static void saa_init_regs(struct planb *);static int grabbuf_alloc(struct planb *);static int vgrab(struct planb *, struct video_mmap *);static void add_clip(struct planb *, struct video_clip *);static void fill_cmd_buff(struct planb *);static void cmd_buff(struct planb *);static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);static void overlay_start(struct planb *);static void overlay_stop(struct planb *);static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,	unsigned int);static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,	unsigned int);static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,	unsigned short, unsigned int, unsigned int);static int init_planb(struct planb *);static int find_planb(void);static void planb_pre_capture(int, int, struct planb *);static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,					int, int, int, int, int, struct planb *);static inline void planb_dbdma_stop(volatile struct dbdma_regs *);static unsigned int saa_geo_setup(int, int, int, int, struct planb *);static inline int overlay_is_active(struct planb *);/*******************************//* Memory management functions *//*******************************/static int grabbuf_alloc(struct planb *pb){	int i, npage;	npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)#ifndef PLANB_GSCANLINE		+ MAX_LNUM#endif /* PLANB_GSCANLINE */		);	if ((pb->rawbuf = (unsigned char**) kmalloc (npage				* sizeof(unsigned long), GFP_KERNEL)) == 0)		return -ENOMEM;	for (i = 0; i < npage; i++) {		pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL								|GFP_DMA, 0);		if (!pb->rawbuf[i])			break;		SetPageReserved(virt_to_page(pb->rawbuf[i]));	}	if (i-- < npage) {		printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");		for (; i > 0; i--) {			ClearPageReserved(virt_to_page(pb->rawbuf[i]));			free_pages((unsigned long)pb->rawbuf[i], 0);		}		kfree(pb->rawbuf);		return -ENOBUFS;	}	pb->rawbuf_size = npage;	return 0;}/*****************************//* Hardware access functions *//*****************************/static void saa_write_reg(unsigned char addr, unsigned char val){	planb_regs->saa_addr = addr; eieio();	planb_regs->saa_regval = val; eieio();	return;}/* return  status byte 0 or 1: */static unsigned char saa_status(int byte, struct planb *pb){	saa_regs[pb->win.norm][SAA7196_STDC] =		(saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1);	saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]);	/* Let's wait 30msec for this one */	msleep_interruptible(30);	return (unsigned char)in_8 (&planb_regs->saa_status);}static void saa_set(unsigned char addr, unsigned char val, struct planb *pb){	if(saa_regs[pb->win.norm][addr] != val) {		saa_regs[pb->win.norm][addr] = val;		saa_write_reg (addr, val);	}	return;}static void saa_init_regs(struct planb *pb){	int i;	for (i = 0; i < SAA7196_NUMREGS; i++)		saa_write_reg (i, saa_regs[pb->win.norm][i]);}static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,	struct planb *pb){	int ht, norm = pb->win.norm;	switch(bpp) {	case 2:		/* RGB555+a 1x16-bit + 16-bit transparent */		saa_regs[norm][SAA7196_FMTS] &= ~0x3;		break;	case 1:	case 4:		/* RGB888 1x24-bit + 8-bit transparent */		saa_regs[norm][SAA7196_FMTS] &= ~0x1;		saa_regs[norm][SAA7196_FMTS] |= 0x2;		break;	default:		return -EINVAL;	}	ht = (interlace ? height / 2 : height);	saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff);	saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3)						| (width >> 8 & 0x3);	saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff);	saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3)						| (ht >> 8 & 0x3);	/* feed both fields if interlaced, or else feed only even fields */	saa_regs[norm][SAA7196_FMTS] = (interlace) ?					(saa_regs[norm][SAA7196_FMTS] & ~0x60)					: (saa_regs[norm][SAA7196_FMTS] | 0x60);	/* transparent mode; extended format enabled */	saa_regs[norm][SAA7196_DPATH] |= 0x3;	return 0;}/***************************//* DBDMA support functions *//***************************/static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch){	out_le32(&ch->control, PLANB_CLR(RUN));	out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));}static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch){	int i = 0;	out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH));	while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {		IDEBUG("PlanB: waiting for DMA to stop\n");		i++;	}}static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,	unsigned short command, unsigned int cmd_dep){	st_le16(&ch->command, command);	st_le32(&ch->cmd_dep, cmd_dep);}static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,	unsigned int phy_addr, unsigned int cmd_dep){	st_le16(&ch->command, STORE_WORD | KEY_SYSTEM);	st_le16(&ch->req_count, 4);	st_le32(&ch->phy_addr, phy_addr);	st_le32(&ch->cmd_dep, cmd_dep);}static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch,	unsigned short command, unsigned short req_count,	unsigned int phy_addr, unsigned int cmd_dep){	st_le16(&ch->command, command);	st_le16(&ch->req_count, req_count);	st_le32(&ch->phy_addr, phy_addr);	st_le32(&ch->cmd_dep, cmd_dep);}static volatile struct dbdma_cmd *cmd_geo_setup(	volatile struct dbdma_cmd *c1, int width, int height, int interlace,	int bpp, int clip, struct planb *pb){	int norm = pb->win.norm;	if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0)		return (volatile struct dbdma_cmd *)NULL;	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),							SAA7196_FMTS);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),					saa_regs[norm][SAA7196_FMTS]);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),							SAA7196_DPATH);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),					saa_regs[norm][SAA7196_DPATH]);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even),					bpp | ((clip)? PLANB_CLIPMASK: 0));	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd),					bpp | ((clip)? PLANB_CLIPMASK: 0));	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),							SAA7196_OUTPIX);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),					saa_regs[norm][SAA7196_OUTPIX]);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),							SAA7196_HFILT);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),					saa_regs[norm][SAA7196_HFILT]);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),							SAA7196_OUTLINE);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),					saa_regs[norm][SAA7196_OUTLINE]);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),							SAA7196_VYP);	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),					saa_regs[norm][SAA7196_VYP]);	return c1;}/******************************//* misc. supporting functions *//******************************/static inline void planb_lock(struct planb *pb){	down(&pb->lock);}static inline void planb_unlock(struct planb *pb){	up(&pb->lock);}/***************//* Driver Core *//***************/static int planb_prepare_open(struct planb *pb){	int	i, size;	/* allocate memory for two plus alpha command buffers (size: max lines,	   plus 40 commands handling, plus 1 alignment), plus dummy command buf,	   plus clipmask buffer, plus frame grabbing status */	size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS		* PLANB_DUMMY)*sizeof(struct dbdma_cmd)		+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8		+MAX_GBUFFERS*sizeof(unsigned int);	if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)		return -ENOMEM;	memset ((void *) pb->priv_space, 0, size);	pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)						DBDMA_ALIGN (pb->priv_space);	pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;	pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);	pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;	pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;	for (i = 1; i < MAX_GBUFFERS; i++) {		pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;		pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;	}	pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]						+ PLANB_DUMMY);	pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);	pb->rawbuf = NULL;	pb->rawbuf_size = 0;	pb->grabbing = 0;	for (i = 0; i < MAX_GBUFFERS; i++) {		pb->frame_stat[i] = GBUFFER_UNUSED;		pb->gwidth[i] = 0;		pb->gheight[i] = 0;		pb->gfmt[i] = 0;		pb->gnorm_switch[i] = 0;#ifndef PLANB_GSCANLINE		pb->lsize[i] = 0;		pb->lnum[i] = 0;#endif /* PLANB_GSCANLINE */	}	pb->gcount = 0;	pb->suspend = 0;	pb->last_fr = -999;	pb->prev_last_fr = -999;	/* Reset DMA controllers */	planb_dbdma_stop(&pb->planb_base->ch2);	planb_dbdma_stop(&pb->planb_base->ch1);	return 0;}static void planb_prepare_close(struct planb *pb){	int i;	/* make sure the dma's are idle */	planb_dbdma_stop(&pb->planb_base->ch2);	planb_dbdma_stop(&pb->planb_base->ch1);	/* free kernel memory of command buffers */	if(pb->priv_space != 0) {		kfree (pb->priv_space);		pb->priv_space = 0;		pb->cmd_buff_inited = 0;	}	if(pb->rawbuf) {		for (i = 0; i < pb->rawbuf_size; i++) {			ClearPageReserved(virt_to_page(pb->rawbuf[i]));			free_pages((unsigned long)pb->rawbuf[i], 0);		}		kfree(pb->rawbuf);	}	pb->rawbuf = NULL;}/*****************************//* overlay support functions *//*****************************/static inline int overlay_is_active(struct planb *pb){	unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);	unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);	return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)			&& (caddr < (pb->ch1_cmd_phys + size))			&& (caddr >= (unsigned)pb->ch1_cmd_phys);}static void overlay_start(struct planb *pb){	DEBUG("PlanB: overlay_start()\n");	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {		DEBUG("PlanB: presumably, grabbing is in progress...\n");		planb_dbdma_stop(&pb->planb_base->ch2);		out_le32 (&pb->planb_base->ch2.cmdptr,						virt_to_bus(pb->ch2_cmd));		planb_dbdma_restart(&pb->planb_base->ch2);		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);		tab_cmd_dbdma(pb->last_cmd[pb->last_fr],					DBDMA_NOP | BR_ALWAYS,					virt_to_bus(pb->ch1_cmd));		eieio();		pb->prev_last_fr = pb->last_fr;		pb->last_fr = -2;		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {			IDEBUG("PlanB: became inactive "				"in the mean time... reactivating\n");			planb_dbdma_stop(&pb->planb_base->ch1);			out_le32 (&pb->planb_base->ch1.cmdptr,						virt_to_bus(pb->ch1_cmd));			planb_dbdma_restart(&pb->planb_base->ch1);

⌨️ 快捷键说明

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