Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10033e8e authored by Gilad Broner's avatar Gilad Broner
Browse files

media: dvb: TSPPv2 demux plugin



Add new demux plugin to support TSPPv2 hardware.
The plugin utilizes the HW capabilities of TSPPv2 to offload some
processing such as: TS packet inspection, PID filtering, PES assembly,
Indexing and more.

Change-Id: I820237215e2fd812e2a6974c75b1d57601c59146
Signed-off-by: default avatarGilad Broner <gbroner@codeaurora.org>
parent 3c7fdec0
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ struct dmx_data_ready {
	/*
	 * data_length may be 0 in case of DMX_OK_PES_END or DMX_OK_EOS
	 * and in non-DMX_OK_XXX events. In DMX_OK_PES_END,
	 * data_length is for data comming after the end of PES.
	 * data_length is for data coming after the end of PES.
	 */
	int data_length;

@@ -292,11 +292,13 @@ typedef int (*dmx_section_cb) ( const u8 * buffer1,

typedef int (*dmx_ts_fullness) (
				struct dmx_ts_feed *source,
				int required_space);
				int required_space,
				int wait);

typedef int (*dmx_section_fullness) (
				struct dmx_section_filter *source,
				int required_space);
				int required_space,
				int wait);

/*--------------------------------------------------------------------------*/
/* DVB Front-End */
+183 −23
Original line number Diff line number Diff line
@@ -47,6 +47,58 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");

#define dprintk	if (debug) printk

static inline int dvb_dmxdev_verify_buffer_size(u32 size, u32 max_size,
	u32 size_align)
{
	if (size_align)
		return size <= max_size && !(size % size_align);
	else
		return size <= max_size;
}

static int dvb_filter_verify_buffer_size(struct dmxdev_filter *filter,
	size_t size)
{
	struct dmx_caps caps;

	/*
	 * For backward compatibility, if no demux capabilities can
	 * be retrieved assume size is ok.
	 * Decoder filter buffer size is verified when decoder buffer is set.
	 */
	if (filter->dev->demux->get_caps) {
		filter->dev->demux->get_caps(filter->dev->demux, &caps);

		if (filter->type == DMXDEV_TYPE_SEC)
			return dvb_dmxdev_verify_buffer_size(
				size,
				caps.section.max_size,
				caps.section.size_alignment);

		if (filter->params.pes.output == DMX_OUT_TAP)
			return dvb_dmxdev_verify_buffer_size(
				size,
				caps.pes.max_size,
				caps.pes.size_alignment);

		if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP ||
			filter->params.pes.output == DMX_OUT_TS_TAP) {
			if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188)
				return dvb_dmxdev_verify_buffer_size(
					size,
					caps.recording_188_tsp.max_size,
					caps.recording_188_tsp.size_alignment);

			return dvb_dmxdev_verify_buffer_size(
					size,
					caps.recording_192_tsp.max_size,
					caps.recording_192_tsp.size_alignment);
		}
	}

	return 1;
}

static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
				   const u8 *src, size_t len)
{
@@ -1115,6 +1167,38 @@ static int dvb_dvr_external_input_only(struct dmxdev *dmxdev)
	return is_external_only;
}

static int dvb_dvr_verify_buffer_size(struct dmxdev *dmxdev,
	unsigned int f_flags,
	unsigned long size)
{
	struct dmx_caps caps;
	int tsp_size;

	if (!dmxdev->demux->get_caps)
		return 1;

	if (dmxdev->demux->get_tsp_size)
		tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux);
	else
		tsp_size = 188;

	dmxdev->demux->get_caps(dmxdev->demux, &caps);
	if ((f_flags & O_ACCMODE) == O_RDONLY)
		return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size,
				caps.recording_188_tsp.max_size,
				caps.recording_188_tsp.size_alignment)) ||
			(tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size,
				caps.recording_192_tsp.max_size,
				caps.recording_192_tsp.size_alignment));

	return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size,
		caps.playback_188_tsp.max_size,
		caps.playback_188_tsp.size_alignment)) ||
		(tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size,
			caps.playback_192_tsp.max_size,
			caps.playback_192_tsp.size_alignment));
}

