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

📄 dmxdev.c

📁 linux环境下的dvb驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * dmxdev.c - DVB demultiplexer device  * * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de> *		  & Marcus Metzler <marcus@convergence.de>		      for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * 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 Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. * */#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/ioctl.h>#include <linux/wait.h>#include <asm/uaccess.h>#include <asm/system.h>#include "dmxdev.h"#include "dvb_functions.h"MODULE_PARM(debug,"i");static int debug = 0;#define dprintk	if (debug) printkinline struct dmxdev_filter *dvb_dmxdev_file_to_filter(struct file *file){	return (struct dmxdev_filter *) file->private_data;}inline struct dmxdev_dvr *dvb_dmxdev_file_to_dvr(struct dmxdev *dmxdev, struct file *file){	return (struct dmxdev_dvr *) file->private_data;}static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) {	buffer->data=0;	buffer->size=8192;	buffer->pread=0;	buffer->pwrite=0;	buffer->error=0;	init_waitqueue_head(&buffer->queue);}static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len) {	int split;	int free;	int todo;	if (!len)		return 0;	if (!buf->data)		return 0;		free=buf->pread-buf->pwrite;	split=0;	if (free<=0) {		free+=buf->size;		split=buf->size-buf->pwrite;	}	if (len>=free) {		dprintk("dmxdev: buffer overflow\n");		return -1;	}	if (split>=len)		split=0;	todo=len;	if (split) {		memcpy(buf->data + buf->pwrite, src, split);		todo-=split;		buf->pwrite=0;	}	memcpy(buf->data + buf->pwrite, src+split, todo);	buf->pwrite=(buf->pwrite+todo)%buf->size;	return len;}static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src,		int non_blocking, char *buf, size_t count, loff_t *ppos){	unsigned long todo=count;	int split, avail, error;		if (!src->data)		return 0;	if ((error=src->error)) {		src->pwrite=src->pread;		src->error=0;		return error; 	}	if (non_blocking && (src->pwrite==src->pread))		return -EWOULDBLOCK;	while (todo>0) {		if (non_blocking && (src->pwrite==src->pread))			return (count-todo) ? (count-todo) : -EWOULDBLOCK;		if (wait_event_interruptible(src->queue,					     (src->pread!=src->pwrite) ||					     (src->error))<0)			return count-todo;		if ((error=src->error)) {			src->pwrite=src->pread;			src->error=0;			return error; 		}				split=src->size;		avail=src->pwrite - src->pread;		if (avail<0) {			avail+=src->size;			split=src->size - src->pread;		}		if (avail>todo)			avail=todo;		if (split<avail) {			if (copy_to_user(buf, src->data+src->pread, split))				  return -EFAULT;			buf+=split;			src->pread=0;			todo-=split;			avail-=split;		}		if (avail) {			if (copy_to_user(buf, src->data+src->pread, avail))				return -EFAULT;			src->pread = (src->pread + avail) % src->size;			todo-=avail;			buf+=avail;		}	}	return count;}static struct dmx_frontend * get_fe(struct dmx_demux *demux, int type){	struct list_head *head, *pos;	head=demux->get_frontends(demux);	if (!head)		return 0;	list_for_each(pos, head)		if (DMX_FE_ENTRY(pos)->source==type)			return DMX_FE_ENTRY(pos);		return 0;}static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state){	spin_lock_irq(&dmxdevdvr->dev->lock);	dmxdevdvr->state=state;	spin_unlock_irq(&dmxdevdvr->dev->lock);}static int dvb_dvr_open(struct inode *inode, struct file *file){	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;	struct dmx_frontend *front;	dprintk ("function : %s\n", __FUNCTION__);	if (down_interruptible (&dmxdev->mutex))		return -ERESTARTSYS;		if ((file->f_flags&O_ACCMODE)==O_RDWR) {		if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {			up(&dmxdev->mutex);			return -EOPNOTSUPP;		}	}	if ((file->f_flags&O_ACCMODE)==O_RDONLY) {	      dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);	      dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE;	      dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE);	      if (!dmxdev->dvr_buffer.data) {		      up(&dmxdev->mutex);		      return -ENOMEM;	      }	}	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {		dmxdev->dvr_orig_fe=dmxdev->demux->frontend;				if (!dmxdev->demux->write) {			up(&dmxdev->mutex);			return -EOPNOTSUPP;		}				front=get_fe(dmxdev->demux, DMX_MEMORY_FE);				if (!front) {			up(&dmxdev->mutex);			return -EINVAL;		}		dmxdev->demux->disconnect_frontend(dmxdev->demux);			dmxdev->demux->connect_frontend(dmxdev->demux, front);		}	up(&dmxdev->mutex);	return 0;}static int dvb_dvr_release(struct inode *inode, struct file *file){	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;	if (down_interruptible (&dmxdev->mutex))		return -ERESTARTSYS;	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {		dmxdev->demux->disconnect_frontend(dmxdev->demux);			dmxdev->demux->connect_frontend(dmxdev->demux, 						dmxdev->dvr_orig_fe);	}	if ((file->f_flags&O_ACCMODE)==O_RDONLY) {		if (dmxdev->dvr_buffer.data) {			void *mem=dmxdev->dvr_buffer.data;			mb();			spin_lock_irq(&dmxdev->lock);			dmxdev->dvr_buffer.data=0;			spin_unlock_irq(&dmxdev->lock);			vfree(mem);		}	}	up(&dmxdev->mutex);	return 0;}static ssize_t dvb_dvr_write(struct file *file, const char *buf,		size_t count, loff_t *ppos){	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;	int ret;	if (!dmxdev->demux->write)		return -EOPNOTSUPP;	if ((file->f_flags&O_ACCMODE)!=O_WRONLY)		return -EINVAL;	if (down_interruptible (&dmxdev->mutex))		return -ERESTARTSYS;	ret=dmxdev->demux->write(dmxdev->demux, buf, count);	up(&dmxdev->mutex);	return ret;}static ssize_t dvb_dvr_read(struct file *file, char *buf, size_t count,		loff_t *ppos){	struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;	struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv;	int ret;	//down(&dmxdev->mutex);	ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, 			      file->f_flags&O_NONBLOCK, 			      buf, count, ppos);	//up(&dmxdev->mutex);	return ret;}static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter *dmxdevfilter, int state){	spin_lock_irq(&dmxdevfilter->dev->lock);	dmxdevfilter->state=state;	spin_unlock_irq(&dmxdevfilter->dev->lock);}static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsigned long size){	struct dmxdev_buffer *buf=&dmxdevfilter->buffer;	void *mem;	if (buf->size==size)		return 0;	if (dmxdevfilter->state>=DMXDEV_STATE_GO)		return -EBUSY;	spin_lock_irq(&dmxdevfilter->dev->lock);	mem=buf->data;	buf->data=0;	buf->size=size;	buf->pwrite=buf->pread=0;    	spin_unlock_irq(&dmxdevfilter->dev->lock);	if (mem) 		vfree(mem);			if (buf->size) {		mem=vmalloc(dmxdevfilter->buffer.size);		if (!mem)			return -ENOMEM;		spin_lock_irq(&dmxdevfilter->dev->lock);		buf->data=mem;		spin_unlock_irq(&dmxdevfilter->dev->lock);	}	return 0;}static void dvb_dmxdev_filter_timeout(unsigned long data){	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data;		dmxdevfilter->buffer.error=-ETIMEDOUT;	spin_lock_irq(&dmxdevfilter->dev->lock);	dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT;	spin_unlock_irq(&dmxdevfilter->dev->lock);	wake_up(&dmxdevfilter->buffer.queue);}static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter){	struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;  	del_timer(&dmxdevfilter->timer);	if (para->timeout) {		dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout;		dmxdevfilter->timer.data=(unsigned long) dmxdevfilter;		dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000;		add_timer(&dmxdevfilter->timer);	}}static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,			    const u8 *buffer2, size_t buffer2_len,			    struct dmx_section_filter *filter, enum dmx_success success){	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *) filter->priv;	int ret;		if (dmxdevfilter->buffer.error) {		wake_up(&dmxdevfilter->buffer.queue);		return 0;	}	spin_lock(&dmxdevfilter->dev->lock);	if (dmxdevfilter->state!=DMXDEV_STATE_GO) {		spin_unlock(&dmxdevfilter->dev->lock);		return 0;	}	del_timer(&dmxdevfilter->timer);	dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", 		buffer1[0], buffer1[1], 		buffer1[2], buffer1[3], 		buffer1[4], buffer1[5]);	ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);	if (ret==buffer1_len) {		ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);	}	if (ret<0) {		dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;    		dmxdevfilter->buffer.error=-EOVERFLOW;	}	if (dmxdevfilter->params.sec.flags&DMX_ONESHOT)		dmxdevfilter->state=DMXDEV_STATE_DONE;	spin_unlock(&dmxdevfilter->dev->lock);	wake_up(&dmxdevfilter->buffer.queue);	return 0;}static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,		       const u8 *buffer2, size_t buffer2_len,		       struct dmx_ts_feed *feed, enum dmx_success success){	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *) feed->priv;	struct dmxdev_buffer *buffer;	int ret;		spin_lock(&dmxdevfilter->dev->lock);	if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) {		spin_unlock(&dmxdevfilter->dev->lock);		return 0;	}	if (dmxdevfilter->params.pes.output==DMX_OUT_TAP)		buffer=&dmxdevfilter->buffer;	else		buffer=&dmxdevfilter->dev->dvr_buffer;	if (buffer->error) {		spin_unlock(&dmxdevfilter->dev->lock);		wake_up(&buffer->queue);		return 0;	}	ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);	if (ret==buffer1_len) 		ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);	if (ret<0) {		buffer->pwrite=buffer->pread;    		buffer->error=-EOVERFLOW;	}	spin_unlock(&dmxdevfilter->dev->lock);	wake_up(&buffer->queue);	return 0;}/* stop feed but only mark the specified filter as stopped (state set) */static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter){	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);	switch (dmxdevfilter->type) {	case DMXDEV_TYPE_SEC:		del_timer(&dmxdevfilter->timer);		dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);		break;	case DMXDEV_TYPE_PES:		dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);		break;	default:		return -EINVAL;	}	return 0;}/* start feed associated with the specified filter */static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter){	dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO);	switch (filter->type) {	case DMXDEV_TYPE_SEC:		return filter->feed.sec->start_filtering(filter->feed.sec);		break;	case DMXDEV_TYPE_PES:		return filter->feed.ts->start_filtering(filter->feed.ts);		break;	default:		return -EINVAL;	}	return 0;}/* restart section feed if it has filters left associated with it,    otherwise release the feed */static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter){	int i;	struct dmxdev *dmxdev = filter->dev;	u16 pid = filter->params.sec.pid;		for (i=0; i<dmxdev->filternum; i++) 		if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&		    dmxdev->filter[i].type==DMXDEV_TYPE_SEC &&		    dmxdev->filter[i].pid==pid) {			dvb_dmxdev_feed_start(&dmxdev->filter[i]);			return 0;		}		filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);	return 0;}static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter){	if (dmxdevfilter->state<DMXDEV_STATE_GO) 		return 0;	switch (dmxdevfilter->type) {	case DMXDEV_TYPE_SEC:		if (!dmxdevfilter->feed.sec)			break;		dvb_dmxdev_feed_stop(dmxdevfilter);		if (dmxdevfilter->filter.sec)			dmxdevfilter->feed.sec->				release_filter(dmxdevfilter->feed.sec,					       dmxdevfilter->filter.sec);		dvb_dmxdev_feed_restart(dmxdevfilter);		dmxdevfilter->feed.sec=0;		break;	case DMXDEV_TYPE_PES:		if (!dmxdevfilter->feed.ts)			break;		dvb_dmxdev_feed_stop(dmxdevfilter);		dmxdevfilter->dev->demux->			release_ts_feed(dmxdevfilter->dev->demux,					dmxdevfilter->feed.ts);		dmxdevfilter->feed.ts=0;		break;	default:		if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) 			return 0;		return -EINVAL;	}	dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;    	return 0;}static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter){	if (dmxdevfilter->state<DMXDEV_STATE_SET) 		return 0;	dmxdevfilter->type=DMXDEV_TYPE_NONE;	dmxdevfilter->pid=0xffff;	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);	return 0;}static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter){	struct dmxdev *dmxdev = filter->dev;	void *mem;	int ret, i;	if (filter->state < DMXDEV_STATE_SET) 		return -EINVAL;	if (filter->state >= DMXDEV_STATE_GO)		dvb_dmxdev_filter_stop(filter); 	if (!(mem = filter->buffer.data)) {		mem = vmalloc(filter->buffer.size);		spin_lock_irq(&filter->dev->lock);		filter->buffer.data=mem;		spin_unlock_irq(&filter->dev->lock);		if (!filter->buffer.data)			return -ENOMEM;	}	filter->buffer.pwrite = filter->buffer.pread = 0;	switch (filter->type) {	case DMXDEV_TYPE_SEC:	{		struct dmx_sct_filter_params *para=&filter->params.sec;		struct dmx_section_filter **secfilter=&filter->filter.sec;		struct dmx_section_feed **secfeed=&filter->feed.sec;		*secfilter=0;		*secfeed=0;		/* find active filter/feed with same PID */		for (i=0; i<dmxdev->filternum; i++) {			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&			    dmxdev->filter[i].pid == para->pid && 			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {				*secfeed = dmxdev->filter[i].feed.sec;				break;			}		}		/* if no feed found, try to allocate new one */ 

⌨️ 快捷键说明

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