diff options
Diffstat (limited to 'drivers/media/dvb/dvb-core/dvb_demux.c')
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_demux.c | 1302 | 
1 files changed, 0 insertions, 1302 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c deleted file mode 100644 index 4a88a3e4db2..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ /dev/null @@ -1,1302 +0,0 @@ -/* - * dvb_demux.c - DVB kernel demux API - * - * Copyright (C) 2000-2001 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/sched.h> -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/module.h> -#include <linux/poll.h> -#include <linux/string.h> -#include <linux/crc32.h> -#include <asm/uaccess.h> -#include <asm/div64.h> - -#include "dvb_demux.h" - -#define NOBUFS -/* -** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog -*/ -// #define DVB_DEMUX_SECTION_LOSS_LOG - -static int dvb_demux_tscheck; -module_param(dvb_demux_tscheck, int, 0644); -MODULE_PARM_DESC(dvb_demux_tscheck, -		"enable transport stream continuity and TEI check"); - -static int dvb_demux_speedcheck; -module_param(dvb_demux_speedcheck, int, 0644); -MODULE_PARM_DESC(dvb_demux_speedcheck, -		"enable transport stream speed check"); - -#define dprintk_tscheck(x...) do {                              \ -		if (dvb_demux_tscheck && printk_ratelimit())    \ -			printk(x);                              \ -	} while (0) - -/****************************************************************************** - * static inlined helper functions - ******************************************************************************/ - -static inline u16 section_length(const u8 *buf) -{ -	return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; -} - -static inline u16 ts_pid(const u8 *buf) -{ -	return ((buf[1] & 0x1f) << 8) + buf[2]; -} - -static inline u8 payload(const u8 *tsp) -{ -	if (!(tsp[3] & 0x10))	// no payload? -		return 0; - -	if (tsp[3] & 0x20) {	// adaptation field? -		if (tsp[4] > 183)	// corrupted data? -			return 0; -		else -			return 184 - 1 - tsp[4]; -	} - -	return 184; -} - -static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len) -{ -	return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len)); -} - -static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, -			    size_t len) -{ -	memcpy(d, s, len); -} - -/****************************************************************************** - * Software filter functions - ******************************************************************************/ - -static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, -					   const u8 *buf) -{ -	int count = payload(buf); -	int p; -	//int ccok; -	//u8 cc; - -	if (count == 0) -		return -1; - -	p = 188 - count; - -	/* -	cc = buf[3] & 0x0f; -	ccok = ((feed->cc + 1) & 0x0f) == cc; -	feed->cc = cc; -	if (!ccok) -		printk("missed packet!\n"); -	*/ - -	if (buf[1] & 0x40)	// PUSI ? -		feed->peslen = 0xfffa; - -	feed->peslen += count; - -	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); -} - -static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, -					  struct dvb_demux_filter *f) -{ -	u8 neq = 0; -	int i; - -	for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { -		u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i]; - -		if (f->maskandmode[i] & xor) -			return 0; - -		neq |= f->maskandnotmode[i] & xor; -	} - -	if (f->doneq && !neq) -		return 0; - -	return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, -			    NULL, 0, &f->filter, DMX_OK); -} - -static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) -{ -	struct dvb_demux *demux = feed->demux; -	struct dvb_demux_filter *f = feed->filter; -	struct dmx_section_feed *sec = &feed->feed.sec; -	int section_syntax_indicator; - -	if (!sec->is_filtering) -		return 0; - -	if (!f) -		return 0; - -	if (sec->check_crc) { -		section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); -		if (section_syntax_indicator && -		    demux->check_crc32(feed, sec->secbuf, sec->seclen)) -			return -1; -	} - -	do { -		if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0) -			return -1; -	} while ((f = f->next) && sec->is_filtering); - -	sec->seclen = 0; - -	return 0; -} - -static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) -{ -	struct dmx_section_feed *sec = &feed->feed.sec; - -#ifdef DVB_DEMUX_SECTION_LOSS_LOG -	if (sec->secbufp < sec->tsfeedp) { -		int i, n = sec->tsfeedp - sec->secbufp; - -		/* -		 * Section padding is done with 0xff bytes entirely. -		 * Due to speed reasons, we won't check all of them -		 * but just first and last. -		 */ -		if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { -			printk("dvb_demux.c section ts padding loss: %d/%d\n", -			       n, sec->tsfeedp); -			printk("dvb_demux.c pad data:"); -			for (i = 0; i < n; i++) -				printk(" %02x", sec->secbuf[i]); -			printk("\n"); -		} -	} -#endif - -	sec->tsfeedp = sec->secbufp = sec->seclen = 0; -	sec->secbuf = sec->secbuf_base; -} - -/* - * Losless Section Demux 1.4.1 by Emard - * Valsecchi Patrick: - *  - middle of section A  (no PUSI) - *  - end of section A and start of section B - *    (with PUSI pointing to the start of the second section) - * - *  In this case, without feed->pusi_seen you'll receive a garbage section - *  consisting of the end of section A. Basically because tsfeedp - *  is incemented and the use=0 condition is not raised - *  when the second packet arrives. - * - * Fix: - * when demux is started, let feed->pusi_seen = 0 to - * prevent initial feeding of garbage from the end of - * previous section. When you for the first time see PUSI=1 - * then set feed->pusi_seen = 1 - */ -static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, -					      const u8 *buf, u8 len) -{ -	struct dvb_demux *demux = feed->demux; -	struct dmx_section_feed *sec = &feed->feed.sec; -	u16 limit, seclen, n; - -	if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) -		return 0; - -	if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef DVB_DEMUX_SECTION_LOSS_LOG -		printk("dvb_demux.c section buffer full loss: %d/%d\n", -		       sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, -		       DMX_MAX_SECFEED_SIZE); -#endif -		len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; -	} - -	if (len <= 0) -		return 0; - -	demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); -	sec->tsfeedp += len; - -	/* -	 * Dump all the sections we can find in the data (Emard) -	 */ -	limit = sec->tsfeedp; -	if (limit > DMX_MAX_SECFEED_SIZE) -		return -1;	/* internal error should never happen */ - -	/* to be sure always set secbuf */ -	sec->secbuf = sec->secbuf_base + sec->secbufp; - -	for (n = 0; sec->secbufp + 2 < limit; n++) { -		seclen = section_length(sec->secbuf); -		if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE -		    || seclen + sec->secbufp > limit) -			return 0; -		sec->seclen = seclen; -		sec->crc_val = ~0; -		/* dump [secbuf .. secbuf+seclen) */ -		if (feed->pusi_seen) -			dvb_dmx_swfilter_section_feed(feed); -#ifdef DVB_DEMUX_SECTION_LOSS_LOG -		else -			printk("dvb_demux.c pusi not seen, discarding section data\n"); -#endif -		sec->secbufp += seclen;	/* secbufp and secbuf moving together is */ -		sec->secbuf += seclen;	/* redundant but saves pointer arithmetic */ -	} - -	return 0; -} - -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, -					   const u8 *buf) -{ -	u8 p, count; -	int ccok, dc_i = 0; -	u8 cc; - -	count = payload(buf); - -	if (count == 0)		/* count == 0 if no payload or out of range */ -		return -1; - -	p = 188 - count;	/* payload start */ - -	cc = buf[3] & 0x0f; -	ccok = ((feed->cc + 1) & 0x0f) == cc; -	feed->cc = cc; - -	if (buf[3] & 0x20) { -		/* adaption field present, check for discontinuity_indicator */ -		if ((buf[4] > 0) && (buf[5] & 0x80)) -			dc_i = 1; -	} - -	if (!ccok || dc_i) { -#ifdef DVB_DEMUX_SECTION_LOSS_LOG -		printk("dvb_demux.c discontinuity detected %d bytes lost\n", -		       count); -		/* -		 * those bytes under sume circumstances will again be reported -		 * in the following dvb_dmx_swfilter_section_new -		 */ -#endif -		/* -		 * Discontinuity detected. Reset pusi_seen = 0 to -		 * stop feeding of suspicious data until next PUSI=1 arrives -		 */ -		feed->pusi_seen = 0; -		dvb_dmx_swfilter_section_new(feed); -	} - -	if (buf[1] & 0x40) { -		/* PUSI=1 (is set), section boundary is here */ -		if (count > 1 && buf[p] < count) { -			const u8 *before = &buf[p + 1]; -			u8 before_len = buf[p]; -			const u8 *after = &before[before_len]; -			u8 after_len = count - 1 - before_len; - -			dvb_dmx_swfilter_section_copy_dump(feed, before, -							   before_len); -			/* before start of new section, set pusi_seen = 1 */ -			feed->pusi_seen = 1; -			dvb_dmx_swfilter_section_new(feed); -			dvb_dmx_swfilter_section_copy_dump(feed, after, -							   after_len); -		} -#ifdef DVB_DEMUX_SECTION_LOSS_LOG -		else if (count > 0) -			printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); -#endif -	} else { -		/* PUSI=0 (is not set), no section boundary */ -		dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); -	} - -	return 0; -} - -static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, -						const u8 *buf) -{ -	switch (feed->type) { -	case DMX_TYPE_TS: -		if (!feed->feed.ts.is_filtering) -			break; -		if (feed->ts_type & TS_PACKET) { -			if (feed->ts_type & TS_PAYLOAD_ONLY) -				dvb_dmx_swfilter_payload(feed, buf); -			else -				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, -					    DMX_OK); -		} -		if (feed->ts_type & TS_DECODER) -			if (feed->demux->write_to_decoder) -				feed->demux->write_to_decoder(feed, buf, 188); -		break; - -	case DMX_TYPE_SEC: -		if (!feed->feed.sec.is_filtering) -			break; -		if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) -			feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; -		break; - -	default: -		break; -	} -} - -#define DVR_FEED(f)							\ -	(((f)->type == DMX_TYPE_TS) &&					\ -	((f)->feed.ts.is_filtering) &&					\ -	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) - -static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) -{ -	struct dvb_demux_feed *feed; -	u16 pid = ts_pid(buf); -	int dvr_done = 0; - -	if (dvb_demux_speedcheck) { -		struct timespec cur_time, delta_time; -		u64 speed_bytes, speed_timedelta; - -		demux->speed_pkts_cnt++; - -		/* show speed every SPEED_PKTS_INTERVAL packets */ -		if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { -			cur_time = current_kernel_time(); - -			if (demux->speed_last_time.tv_sec != 0 && -					demux->speed_last_time.tv_nsec != 0) { -				delta_time = timespec_sub(cur_time, -						demux->speed_last_time); -				speed_bytes = (u64)demux->speed_pkts_cnt -					* 188 * 8; -				/* convert to 1024 basis */ -				speed_bytes = 1000 * div64_u64(speed_bytes, -						1024); -				speed_timedelta = -					(u64)timespec_to_ns(&delta_time); -				speed_timedelta = div64_u64(speed_timedelta, -						1000000); /* nsec -> usec */ -				printk(KERN_INFO "TS speed %llu Kbits/sec \n", -						div64_u64(speed_bytes, -							speed_timedelta)); -			}; - -			demux->speed_last_time = cur_time; -			demux->speed_pkts_cnt = 0; -		}; -	}; - -	if (demux->cnt_storage && dvb_demux_tscheck) { -		/* check pkt counter */ -		if (pid < MAX_PID) { -			if (buf[1] & 0x80) -				dprintk_tscheck("TEI detected. " -						"PID=0x%x data1=0x%x\n", -						pid, buf[1]); - -			if ((buf[3] & 0xf) != demux->cnt_storage[pid]) -				dprintk_tscheck("TS packet counter mismatch. " -						"PID=0x%x expected 0x%x " -						"got 0x%x\n", -						pid, demux->cnt_storage[pid], -						buf[3] & 0xf); - -			demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; -		}; -		/* end check */ -	}; - -	list_for_each_entry(feed, &demux->feed_list, list_head) { -		if ((feed->pid != pid) && (feed->pid != 0x2000)) -			continue; - -		/* copy each packet only once to the dvr device, even -		 * if a PID is in multiple filters (e.g. video + PCR) */ -		if ((DVR_FEED(feed)) && (dvr_done++)) -			continue; - -		if (feed->pid == pid) -			dvb_dmx_swfilter_packet_type(feed, buf); -		else if (feed->pid == 0x2000) -			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); -	} -} - -void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, -			      size_t count) -{ -	spin_lock(&demux->lock); - -	while (count--) { -		if (buf[0] == 0x47) -			dvb_dmx_swfilter_packet(demux, buf); -		buf += 188; -	} - -	spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); - -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) -{ -	int p = 0, i, j; - -	spin_lock(&demux->lock); - -	if (demux->tsbufp) { -		i = demux->tsbufp; -		j = 188 - i; -		if (count < j) { -			memcpy(&demux->tsbuf[i], buf, count); -			demux->tsbufp += count; -			goto bailout; -		} -		memcpy(&demux->tsbuf[i], buf, j); -		if (demux->tsbuf[0] == 0x47) -			dvb_dmx_swfilter_packet(demux, demux->tsbuf); -		demux->tsbufp = 0; -		p += j; -	} - -	while (p < count) { -		if (buf[p] == 0x47) { -			if (count - p >= 188) { -				dvb_dmx_swfilter_packet(demux, &buf[p]); -				p += 188; -			} else { -				i = count - p; -				memcpy(demux->tsbuf, &buf[p], i); -				demux->tsbufp = i; -				goto bailout; -			} -		} else -			p++; -	} - -bailout: -	spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter); - -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) -{ -	int p = 0, i, j; -	u8 tmppack[188]; - -	spin_lock(&demux->lock); - -	if (demux->tsbufp) { -		i = demux->tsbufp; -		j = 204 - i; -		if (count < j) { -			memcpy(&demux->tsbuf[i], buf, count); -			demux->tsbufp += count; -			goto bailout; -		} -		memcpy(&demux->tsbuf[i], buf, j); -		if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) { -			memcpy(tmppack, demux->tsbuf, 188); -			if (tmppack[0] == 0xB8) -				tmppack[0] = 0x47; -			dvb_dmx_swfilter_packet(demux, tmppack); -		} -		demux->tsbufp = 0; -		p += j; -	} - -	while (p < count) { -		if ((buf[p] == 0x47) || (buf[p] == 0xB8)) { -			if (count - p >= 204) { -				memcpy(tmppack, &buf[p], 188); -				if (tmppack[0] == 0xB8) -					tmppack[0] = 0x47; -				dvb_dmx_swfilter_packet(demux, tmppack); -				p += 204; -			} else { -				i = count - p; -				memcpy(demux->tsbuf, &buf[p], i); -				demux->tsbufp = i; -				goto bailout; -			} -		} else { -			p++; -		} -	} - -bailout: -	spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter_204); - -static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) -{ -	int i; - -	for (i = 0; i < demux->filternum; i++) -		if (demux->filter[i].state == DMX_STATE_FREE) -			break; - -	if (i == demux->filternum) -		return NULL; - -	demux->filter[i].state = DMX_STATE_ALLOCATED; - -	return &demux->filter[i]; -} - -static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) -{ -	int i; - -	for (i = 0; i < demux->feednum; i++) -		if (demux->feed[i].state == DMX_STATE_FREE) -			break; - -	if (i == demux->feednum) -		return NULL; - -	demux->feed[i].state = DMX_STATE_ALLOCATED; - -	return &demux->feed[i]; -} - -static int dvb_demux_feed_find(struct dvb_demux_feed *feed) -{ -	struct dvb_demux_feed *entry; - -	list_for_each_entry(entry, &feed->demux->feed_list, list_head) -		if (entry == feed) -			return 1; - -	return 0; -} - -static void dvb_demux_feed_add(struct dvb_demux_feed *feed) -{ -	spin_lock_irq(&feed->demux->lock); -	if (dvb_demux_feed_find(feed)) { -		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", -		       __func__, feed->type, feed->state, feed->pid); -		goto out; -	} - -	list_add(&feed->list_head, &feed->demux->feed_list); -out: -	spin_unlock_irq(&feed->demux->lock); -} - -static void dvb_demux_feed_del(struct dvb_demux_feed *feed) -{ -	spin_lock_irq(&feed->demux->lock); -	if (!(dvb_demux_feed_find(feed))) { -		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", -		       __func__, feed->type, feed->state, feed->pid); -		goto out; -	} - -	list_del(&feed->list_head); -out: -	spin_unlock_irq(&feed->demux->lock); -} - -static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, -			   enum dmx_ts_pes pes_type, -			   size_t circular_buffer_size, struct timespec timeout) -{ -	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; -	struct dvb_demux *demux = feed->demux; - -	if (pid > DMX_MAX_PID) -		return -EINVAL; - -	if (mutex_lock_interruptible(&demux->mutex)) -		return -ERESTARTSYS; - -	if (ts_type & TS_DECODER) { -		if (pes_type >= DMX_TS_PES_OTHER) { -			mutex_unlock(&demux->mutex); -			return -EINVAL; -		} - -		if (demux->pesfilter[pes_type] && -		    demux->pesfilter[pes_type] != feed) { -			mutex_unlock(&demux->mutex); -			return -EINVAL; -		} - -		demux->pesfilter[pes_type] = feed; -		demux->pids[pes_type] = pid; -	} - -	dvb_demux_feed_add(feed); - -	feed->pid = pid; -	feed->buffer_size = circular_buffer_size; -	feed->timeout = timeout; -	feed->ts_type = ts_type; -	feed->pes_type = pes_type; - -	if (feed->buffer_size) { -#ifdef NOBUFS -		feed->buffer = NULL; -#else -		feed->buffer = vmalloc(feed->buffer_size); -		if (!feed->buffer) { -			mutex_unlock(&demux->mutex); -			return -ENOMEM; -		} -#endif -	} - -	feed->state = DMX_STATE_READY; -	mutex_unlock(&demux->mutex); - -	return 0; -} - -static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) -{ -	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; -	struct dvb_demux *demux = feed->demux; -	int ret; - -	if (mutex_lock_interruptible(&demux->mutex)) -		return -ERESTARTSYS; - -	if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { -		mutex_unlock(&demux->mutex); -		return -EINVAL; -	} - -	if (!demux->start_feed) { -		mutex_unlock(&demux->mutex); -		return -ENODEV; -	} - -	if ((ret = demux->start_feed(feed)) < 0) { -		mutex_unlock(&demux->mutex); -		return ret; -	} - -	spin_lock_irq(&demux->lock); -	ts_feed->is_filtering = 1; -	feed->state = DMX_STATE_GO; -	spin_unlock_irq(&demux->lock); -	mutex_unlock(&demux->mutex); - -	return 0; -} - -static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) -{ -	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; -	struct dvb_demux *demux = feed->demux; -	int ret; - -	mutex_lock(&demux->mutex); - -	if (feed->state < DMX_STATE_GO) { -		mutex_unlock(&demux->mutex); -		return -EINVAL; -	} - -	if (!demux->stop_feed) { -		mutex_unlock(&demux->mutex); -		return -ENODEV; -	} - -	ret = demux->stop_feed(feed); - -	spin_lock_irq(&demux->lock); -	ts_feed->is_filtering = 0; -	feed->state = DMX_STATE_ALLOCATED; -	spin_unlock_irq(&demux->lock); -	mutex_unlock(&demux->mutex); - -	return ret; -} - -static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, -				   struct dmx_ts_feed **ts_feed, -				   dmx_ts_cb callback) -{ -	struct dvb_demux *demux = (struct dvb_demux *)dmx; -	struct dvb_demux_feed *feed; - -	if (mutex_lock_interruptible(&demux->mutex)) -		return -ERESTARTSYS; - -	if (!(feed = dvb_dmx_feed_alloc(demux))) { -		mutex_unlock(&demux->mutex); -		return -EBUSY; -	} - -	feed->type = DMX_TYPE_TS; -	feed->cb.ts = callback; -	feed->demux = demux; -	feed->pid = 0xffff; -	feed->peslen = 0xfffa; -	feed->buffer = NULL; - -	(*ts_feed) = &feed->feed.ts; -	(*ts_feed)->parent = dmx; -	(*ts_feed)->priv = NULL; -	(*ts_feed)->is_filtering = 0; -	(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; -	(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; -	(*ts_feed)->set = dmx_ts_feed_set; - -	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { -		feed->state = DMX_STATE_FREE; -		mutex_unlock(&demux->mutex); -		return -EBUSY; -	} - -	feed->filter->type = DMX_TYPE_TS; -	feed->filter->feed = feed; -	feed->filter->state = DMX_STATE_READY; - -	mutex_unlock(&demux->mutex); - -	return 0; -} - -static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, -				  struct dmx_ts_feed *ts_feed) -{ -	struct dvb_demux *demux = (struct dvb_demux *)dmx; -	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - -	mutex_lock(&demux->mutex); - -	if (feed->state == DMX_STATE_FREE) { -		mutex_unlock(&demux->mutex); -		return -EINVAL; -	} -#ifndef NOBUFS -	vfree(feed->buffer); -	feed->buffer = NULL; -#endif - -	feed->state = DMX_STATE_FREE; -	feed->filter->state = DMX_STATE_FREE; - -	dvb_demux_feed_del(feed); - -	feed->pid = 0xffff; - -	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) -		demux->pesfilter[feed->pes_type] = NULL; - -	mutex_unlock(&demux->mutex); -	return 0; -} - -/****************************************************************************** - * dmx_section_feed API calls - ******************************************************************************/ - -static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, -					    struct dmx_section_filter **filter) -{ -	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; -	struct dvb_demux *dvbdemux = dvbdmxfeed->demux; -	struct dvb_demux_filter *dvbdmxfilter; - -	if (mutex_lock_interruptible(&dvbdemux->mutex)) -		return -ERESTARTSYS; - -	dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); -	if (!dvbdmxfilter) { -		mutex_unlock(&dvbdemux->mutex); -		return -EBUSY; -	} - -	spin_lock_irq(&dvbdemux->lock); -	*filter = &dvbdmxfilter->filter; -	(*filter)->parent = feed; -	(*filter)->priv = NULL; -	dvbdmxfilter->feed = dvbdmxfeed; -	dvbdmxfilter->type = DMX_TYPE_SEC; -	dvbdmxfilter->state = DMX_STATE_READY; -	dvbdmxfilter->next = dvbdmxfeed->filter; -	dvbdmxfeed->filter = dvbdmxfilter; -	spin_unlock_irq(&dvbdemux->lock); - -	mutex_unlock(&dvbdemux->mutex); -	return 0; -} - -static int dmx_section_feed_set(struct dmx_section_feed *feed, -				u16 pid, size_t circular_buffer_size, -				int check_crc) -{ -	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; -	struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - -	if (pid > 0x1fff) -		return -EINVAL; - -	if (mutex_lock_interruptible(&dvbdmx->mutex)) -		return -ERESTARTSYS; - -	dvb_demux_feed_add(dvbdmxfeed); - -	dvbdmxfeed->pid = pid; -	dvbdmxfeed->buffer_size = circular_buffer_size; -	dvbdmxfeed->feed.sec.check_crc = check_crc; - -#ifdef NOBUFS -	dvbdmxfeed->buffer = NULL; -#else -	dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); -	if (!dvbdmxfeed->buffer) { -		mutex_unlock(&dvbdmx->mutex); -		return -ENOMEM; -	} -#endif - -	dvbdmxfeed->state = DMX_STATE_READY; -	mutex_unlock(&dvbdmx->mutex); -	return 0; -} - -static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) -{ -	int i; -	struct dvb_demux_filter *f; -	struct dmx_section_filter *sf; -	u8 mask, mode, doneq; - -	if (!(f = dvbdmxfeed->filter)) -		return; -	do { -		sf = &f->filter; -		doneq = 0; -		for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { -			mode = sf->filter_mode[i]; -			mask = sf->filter_mask[i]; -			f->maskandmode[i] = mask & mode; -			doneq |= f->maskandnotmode[i] = mask & ~mode; -		} -		f->doneq = doneq ? 1 : 0; -	} while ((f = f->next)); -} - -static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) -{ -	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; -	struct dvb_demux *dvbdmx = dvbdmxfeed->demux; -	int ret; - -	if (mutex_lock_interruptible(&dvbdmx->mutex)) -		return -ERESTARTSYS; - -	if (feed->is_filtering) { -		mutex_unlock(&dvbdmx->mutex); -		return -EBUSY; -	} - -	if (!dvbdmxfeed->filter) { -		mutex_unlock(&dvbdmx->mutex); -		return -EINVAL; -	} - -	dvbdmxfeed->feed.sec.tsfeedp = 0; -	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; -	dvbdmxfeed->feed.sec.secbufp = 0; -	dvbdmxfeed->feed.sec.seclen = 0; - -	if (!dvbdmx->start_feed) { -		mutex_unlock(&dvbdmx->mutex); -		return -ENODEV; -	} - -	prepare_secfilters(dvbdmxfeed); - -	if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) { -		mutex_unlock(&dvbdmx->mutex); -		return ret; -	} - -	spin_lock_irq(&dvbdmx->lock); -	feed->is_filtering = 1; -	dvbdmxfeed->state = DMX_STATE_GO; -	spin_unlock_irq(&dvbdmx->lock); - -	mutex_unlock(&dvbdmx->mutex); -	return 0; -} - -static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) -{ -	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; -	struct dvb_demux *dvbdmx = dvbdmxfeed->demux; -	int ret; - -	mutex_lock(&dvbdmx->mutex); - -	if (!dvbdmx->stop_feed) { -		mutex_unlock(&dvbdmx->mutex); -		return -ENODEV; -	} - -	ret = dvbdmx->stop_feed(dvbdmxfeed); - -	spin_lock_irq(&dvbdmx->lock); -	dvbdmxfeed->state = DMX_STATE_READY; -	feed->is_filtering = 0; -	spin_unlock_irq(&dvbdmx->lock); - -	mutex_unlock(&dvbdmx->mutex); -	return ret; -} - -static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, -					   struct dmx_section_filter *filter) -{ -	struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f; -	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; -	struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - -	mutex_lock(&dvbdmx->mutex); - -	if (dvbdmxfilter->feed != dvbdmxfeed) { -		mutex_unlock(&dvbdmx->mutex); -		return -EINVAL; -	} - -	if (feed->is_filtering) -		feed->stop_filtering(feed); - -	spin_lock_irq(&dvbdmx->lock); -	f = dvbdmxfeed->filter; - -	if (f == dvbdmxfilter) { -		dvbdmxfeed->filter = dvbdmxfilter->next; -	} else { -		while (f->next != dvbdmxfilter) -			f = f->next; -		f->next = f->next->next; -	} - -	dvbdmxfilter->state = DMX_STATE_FREE; -	spin_unlock_irq(&dvbdmx->lock); -	mutex_unlock(&dvbdmx->mutex); -	return 0; -} - -static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, -					struct dmx_section_feed **feed, -					dmx_section_cb callback) -{ -	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; -	struct dvb_demux_feed *dvbdmxfeed; - -	if (mutex_lock_interruptible(&dvbdmx->mutex)) -		return -ERESTARTSYS; - -	if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { -		mutex_unlock(&dvbdmx->mutex); -		return -EBUSY; -	} - -	dvbdmxfeed->type = DMX_TYPE_SEC; -	dvbdmxfeed->cb.sec = callback; -	dvbdmxfeed->demux = dvbdmx; -	dvbdmxfeed->pid = 0xffff; -	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; -	dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; -	dvbdmxfeed->feed.sec.tsfeedp = 0; -	dvbdmxfeed->filter = NULL; -	dvbdmxfeed->buffer = NULL; - -	(*feed) = &dvbdmxfeed->feed.sec; -	(*feed)->is_filtering = 0; -	(*feed)->parent = demux; -	(*feed)->priv = NULL; - -	(*feed)->set = dmx_section_feed_set; -	(*feed)->allocate_filter = dmx_section_feed_allocate_filter; -	(*feed)->start_filtering = dmx_section_feed_start_filtering; -	(*feed)->stop_filtering = dmx_section_feed_stop_filtering; -	(*feed)->release_filter = dmx_section_feed_release_filter; - -	mutex_unlock(&dvbdmx->mutex); -	return 0; -} - -static int dvbdmx_release_section_feed(struct dmx_demux *demux, -				       struct dmx_section_feed *feed) -{ -	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; -	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; - -	mutex_lock(&dvbdmx->mutex); - -	if (dvbdmxfeed->state == DMX_STATE_FREE) { -		mutex_unlock(&dvbdmx->mutex); -		return -EINVAL; -	} -#ifndef NOBUFS -	vfree(dvbdmxfeed->buffer); -	dvbdmxfeed->buffer = NULL; -#endif -	dvbdmxfeed->state = DMX_STATE_FREE; - -	dvb_demux_feed_del(dvbdmxfeed); - -	dvbdmxfeed->pid = 0xffff; - -	mutex_unlock(&dvbdmx->mutex); -	return 0; -} - -/****************************************************************************** - * dvb_demux kernel data API calls - ******************************************************************************/ - -static int dvbdmx_open(struct dmx_demux *demux) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - -	if (dvbdemux->users >= MAX_DVB_DEMUX_USERS) -		return -EUSERS; - -	dvbdemux->users++; -	return 0; -} - -static int dvbdmx_close(struct dmx_demux *demux) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - -	if (dvbdemux->users == 0) -		return -ENODEV; - -	dvbdemux->users--; -	//FIXME: release any unneeded resources if users==0 -	return 0; -} - -static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; -	void *p; - -	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) -		return -EINVAL; - -	p = memdup_user(buf, count); -	if (IS_ERR(p)) -		return PTR_ERR(p); -	if (mutex_lock_interruptible(&dvbdemux->mutex)) { -		kfree(p); -		return -ERESTARTSYS; -	} -	dvb_dmx_swfilter(dvbdemux, p, count); -	kfree(p); -	mutex_unlock(&dvbdemux->mutex); - -	if (signal_pending(current)) -		return -EINTR; -	return count; -} - -static int dvbdmx_add_frontend(struct dmx_demux *demux, -			       struct dmx_frontend *frontend) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; -	struct list_head *head = &dvbdemux->frontend_list; - -	list_add(&(frontend->connectivity_list), head); - -	return 0; -} - -static int dvbdmx_remove_frontend(struct dmx_demux *demux, -				  struct dmx_frontend *frontend) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; -	struct list_head *pos, *n, *head = &dvbdemux->frontend_list; - -	list_for_each_safe(pos, n, head) { -		if (DMX_FE_ENTRY(pos) == frontend) { -			list_del(pos); -			return 0; -		} -	} - -	return -ENODEV; -} - -static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - -	if (list_empty(&dvbdemux->frontend_list)) -		return NULL; - -	return &dvbdemux->frontend_list; -} - -static int dvbdmx_connect_frontend(struct dmx_demux *demux, -				   struct dmx_frontend *frontend) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - -	if (demux->frontend) -		return -EINVAL; - -	mutex_lock(&dvbdemux->mutex); - -	demux->frontend = frontend; -	mutex_unlock(&dvbdemux->mutex); -	return 0; -} - -static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - -	mutex_lock(&dvbdemux->mutex); - -	demux->frontend = NULL; -	mutex_unlock(&dvbdemux->mutex); -	return 0; -} - -static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) -{ -	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - -	memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); -	return 0; -} - -int dvb_dmx_init(struct dvb_demux *dvbdemux) -{ -	int i; -	struct dmx_demux *dmx = &dvbdemux->dmx; - -	dvbdemux->cnt_storage = NULL; -	dvbdemux->users = 0; -	dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); - -	if (!dvbdemux->filter) -		return -ENOMEM; - -	dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); -	if (!dvbdemux->feed) { -		vfree(dvbdemux->filter); -		dvbdemux->filter = NULL; -		return -ENOMEM; -	} -	for (i = 0; i < dvbdemux->filternum; i++) { -		dvbdemux->filter[i].state = DMX_STATE_FREE; -		dvbdemux->filter[i].index = i; -	} -	for (i = 0; i < dvbdemux->feednum; i++) { -		dvbdemux->feed[i].state = DMX_STATE_FREE; -		dvbdemux->feed[i].index = i; -	} - -	dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); -	if (!dvbdemux->cnt_storage) -		printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); - -	INIT_LIST_HEAD(&dvbdemux->frontend_list); - -	for (i = 0; i < DMX_TS_PES_OTHER; i++) { -		dvbdemux->pesfilter[i] = NULL; -		dvbdemux->pids[i] = 0xffff; -	} - -	INIT_LIST_HEAD(&dvbdemux->feed_list); - -	dvbdemux->playing = 0; -	dvbdemux->recording = 0; -	dvbdemux->tsbufp = 0; - -	if (!dvbdemux->check_crc32) -		dvbdemux->check_crc32 = dvb_dmx_crc32; - -	if (!dvbdemux->memcopy) -		dvbdemux->memcopy = dvb_dmx_memcopy; - -	dmx->frontend = NULL; -	dmx->priv = dvbdemux; -	dmx->open = dvbdmx_open; -	dmx->close = dvbdmx_close; -	dmx->write = dvbdmx_write; -	dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed; -	dmx->release_ts_feed = dvbdmx_release_ts_feed; -	dmx->allocate_section_feed = dvbdmx_allocate_section_feed; -	dmx->release_section_feed = dvbdmx_release_section_feed; - -	dmx->add_frontend = dvbdmx_add_frontend; -	dmx->remove_frontend = dvbdmx_remove_frontend; -	dmx->get_frontends = dvbdmx_get_frontends; -	dmx->connect_frontend = dvbdmx_connect_frontend; -	dmx->disconnect_frontend = dvbdmx_disconnect_frontend; -	dmx->get_pes_pids = dvbdmx_get_pes_pids; - -	mutex_init(&dvbdemux->mutex); -	spin_lock_init(&dvbdemux->lock); - -	return 0; -} - -EXPORT_SYMBOL(dvb_dmx_init); - -void dvb_dmx_release(struct dvb_demux *dvbdemux) -{ -	vfree(dvbdemux->cnt_storage); -	vfree(dvbdemux->filter); -	vfree(dvbdemux->feed); -} - -EXPORT_SYMBOL(dvb_dmx_release);  | 