static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
			     size_t count, loff_t *ppos)
{
@@ -1129,7 +1213,8 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
	if (!dmxdev->demux->write)
		return -EOPNOTSUPP;

	if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
	if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags, src->size) ||
		((file->f_flags & O_ACCMODE) == O_RDONLY) ||
		!src->data || !cmdbuf->data ||
		(dvb_dvr_external_input_only(dmxdev) &&
		 (dmxdev->dvr_input_buffer_mode == DMX_BUFFER_MODE_INTERNAL)))
@@ -1203,6 +1288,10 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
	if (dmxdev->exit)
		return -ENODEV;

	if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags,
		dmxdev->dvr_buffer.size))
		return -EINVAL;

	res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer,
				file->f_flags & O_NONBLOCK,
				buf, count, ppos);
@@ -1475,12 +1564,14 @@ static int dvb_dvr_get_event(struct dmxdev *dmxdev,
		 */
		flush_len = dvb_ringbuffer_avail(&dmxdev->dvr_buffer);
		dvb_ringbuffer_flush(&dmxdev->dvr_buffer);
		dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, flush_len);
		dmxdev->dvr_buffer.error = 0;
	}

	spin_unlock_irq(&dmxdev->lock);

	if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
		dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, flush_len);

	/*
	 * in PULL mode, we might be stalling on
	 * event queue, so need to wake-up waiters
@@ -1522,10 +1613,7 @@ static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev,
			 */
			flush_len = dvb_ringbuffer_avail(buf);
			dvb_ringbuffer_flush(buf);
			dvb_dmxdev_notify_data_read(dmxdev->dvr_feed,
				flush_len);
		}

		buf->error = 0;
	}

@@ -1535,6 +1623,9 @@ static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev,
	dmx_buffer_status->write_offset = buf->pwrite;
	dmx_buffer_status->size = buf->size;

	if (dmx_buffer_status->error == -EOVERFLOW)
		dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, flush_len);

	spin_unlock_irq(lock);

	return 0;
@@ -1738,7 +1829,17 @@ static int dvb_dmxdev_set_decoder_buffer_size(
	struct dmxdev_filter *dmxdevfilter,
	unsigned long size)
{
	if (0 == size)
	struct dmx_caps caps;
	struct dmx_demux *demux = dmxdevfilter->dev->demux;

	if (demux->get_caps) {
		demux->get_caps(demux, &caps);
		if (!dvb_dmxdev_verify_buffer_size(size, caps.decoder.max_size,
			caps.decoder.size_alignment))
			return -EINVAL;
	}

	if (size == 0)
		return -EINVAL;

	if (dmxdevfilter->decoder_buffers.buffers_size == size)
@@ -1841,6 +1942,7 @@ static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter,
	struct dmxdev_feed *feed;
	struct dmxdev_feed *ts_feed = NULL;
	struct dmx_caps caps;
	int ret = 0;

	if (!dmxdevfilter->dev->demux->get_caps)
		return -EINVAL;
@@ -1866,7 +1968,7 @@ static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter,
			ts_feed->idx_params = *idx_params;
			if ((dmxdevfilter->state == DMXDEV_STATE_GO) &&
				ts_feed->ts->set_idx_params)
				ts_feed->ts->set_idx_params(
				ret = ts_feed->ts->set_idx_params(
						ts_feed->ts, idx_params);
			break;
		}
@@ -1875,7 +1977,7 @@ static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter,
	if (!found_pid)
		return -EINVAL;

	return 0;
	return ret;
}

static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter,
@@ -2108,7 +2210,7 @@ static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter,
}

