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

📄 av7110.c

📁 linux环境下的dvb驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			len = 2 * 1024;		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);		memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);		av7110->bmpp += len;		av7110->bmplen -= len;		saa7146_wait_for_debi_done(av7110->dev);		saa7146_write(av7110->dev, IER,			      saa7146_read(av7110->dev, IER) | MASK_19);		if (len < 5)			len = 5; /* we want a real DEBI DMA */		iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len + 3) & ~3);		spin_unlock(&av7110->debilock);		return;	case DATA_CI_GET:	case DATA_COMMON_INTERFACE:	case DATA_FSECTION:	case DATA_IPMPE:	case DATA_PIPING:		if (!len || len > 4 * 1024) {			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);			break;		}		/* fall through */	case DATA_TS_RECORD:	case DATA_PES_RECORD:		saa7146_wait_for_debi_done(av7110->dev);		saa7146_write(av7110->dev, IER,			      saa7146_read(av7110->dev, IER) | MASK_19);		irdebi(av7110, DEBISWAB, DPRAM_BASE+rxbuf, 0, len);		spin_unlock(&av7110->debilock);		return;	case DATA_DEBUG_MESSAGE:		saa7146_wait_for_debi_done(av7110->dev);		if (!len || len > 0xff) {			iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);			break;		}		saa7146_write(av7110->dev, IER,			      saa7146_read(av7110->dev, IER) | MASK_19);		irdebi(av7110, DEBISWAB, Reserved, 0, len);		spin_unlock(&av7110->debilock);		return;	case DATA_IRCOMMAND:		IR_handle(av7110,			  swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		break;	default:		printk("gpioirq unknown type=%d len=%d\n",		       av7110->debitype, av7110->debilen);		break;	}	ARM_ClearMailBox(av7110);	av7110->debitype = -1;	spin_unlock(&av7110->debilock);}#ifdef CONFIG_DVB_AV7110_OSDstatic int dvb_osd_ioctl(struct inode *inode, struct file *file,			 unsigned int cmd, void *parg){	struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;	struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;	DEB_EE(("av7110: %p\n", av7110));	if (cmd == OSD_SEND_CMD)		return av7110_osd_cmd(av7110, (osd_cmd_t *) parg);	return -EINVAL;}static struct file_operations dvb_osd_fops = {	.owner		= THIS_MODULE,	.ioctl		= dvb_generic_ioctl,	.open		= dvb_generic_open,	.release	= dvb_generic_release,};static struct dvb_device dvbdev_osd = {	.priv		= 0,	.users		= 1,	.writers	= 1,	.fops		= &dvb_osd_fops,	.kernel_ioctl	= dvb_osd_ioctl,};#endif /* CONFIG_DVB_AV7110_OSD */static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,			  u16 subpid, u16 pcrpid){	DEB_EE(("av7110: %p\n", av7110));	if (vpid == 0x1fff || apid == 0x1fff ||	    ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) {		vpid = apid = ttpid = subpid = pcrpid = 0;		av7110->pids[DMX_PES_VIDEO] = 0;		av7110->pids[DMX_PES_AUDIO] = 0;		av7110->pids[DMX_PES_TELETEXT] = 0;		av7110->pids[DMX_PES_PCR] = 0;	}	return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5,			     pcrpid, vpid, apid, ttpid, subpid);}void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,		u16 subpid, u16 pcrpid){	DEB_EE(("av7110: %p\n", av7110));	if (down_interruptible(&av7110->pid_mutex))		return;	if (!(vpid & 0x8000))		av7110->pids[DMX_PES_VIDEO] = vpid;	if (!(apid & 0x8000))		av7110->pids[DMX_PES_AUDIO] = apid;	if (!(ttpid & 0x8000))		av7110->pids[DMX_PES_TELETEXT] = ttpid;	if (!(pcrpid & 0x8000))		av7110->pids[DMX_PES_PCR] = pcrpid;	av7110->pids[DMX_PES_SUBTITLE] = 0;	if (av7110->fe_synced) {		pcrpid = av7110->pids[DMX_PES_PCR];		SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);	}	up(&av7110->pid_mutex);}/****************************************************************************** * hardware filter functions ******************************************************************************/static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter){	struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;	struct av7110 *av7110 = (struct av7110 *) dvbdmxfeed->demux->priv;	u16 buf[20];	int ret, i;	u16 handle;//	u16 mode=0x0320;	u16 mode=0xb96a;	DEB_EE(("av7110: %p\n", av7110));	if (dvbdmxfilter->type == DMX_TYPE_SEC) {		if (hw_sections) {			buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |				dvbdmxfilter->maskandmode[0];			for (i = 3; i < 18; i++)				buf[i + 4 - 2] =					(dvbdmxfilter->filter.filter_value[i] << 8) |					dvbdmxfilter->maskandmode[i];			mode = 4;		}	} else if ((dvbdmxfeed->ts_type & TS_PACKET) &&		   !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) {		av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed);	}	buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter;	buf[1] = 16;	buf[2] = dvbdmxfeed->pid;	buf[3] = mode;	ret = av7110_fw_request(av7110, buf, 20, &handle, 1);	if (ret < 0) {		printk("StartHWFilter error\n");		return ret;	}	av7110->handle2filter[handle] = dvbdmxfilter;	dvbdmxfilter->hw_handle = handle;	return ret;}static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter){	struct av7110 *av7110 = (struct av7110 *) dvbdmxfilter->feed->demux->priv;	u16 buf[3];	u16 answ[2];	int ret;	u16 handle;	DEB_EE(("av7110: %p\n", av7110));	handle = dvbdmxfilter->hw_handle;	if (handle > 32) {		DEB_S(("dvb: StopHWFilter tried to stop invalid filter %d.\n",		       handle));		DEB_S(("dvb: filter type = %d\n", dvbdmxfilter->type));		return 0;	}	av7110->handle2filter[handle] = NULL;	buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter;	buf[1] = 1;	buf[2] = handle;	ret = av7110_fw_request(av7110, buf, 3, answ, 2);	if (ret)		printk("StopHWFilter error\n");	if (answ[1] != handle) {		DEB_S(("dvb: filter %d shutdown error :%d\n", handle, answ[1]));		ret = -1;	}	return ret;}static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed){	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;	struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;	u16 *pid = dvbdmx->pids, npids[5];	int i;	DEB_EE(("av7110: %p\n", av7110));	npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;	i = dvbdmxfeed->pes_type;	npids[i] = (pid[i]&0x8000) ? 0 : pid[i];	if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {		npids[i] = 0;		ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);		StartHWFilter(dvbdmxfeed->filter);		return;	}	if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4)		ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);	if (dvbdmxfeed->pes_type < 2 && npids[0])		if (av7110->fe_synced)			av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);	if ((dvbdmxfeed->ts_type & TS_PACKET)) {		if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))			av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);		if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))			av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);	}}static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed){	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;	struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;	u16 *pid = dvbdmx->pids, npids[5];	int i;	DEB_EE(("av7110: %p\n", av7110));	if (dvbdmxfeed->pes_type <= 1) {		av7110_av_stop(av7110, dvbdmxfeed->pes_type ?  RP_VIDEO : RP_AUDIO);		if (!av7110->rec_mode)			dvbdmx->recording = 0;		if (!av7110->playing)			dvbdmx->playing = 0;	}	npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;	i = dvbdmxfeed->pes_type;	switch (i) {	case 2: //teletext		if (dvbdmxfeed->ts_type & TS_PACKET)			StopHWFilter(dvbdmxfeed->filter);		npids[2] = 0;		break;	case 0:	case 1:	case 4:		if (!pids_off)			return;		npids[i] = (pid[i]&0x8000) ? 0 : pid[i];		break;	}	ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);}static int av7110_start_feed(struct dvb_demux_feed *feed){	struct dvb_demux *demux = feed->demux;	struct av7110 *av7110 = (struct av7110 *) demux->priv;	DEB_EE(("av7110: %p\n", av7110));	if (!demux->dmx.frontend)		return -EINVAL;	if (feed->pid > 0x1fff)		return -EINVAL;	if (feed->type == DMX_TYPE_TS) {		if ((feed->ts_type & TS_DECODER) &&		    (feed->pes_type < DMX_TS_PES_OTHER)) {			switch (demux->dmx.frontend->source) {			case DMX_MEMORY_FE:				if (feed->ts_type & TS_DECODER)				       if (feed->pes_type < 2 &&					   !(demux->pids[0] & 0x8000) &&					   !(demux->pids[1] & 0x8000)) {					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);					       av7110_av_start_play(av7110,RP_AV);					       demux->playing = 1;					}				break;			default:				dvb_feed_start_pid(feed);				break;			}		} else if ((feed->ts_type & TS_PACKET) &&			   (demux->dmx.frontend->source != DMX_MEMORY_FE)) {			StartHWFilter(feed->filter);		}	}	if (feed->type == DMX_TYPE_SEC) {		int i;		for (i = 0; i < demux->filternum; i++) {			if (demux->filter[i].state != DMX_STATE_READY)				continue;			if (demux->filter[i].type != DMX_TYPE_SEC)				continue;			if (demux->filter[i].filter.parent != &feed->feed.sec)				continue;			demux->filter[i].state = DMX_STATE_GO;			if (demux->dmx.frontend->source != DMX_MEMORY_FE)				StartHWFilter(&demux->filter[i]);		}	}	return 0;}static int av7110_stop_feed(struct dvb_demux_feed *feed){	struct dvb_demux *demux = feed->demux;	struct av7110 *av7110 = (struct av7110 *) demux->priv;	DEB_EE(("av7110: %p\n", av7110));	if (feed->type == DMX_TYPE_TS) {		if (feed->ts_type & TS_DECODER) {			if (feed->pes_type >= DMX_TS_PES_OTHER ||			    !demux->pesfilter[feed->pes_type])				return -EINVAL;			demux->pids[feed->pes_type] |= 0x8000;			demux->pesfilter[feed->pes_type] = 0;		}		if (feed->ts_type & TS_DECODER &&		    feed->pes_type < DMX_TS_PES_OTHER) {			dvb_feed_stop_pid(feed);		} else			if ((feed->ts_type & TS_PACKET) &&			    (demux->dmx.frontend->source != DMX_MEMORY_FE))				StopHWFilter(feed->filter);	}	if (feed->type == DMX_TYPE_SEC) {		int i;		for (i=0; i<demux->filternum; i++)			if (demux->filter[i].state == DMX_STATE_GO &&			    demux->filter[i].filter.parent == &feed->feed.sec) {				demux->filter[i].state = DMX_STATE_READY;				if (demux->dmx.frontend->source != DMX_MEMORY_FE)					StopHWFilter(&demux->filter[i]);		}	}	return 0;}static void restart_feeds(struct av7110 *av7110){	struct dvb_demux *dvbdmx = &av7110->demux;	struct dvb_demux_feed *feed;	int mode;	int i;	DEB_EE(("av7110: %p\n", av7110));	mode = av7110->playing;	av7110->playing = 0;	av7110->rec_mode = 0;	for (i = 0; i < dvbdmx->filternum; i++) {		feed = &dvbdmx->feed[i];		if (feed->state == DMX_STATE_GO)			av7110_start_feed(feed);	}	if (mode)		av7110_av_start_play(av7110, mode);}static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,		       uint64_t *stc, unsigned int *base){	int ret;	u16 fwstc[4];	u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC);	struct dvb_demux *dvbdemux;	struct av7110 *av7110;	/* pointer casting paranoia... */	if (!demux)		BUG();	dvbdemux = (struct dvb_demux *) demux->priv;	if (!dvbdemux)		BUG();	av7110 = (struct av7110 *) dvbdemux->priv;	DEB_EE(("av7110: %p\n", av7110));	if (num != 0)		return -EINVAL;	ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);	if (ret) {		printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__);		return -EIO;	}	DEB_EE(("av7110: fwstc = %04hx %04hx %04hx %04hx\n",		fwstc[0], fwstc[1], fwstc[2], fwstc[3]));	*stc =	(((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) |		(((uint64_t)  fwstc[1]) << 16) | ((uint64_t) fwstc[0]);	*base = 1;	DEB_EE(("av7110: stc = %lu\n", (unsigned long)*stc));	return 0;}/****************************************************************************** * SEC device file operations ******************************************************************************/static int av7110_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg){	struct av7110 *av7110 = fe->before_after_data;	DEB_EE(("av7110: %p\n", av7110));	switch (cmd) {	case FE_SET_TONE:		switch ((fe_sec_tone_mode_t) arg) {		case SEC_TONE_ON:			Set22K(av7110, 1);			break;		case SEC_TONE_OFF:			Set22K(av7110, 0);			break;		default:			return -EINVAL;		};		break;	case FE_DISEQC_SEND_MASTER_CMD:	{		struct dvb_diseqc_master_cmd *cmd = arg;		av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);		break;	}	case FE_DISEQC_SEND_BURST:		av7110_diseqc_send(av7110, 0, NULL, (unsigned long) arg);		break;	default:		return -EOPNOTSUPP;	};	return 0;}static void av7110_before_after_tune(fe_status_t s, void *data){	struct av7110 *av7110 = data;	DEB_EE(("av7110: %p\n", av7110));	av7110->fe_synced = (s & FE_HAS_LOCK) ? 1 : 0;	if (av7110->playing)		return;	if (down_interruptible(&av7110->pid_mutex))		return;	if (av7110->fe_synced) {		SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],			av7110->pids[DMX_PES_AUDIO],			av7110->pids[DMX_PES_TELETEXT], 0,			av7110->pids[DMX_PES_PCR]);		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);	} else {		SetPIDs(av7110, 0, 0, 0, 0, 0);		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);	}	up(&av7110->pid_mutex);}static int av7110_register(struct av7110 *av7110){	int ret, i;	struct dvb_demux *dvbdemux = &av7110->demux;	DEB_EE(("av7110: %p\n", av7110));	if (av7110->registered)		return -1;	av7110->registered = 1;	dvb_add_frontend_notifier (av7110->dvb_adapter,				   av7110_before_after_tune, av7110);	/**	 *   init DiSEqC stuff	 */	dvb_add_frontend_ioctls (av7110->dvb_adapter,				 av7110_diseqc_ioctl, NULL, av7110);	dvbdemux->priv = (void *) av7110;	for (i = 0; i < 32; i++)		av7110->handle2filter[i] = NULL;	dvbdemux->filternum = 32;	dvbdemux->feednum = 32;	dvbdemux->start_feed = av7110_start_feed;	dvbdemux->stop_feed = av7110_stop_feed;	dvbdemux->write_to_decoder = av7110_write_to_decoder;	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |				      DMX_MEMORY_BASED_FILTERING);	dvb_dmx_init(&av7110->demux);	av7110->demux.dmx.get_stc = dvb_get_stc;	av7110->dmxdev.filternum = 32;	av7110->dmxdev.demux = &dvbdemux->dmx;	av7110->dmxdev.capabilities = 0;

⌨️ 快捷键说明

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