static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
				int required_space)
				int required_space, int wait)
{
	struct dmxdev_filter *dmxdevfilter = filter->priv;
	struct dvb_ringbuffer *src;
@@ -2150,6 +2252,9 @@ static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,

		spin_unlock(&dmxdevfilter->dev->lock);

		if (!wait)
			return -ENOSPC;

		ret = wait_event_interruptible(src->queue,
				(!src->data) ||
				((dvb_ringbuffer_free(src) >= required_space) &&
@@ -2165,7 +2270,7 @@ static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,

static int dvb_dmxdev_sec_fullness_callback(
				struct dmx_section_filter *filter,
				int required_space)
				int required_space, int wait)
{
	struct dmxdev_filter *dmxdevfilter = filter->priv;
	struct dvb_ringbuffer *src = &dmxdevfilter->buffer;
@@ -2199,6 +2304,9 @@ static int dvb_dmxdev_sec_fullness_callback(

		spin_unlock(&dmxdevfilter->dev->lock);

		if (!wait)
			return -ENOSPC;

		ret = wait_event_interruptible(src->queue,
				(!src->data) ||
				((dvb_ringbuffer_free(src) >= required_space) &&
@@ -2250,7 +2358,7 @@ static int dvb_dmxdev_get_buffer_status(
		struct dmx_buffer_status *dmx_buffer_status)
{
	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
	ssize_t flush_len;
	ssize_t flush_len = 0;

	/*
	 * Note: Taking the dmxdevfilter->dev->lock spinlock is required only
@@ -2298,7 +2406,6 @@ static int dvb_dmxdev_get_buffer_status(
			 */
			flush_len = dvb_ringbuffer_avail(buf);
			dvb_ringbuffer_flush(buf);
			dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);
		}
		buf->error = 0;
	}
@@ -2311,6 +2418,9 @@ static int dvb_dmxdev_get_buffer_status(

	spin_unlock_irq(&dmxdevfilter->dev->lock);

	if (dmx_buffer_status->error == -EOVERFLOW)
		dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);

	return 0;
}

@@ -2366,7 +2476,6 @@ static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter,
		 */
		flush_len = dvb_ringbuffer_avail(&dmxdevfilter->buffer);
		dvb_ringbuffer_flush(&dmxdevfilter->buffer);
		dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);
		dmxdevfilter->buffer.error = 0;
	} else if (event->type == DMX_EVENT_SECTION_TIMEOUT) {
		/* clear buffer error now that user was notified */
@@ -2387,6 +2496,9 @@ static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter,

	spin_unlock_irq(&dmxdevfilter->dev->lock);

	if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
		dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);

	/*
	 * in PULL mode, we might be stalling on
	 * event queue, so need to wake-up waiters
@@ -2723,6 +2835,23 @@ static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed,
	}

	if (dmx_data_ready->status == DMX_OK_EOS) {
		/* Report partial recording chunk */
		if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP ||
			dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
			&& events->current_event_data_size) {
			event.type = DMX_EVENT_NEW_REC_CHUNK;
			event.params.recording_chunk.offset =
				events->current_event_start_offset;
			event.params.recording_chunk.size =
				events->current_event_data_size;
			events->current_event_start_offset =
				(events->current_event_start_offset +
				events->current_event_data_size) %
				buffer->size;
			events->current_event_data_size = 0;
			dvb_dmxdev_add_event(events, &event);
		}

		dmxdevfilter->eos_state = 1;
		dprintk("dmxdev: DMX_OK_EOS - entering EOS state\n");
		event.type = DMX_EVENT_EOS;
@@ -2856,8 +2985,9 @@ static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed,
			event.params.pes.base_offset =
				events->current_event_start_offset;
			event.params.pes.start_offset =
				events->current_event_start_offset +
				dmx_data_ready->pes_end.start_gap;
				(events->current_event_start_offset +
				dmx_data_ready->pes_end.start_gap) %
				dmxdevfilter->buffer.size;

			event.params.pes.actual_length =
				dmx_data_ready->pes_end.actual_length;
@@ -2895,18 +3025,22 @@ static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed,

	if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) ||
		(dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) {
		if (events->current_event_data_size >=
		while (events->current_event_data_size >=
			dmxdevfilter->params.pes.rec_chunk_size) {
			event.type = DMX_EVENT_NEW_REC_CHUNK;
			event.params.recording_chunk.offset =
				events->current_event_start_offset;

			event.params.recording_chunk.size =
				events->current_event_data_size;
				dmxdevfilter->params.pes.rec_chunk_size;
			events->current_event_data_size =
				events->current_event_data_size -
				dmxdevfilter->params.pes.rec_chunk_size;
			events->current_event_start_offset =
				(events->current_event_start_offset +
				dmxdevfilter->params.pes.rec_chunk_size) %
				buffer->size;

			dvb_dmxdev_add_event(events, &event);

			events->current_event_data_size = 0;
		 }
	}
	spin_unlock(&dmxdevfilter->dev->lock);
@@ -3173,9 +3307,15 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,

	if ((filter->params.pes.output == DMX_OUT_TS_TAP) ||
		(filter->params.pes.output == DMX_OUT_TSDEMUX_TAP))
		if (tsfeed->set_idx_params)
			tsfeed->set_idx_params(
		if (tsfeed->set_idx_params) {
			ret = tsfeed->set_idx_params(
					tsfeed, &feed->idx_params);
			if (ret) {
				dmxdev->demux->release_ts_feed(dmxdev->demux,
					tsfeed);
				return ret;
			}
		}

	ret = tsfeed->start_filtering(tsfeed);
	if (ret < 0) {
@@ -3236,7 +3376,24 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
	if (filter->state >= DMXDEV_STATE_GO)
		dvb_dmxdev_filter_stop(filter);

	if (!dvb_filter_verify_buffer_size(filter, filter->buffer.size))
		return -EINVAL;

	if (!filter->buffer.data) {
		/*
		 * dmxdev buffer in decoder filters is not really used
		 * to exchange data with applications. Decoder buffers
		 * can be set using DMX_SET_DECODER_BUFFER, which
		 * would not update the filter->buffer.data at all.
		 * Therefore we should not treat this filter as
		 * other regular filters and should not fail here
		 * even if user sets the buffer in deocder
		 * filter as external buffer.
		 */
		if ((filter->type == DMXDEV_TYPE_PES) &&
			(filter->params.pes.output == DMX_OUT_DECODER))
			filter->buffer_mode = DMX_BUFFER_MODE_INTERNAL;

		if ((filter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) ||
			dvb_filter_external_buffer_only(dmxdev, filter))
			return -ENOMEM;
@@ -3771,6 +3928,9 @@ static int dvb_dmxdev_set_decoder_buffer(struct dmxdev *dmxdev,
		return -EINVAL;

	dmxdev->demux->get_caps(dmxdev->demux, &caps);
	if (!dvb_dmxdev_verify_buffer_size(buffs->buffers_size,
			caps.decoder.max_size, caps.decoder.size_alignment))
		return -EINVAL;

	if ((buffs->buffers_size == 0) ||
		(buffs->is_linear &&
+110 −71
Original line number Diff line number Diff line
@@ -178,12 +178,7 @@ 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 u16 ts_scrambling_ctrl(const u8 *buf)
static inline u8 ts_scrambling_ctrl(const u8 *buf)
{
	return (buf[3] >> 6) & 0x3;
}
@@ -737,7 +732,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
	return 0;
}

static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
static int dvb_dmx_swfilter_section_one_packet(struct dvb_demux_feed *feed,
					   const u8 *buf)
{
	u8 p, count;
@@ -815,6 +810,60 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
	return 0;
}

/*
 * dvb_dmx_swfilter_section_packet - wrapper for section filtering of single
 * TS packet.
 *
 * @feed: dvb demux feed
 * @buf: buffer containing the TS packet
 * @should_lock: specifies demux locking semantics: if not set, proper demux
 * locking is expected to have been done by the caller.
 *
 * Return error status
 */
int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
	   const u8 *buf, int should_lock)
{
	int ret;

	if (!should_lock && !spin_is_locked(&feed->demux->lock)) {
		pr_err("%s: demux spinlock should have been locked\n",
			__func__);
		return -EINVAL;
	}

	if (should_lock)
		spin_lock(&feed->demux->lock);

	ret = dvb_dmx_swfilter_section_one_packet(feed, buf);

	if (should_lock)
		spin_unlock(&feed->demux->lock);

	return ret;
}
EXPORT_SYMBOL(dvb_dmx_swfilter_section_packet);

static int dvb_demux_idx_event_sort(struct dmx_index_event_info *curr,
	struct dmx_index_event_info *new)
{
	if (curr->match_tsp_num > new->match_tsp_num)
		return 0;

	if (curr->match_tsp_num < new->match_tsp_num)
		return 1;
	/*
	 * In case TSP numbers are equal, sort according to event type giving
	 * priority to PUSI events first, then RAI and finally framing events.
	 */
	if ((curr->type & DMX_IDX_RAI && new->type & DMX_IDX_PUSI) ||
		(!(curr->type & DMX_IDX_PUSI) && !(curr->type & DMX_IDX_RAI) &&
			new->type & (DMX_IDX_PUSI | DMX_IDX_RAI)))
		return 0;

	return 1;
}

static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed,
		struct dmx_index_event_info *idx_event,
		int traverse_from_tail)
@@ -839,8 +888,8 @@ static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed,
	if (traverse_from_tail) {
		list_for_each_entry_reverse(curr_entry,
			&feed->rec_info->idx_info.ready_list, next) {
			if (curr_entry->event.match_tsp_num <=
				idx_event->match_tsp_num) {
			if (dvb_demux_idx_event_sort(&curr_entry->event,
				idx_event)) {
				pos = &curr_entry->next;
				break;
			}
@@ -848,8 +897,8 @@ static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed,
	} else {
		list_for_each_entry(curr_entry,
			&feed->rec_info->idx_info.ready_list, next) {
			if (curr_entry->event.match_tsp_num >
				idx_event->match_tsp_num) {
			if (!dvb_demux_idx_event_sort(&curr_entry->event,
				idx_event)) {
				pos = &curr_entry->next;
				break;
			}
@@ -865,12 +914,17 @@ static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed,
}

int dvb_demux_push_idx_event(struct dvb_demux_feed *feed,
		struct dmx_index_event_info *idx_event)
		struct dmx_index_event_info *idx_event, int should_lock)
{
	int ret;

	if (!should_lock && !spin_is_locked(&feed->demux->lock))
		return -EINVAL;

	if (should_lock)
		spin_lock(&feed->demux->lock);
	ret = dvb_demux_save_idx_event(feed, idx_event, 1);
	if (should_lock)
		spin_unlock(&feed->demux->lock);

	return ret;
@@ -900,10 +954,15 @@ static inline void dvb_dmx_notify_indexing(struct dvb_demux_feed *feed)
	}
}

void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed)
void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock)
{
	if (!should_lock && !spin_is_locked(&feed->demux->lock))
		return;

	if (should_lock)
		spin_lock(&feed->demux->lock);
	dvb_dmx_notify_indexing(feed);
	if (should_lock)
		spin_unlock(&feed->demux->lock);
}
EXPORT_SYMBOL(dvb_dmx_notify_idx_events);
@@ -1078,7 +1137,7 @@ static void dvb_dmx_index(struct dvb_demux_feed *feed,
	/*
	 * if we still did not encounter a TS packet with PUSI indication,
	 * we cannot report index entries yet as we need to provide
	 * the TS packet number with PUSI indication preceeding the TS
	 * the TS packet number with PUSI indication preceding the TS
	 * packet pointed by the reported index entry.
	 */
	if (feed->curr_pusi_tsp_num == (u64)-1) {
@@ -1284,7 +1343,8 @@ static inline int dvb_dmx_swfilter_buffer_check(
				if (likely(was_locked))
					spin_unlock(&demux->lock);

				ret = demux->buffer_ctrl.ts(ts, desired_space);
				ret = demux->buffer_ctrl.ts(ts,
					desired_space, 1);

				if (likely(was_locked))
					spin_lock(&demux->lock);
@@ -1334,7 +1394,8 @@ static inline int dvb_dmx_swfilter_buffer_check(
			if (likely(was_locked))
				spin_unlock(&demux->lock);

			ret = demux->buffer_ctrl.sec(&f->filter, desired_space);
			ret = demux->buffer_ctrl.sec(&f->filter,
				desired_space, 1);

			if (likely(was_locked))
				spin_lock(&demux->lock);
@@ -1398,7 +1459,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
		if (!feed->feed.sec.is_filtering ||
			feed->secure_mode.is_secured)
			break;
		if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
		if (dvb_dmx_swfilter_section_one_packet(feed, buf) < 0)
			feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
		break;

@@ -1508,52 +1569,6 @@ void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
}
EXPORT_SYMBOL(dvb_dmx_swfilter_packet);

void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
			      size_t count)
{
	struct dvb_demux_feed *feed;
	u16 pid = ts_pid(buf);
	struct timespec pre_time;

	if (dvb_demux_performancecheck)
		pre_time = current_kernel_time();

	spin_lock(&demux->lock);

	demux->sw_filter_abort = 0;

	while (count--) {
		if (buf[0] != 0x47) {
			buf += 188;
			continue;
		}

		if (demux->playback_mode == DMX_PB_MODE_PULL)
			if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0)
				break;

		list_for_each_entry(feed, &demux->feed_list, list_head) {
			if (feed->pid != pid)
				continue;

			if (!feed->feed.sec.is_filtering)
				continue;

			if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) {
				feed->feed.sec.seclen = 0;
				feed->feed.sec.secbufp = 0;
			}
		}
		buf += 188;
	}

	spin_unlock(&demux->lock);

	if (dvb_demux_performancecheck)
		demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_section_packets);

void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
			      size_t count)
{
@@ -2041,6 +2056,7 @@ static struct dvb_demux_rec_info *dvb_dmx_alloc_rec_info(
	rec_info->ts_output_count = 0;
	rec_info->idx_info.min_pattern_tsp_num = (u64)-1;
	rec_info->idx_info.pattern_search_feeds_num = 0;
	rec_info->idx_info.indexing_feeds_num = 0;

	return rec_info;
}
@@ -2182,15 +2198,23 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
			mutex_unlock(&demux->mutex);
			return -ENOMEM;
		}
		if (feed->idx_params.enable) {
			dvb_dmx_init_idx_state(feed);
			feed->rec_info->idx_info.indexing_feeds_num++;
			if (demux->set_indexing)
				demux->set_indexing(feed);
		}
	} else {
		feed->pattern_num = 0;
		feed->rec_info = NULL;
	}

	if ((ret = demux->start_feed(feed)) < 0) {
		if ((feed->ts_type & TS_PACKET) &&
		    !(feed->ts_type & TS_PAYLOAD_ONLY)) {
			dvb_dmx_free_rec_info(ts_feed);
			feed->rec_info = NULL;
		}
		mutex_unlock(&demux->mutex);
		return ret;
	}
@@ -2232,6 +2256,8 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
	if (feed->rec_info) {
		if (feed->pattern_num)
			feed->rec_info->idx_info.pattern_search_feeds_num--;
		if (feed->idx_params.enable)
			feed->rec_info->idx_info.indexing_feeds_num--;
		dvb_dmx_free_rec_info(ts_feed);
		feed->rec_info = NULL;
	}
@@ -2368,6 +2394,8 @@ static int dmx_ts_set_idx_params(struct dmx_ts_feed *ts_feed,
{
	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
	struct dvb_demux *dvbdmx = feed->demux;
	int idx_enabled;
	int ret = 0;

	mutex_lock(&dvbdmx->mutex);

@@ -2376,19 +2404,28 @@ static int dmx_ts_set_idx_params(struct dmx_ts_feed *ts_feed,
		mutex_unlock(&dvbdmx->mutex);
		return -EINVAL;
	}

	idx_enabled = feed->idx_params.enable;
	feed->idx_params = *idx_params;

	if (feed->state == DMX_STATE_GO) {
		spin_lock_irq(&dvbdmx->lock);
		if (feed->pattern_num)
			feed->rec_info->idx_info.pattern_search_feeds_num--;
		if (idx_enabled && !idx_params->enable)
			feed->rec_info->idx_info.indexing_feeds_num--;
		if (!idx_enabled && idx_params->enable)
			feed->rec_info->idx_info.indexing_feeds_num++;
		dvb_dmx_init_idx_state(feed);
		spin_unlock_irq(&dvbdmx->lock);

		if (dvbdmx->set_indexing)
			ret = dvbdmx->set_indexing(feed);
	}

	mutex_unlock(&dvbdmx->mutex);

	return 0;
	return ret;
}

static int dvbdmx_ts_feed_oob_cmd(struct dmx_ts_feed *ts_feed,
@@ -2952,11 +2989,13 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
	dvbdmxfeed->demux = dvbdmx;
	dvbdmxfeed->pid = 0xffff;
	dvbdmxfeed->secure_mode.is_secured = 0;
	dvbdmxfeed->tsp_out_format = DMX_TSP_FORMAT_188;
	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;
	dvbdmxfeed->idx_params.enable = 0;

	(*feed) = &dvbdmxfeed->feed.sec;
	(*feed)->is_filtering = 0;
+13 −4
Original line number Diff line number Diff line
@@ -91,6 +91,9 @@ struct dvb_demux_rec_info {
		 */
		u64 min_pattern_tsp_num;

		/* Number of indexing-enabled feeds */
		u8 indexing_feeds_num;

		/* Number of feeds with video pattern search request */
		u8 pattern_search_feeds_num;

@@ -245,6 +248,7 @@ struct dvb_demux {
	void (*convert_ts)(struct dvb_demux_feed *feed,
			 const u8 timestamp[TIMESTAMP_LEN],
			 u64 *timestampIn27Mhz);
	int (*set_indexing)(struct dvb_demux_feed *feed);

	int users;
#define MAX_DVB_DEMUX_USERS 10
@@ -297,8 +301,8 @@ struct dvb_demux {

int dvb_dmx_init(struct dvb_demux *dvbdemux);
void dvb_dmx_release(struct dvb_demux *dvbdemux);
void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
			      size_t count);
int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf,
	int should_lock);
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
			      size_t count);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
@@ -321,13 +325,13 @@ int dvb_dmx_video_pattern_search(
		struct dvb_dmx_video_prefix_size_masks *prefix_size_masks,
		struct dvb_dmx_video_patterns_results *results);
int dvb_demux_push_idx_event(struct dvb_demux_feed *feed,
		struct dmx_index_event_info *idx_event);
		struct dmx_index_event_info *idx_event, int should_lock);
void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed,
		struct dvb_dmx_video_patterns_results *patterns, int pattern,
		u64 curr_stc, u64 prev_stc,
		u64 curr_match_tsp, u64 prev_match_tsp,
		u64 curr_pusi_tsp, u64 prev_pusi_tsp);
void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed);
void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock);
int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
	struct dmx_data_ready *event, int should_lock);

@@ -411,5 +415,10 @@ static inline int dvb_dmx_is_rec_feed(struct dvb_demux_feed *feed)
	return 1;
}

static inline u16 ts_pid(const u8 *buf)
{
	return ((buf[1] & 0x1f) << 8) + buf[2];
}


#endif /* _DVB_DEMUX_H_ */
+1 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@

obj-$(CONFIG_MSM_VIDC_V4L2)     += vidc/
obj-$(CONFIG_MSM_WFD) += wfd/
obj-y += broadcast/
obj-$(CONFIG_DVB_MPQ) += dvb/
obj-$(CONFIG_MSMB_CAMERA) += camera_v2/
obj-y += vcap/
obj-y += broadcast/
Loading