Merge "media: dvb: External buffers support for decoder filters"
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index f802a38..ed657d7 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -188,6 +188,7 @@
struct dmx_demux *parent; /* Back-pointer */
struct data_buffer buffer;
void *priv; /* Pointer to private data of the API client */
+ struct dmx_decoder_buffers *decoder_buffers;
int (*set) (struct dmx_ts_feed *feed,
u16 pid,
int type,
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 507c014..e956170 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -31,7 +31,7 @@
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <linux/mm.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include "dmxdev.h"
@@ -41,6 +41,8 @@
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+#define DMX_DEFAULT_DECODER_BUFFER_SIZE (32768)
+
#define dprintk if (debug) printk
static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
@@ -1351,18 +1353,27 @@
return 0;
}
-static int dvb_dmxdev_set_pes_buffer_size(struct dmxdev_filter *dmxdevfilter,
- unsigned long size)
+static int dvb_dmxdev_set_decoder_buffer_size(
+ struct dmxdev_filter *dmxdevfilter,
+ unsigned long size)
{
- if (dmxdevfilter->pes_buffer_size == size)
- return 0;
- if (!size)
+ if (0 == size)
return -EINVAL;
+
+ if (dmxdevfilter->decoder_buffers.buffers_size == size)
+ return 0;
+
if (dmxdevfilter->state >= DMXDEV_STATE_GO)
return -EBUSY;
- dmxdevfilter->pes_buffer_size = size;
-
+ /*
+ * In case decoder buffers were already set before to some external
+ * buffers, setting the decoder buffer size alone implies transition
+ * to internal buffer mode.
+ */
+ dmxdevfilter->decoder_buffers.buffers_size = size;
+ dmxdevfilter->decoder_buffers.buffers_num = 0;
+ dmxdevfilter->decoder_buffers.is_linear = 0;
return 0;
}
@@ -1524,8 +1535,6 @@
{
struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
- if (!buf->data)
- return -EINVAL;
spin_lock_irq(&dmxdevfilter->dev->lock);
@@ -1550,6 +1559,11 @@
return ret;
}
+ if (!buf->data) {
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+ return -EINVAL;
+ }
+
dmx_buffer_status->error = buf->error;
if (buf->error) {
if (buf->error == -EOVERFLOW) {
@@ -2253,6 +2267,9 @@
if (!dmxdev->dvr_feeds_count)
dmxdev->dvr_feed = filter;
dmxdev->dvr_feeds_count++;
+ } else if (filter->params.pes.output == DMX_OUT_DECODER) {
+ tsfeed->decoder_buffers = &filter->decoder_buffers;
+ tsfeed->buffer.priv_handle = filter->priv_buff_handle;
} else {
tsfeed->buffer.ringbuff = &filter->buffer;
tsfeed->buffer.priv_handle = filter->priv_buff_handle;
@@ -2269,7 +2286,8 @@
ret = tsfeed->set(tsfeed, feed->pid,
ts_type, ts_pes,
- filter->pes_buffer_size, timeout);
+ filter->decoder_buffers.buffers_size,
+ timeout);
if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
return ret;
@@ -2477,6 +2495,11 @@
mutex_init(&dmxdevfilter->mutex);
file->private_data = dmxdevfilter;
+ memset(&dmxdevfilter->decoder_buffers,
+ 0,
+ sizeof(dmxdevfilter->decoder_buffers));
+ dmxdevfilter->decoder_buffers.buffers_size =
+ DMX_DEFAULT_DECODER_BUFFER_SIZE;
dmxdevfilter->buffer_mode = DMX_BUFFER_MODE_INTERNAL;
dmxdevfilter->priv_buff_handle = NULL;
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
@@ -2486,10 +2509,7 @@
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
- dmxdevfilter->pes_buffer_size = 32768;
-
dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
-
dvbdev->users++;
mutex_unlock(&dmxdev->mutex);
@@ -2515,7 +2535,10 @@
vfree(mem);
}
- if ((dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+ /* Decoder filters do not map buffers via priv_buff_handle */
+ if ((DMXDEV_TYPE_PES == dmxdevfilter->type) &&
+ (DMX_OUT_DECODER != dmxdevfilter->params.pes.output) &&
+ (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
(dmxdevfilter->priv_buff_handle)) {
dmxdev->demux->unmap_buffer(dmxdev->demux,
dmxdevfilter->priv_buff_handle);
@@ -2653,6 +2676,47 @@
return 0;
}
+static int dvb_dmxdev_set_decoder_buffer(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter,
+ struct dmx_decoder_buffers *buffs)
+{
+ int i;
+ struct dmx_decoder_buffers *dec_buffs;
+ struct dmx_caps caps;
+
+ if (NULL == dmxdev || NULL == filter || NULL == buffs)
+ return -EINVAL;
+
+ dec_buffs = &filter->decoder_buffers;
+ dmxdev->demux->get_caps(dmxdev->demux, &caps);
+
+ if (0 == buffs->buffers_size ||
+ (buffs->is_linear && buffs->buffers_num <= 1))
+ return -EINVAL;
+
+ if (0 == buffs->buffers_num) {
+ /* Internal mode - linear buffers not supported in this mode */
+ if (!(caps.decoder.flags & DMX_BUFFER_INTERNAL_SUPPORT) ||
+ buffs->is_linear)
+ return -EINVAL;
+ } else {
+ /* External buffer(s) mode */
+ if ((!(caps.decoder.flags & DMX_BUFFER_LINEAR_GROUP_SUPPORT) &&
+ buffs->buffers_num > 1) ||
+ !(caps.decoder.flags & DMX_BUFFER_EXTERNAL_SUPPORT) ||
+ buffs->buffers_num > caps.decoder.max_buffer_num)
+ return -EINVAL;
+
+ dec_buffs->is_linear = buffs->is_linear;
+ dec_buffs->buffers_num = buffs->buffers_num;
+ dec_buffs->buffers_size = buffs->buffers_size;
+ for (i = 0; i < dec_buffs->buffers_num; i++)
+ dec_buffs->handles[i] = buffs->handles[i];
+ }
+
+ return 0;
+}
+
static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
struct file *file, char __user *buf,
size_t count, loff_t *ppos)
@@ -2896,7 +2960,7 @@
return -ERESTARTSYS;
}
- ret = dvb_dmxdev_set_pes_buffer_size(dmxdevfilter, arg);
+ ret = dvb_dmxdev_set_decoder_buffer_size(dmxdevfilter, arg);
mutex_unlock(&dmxdevfilter->mutex);
break;
@@ -2944,6 +3008,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_DECODER_BUFFER:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_set_decoder_buffer(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index d1c1cc3..0f7da1b 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -119,9 +119,6 @@
struct mutex mutex;
- /* relevent for decoder PES */
- unsigned long pes_buffer_size;
-
/* for recording output */
enum dmx_tsp_format_t dmx_tsp_format;
u32 rec_chunk_size;
@@ -130,6 +127,9 @@
struct timer_list timer;
int todo;
u8 secheader[3];
+
+ /* Decoder buffer(s) related */
+ struct dmx_decoder_buffers decoder_buffers;
};
struct dmxdev {
diff --git a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
index f779851..6840858 100644
--- a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -526,3 +526,34 @@
}
EXPORT_SYMBOL(mpq_streambuffer_data_avail);
+int mpq_streambuffer_get_data_rw_offset(
+ struct mpq_streambuffer *sbuff,
+ u32 *read_offset,
+ u32 *write_offset)
+{
+ if (NULL == sbuff)
+ return -EINVAL;
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ if (read_offset)
+ *read_offset = sbuff->raw_data.pread;
+ if (write_offset)
+ *write_offset = sbuff->raw_data.pwrite;
+ } else {
+ struct mpq_streambuffer_buffer_desc *desc;
+
+ if (read_offset) {
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pread];
+ *read_offset = desc->read_ptr;
+ }
+ if (write_offset) {
+ desc = (struct mpq_streambuffer_buffer_desc *)
+ &sbuff->raw_data.data[sbuff->raw_data.pwrite];
+ *write_offset = desc->write_ptr;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_get_data_rw_offset);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 2a60840..d766862 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -39,6 +39,11 @@
static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
module_param(mpq_demux_device_num, int, S_IRUGO);
+/* ION head ID to be used when calling ion_alloc for video decoder buffer */
+static int video_ion_alloc_heap = ION_CP_MM_HEAP_ID;
+module_param(video_ion_alloc_heap, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(video_ion_alloc_heap, "ION heap ID for allocation");
+
/**
* Maximum allowed framing pattern size
*/
@@ -295,8 +300,7 @@
(patterns[j].size - current_size))) {
MPQ_DVB_DBG_PRINT(
- "%s: Found matching pattern"
- "using prefix of size %d\n",
+ "%s: Found matching pattern using prefix of size %d\n",
__func__, current_size);
/*
* pattern found using prefix at the
@@ -787,14 +791,81 @@
}
EXPORT_SYMBOL(mpq_dmx_set_source);
+/**
+ * Takes an ION allocated buffer's file descriptor and handles the details of
+ * mapping it into kernel memory and obtaining an ION handle for it.
+ * Internal helper function.
+ *
+ * @client: ION client
+ * @handle: ION file descriptor to map
+ * @priv_handle: returned ION handle. Must be freed when no longer needed
+ * @kernel_mem: returned kernel mapped pointer
+ *
+ * Note: mapping might not be possible in secured heaps/buffers, and so NULL
+ * might be returned in kernel_mem
+ *
+ * Return errors status
+ */
+static int mpq_map_buffer_to_kernel(
+ struct ion_client *client,
+ int handle,
+ struct ion_handle **priv_handle,
+ void **kernel_mem)
+{
+ struct ion_handle *ion_handle;
+ unsigned long ionflag = 0;
+ int ret;
+
+ if (NULL == client || priv_handle == NULL || kernel_mem == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ ion_handle = ion_import_dma_buf(client, handle);
+ if (IS_ERR_OR_NULL(ion_handle)) {
+ ret = PTR_ERR(ion_handle);
+ MPQ_DVB_ERR_PRINT("%s: ion_import_dma_buf failed %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+
+ goto map_buffer_failed;
+ }
+
+ ret = ion_handle_get_flags(client, ion_handle, &ionflag);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+ __func__, ret);
+ goto map_buffer_failed_free_buff;
+ }
+
+ if (ionflag & ION_SECURE) {
+ MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
+ *kernel_mem = NULL;
+ } else {
+ *kernel_mem = ion_map_kernel(client, ion_handle);
+ if (*kernel_mem == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto map_buffer_failed_free_buff;
+ }
+ }
+
+ *priv_handle = ion_handle;
+ return 0;
+
+map_buffer_failed_free_buff:
+ ion_free(client, ion_handle);
+map_buffer_failed:
+ return ret;
+}
+
int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
void **priv_handle, void **kernel_mem)
{
struct dvb_demux *dvb_demux = demux->priv;
struct mpq_demux *mpq_demux;
- struct ion_handle *ion_handle;
- unsigned long ionflag = 0;
- int ret;
if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
(priv_handle == NULL) || (kernel_mem == NULL)) {
@@ -808,47 +879,10 @@
return -EINVAL;
}
- ion_handle = ion_import_dma_buf(mpq_demux->ion_client,
- dmx_buffer->handle);
- if (IS_ERR_OR_NULL(ion_handle)) {
- ret = PTR_ERR(ion_handle);
- if (!ret)
- ret = -ENOMEM;
-
- MPQ_DVB_ERR_PRINT("%s: ion_import_dma_buf failed %d\n",
- __func__, ret);
- goto map_buffer_failed;
- }
-
- ret = ion_handle_get_flags(mpq_demux->ion_client, ion_handle, &ionflag);
- if (ret) {
- MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
- __func__, ret);
- goto map_buffer_failed_free_buff;
- }
-
- if (ionflag & ION_SECURE) {
- MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
- /* TBD: Set buffer as secured */
- *kernel_mem = NULL;
- } else {
- *kernel_mem = ion_map_kernel(mpq_demux->ion_client,
- ion_handle);
- if (*kernel_mem == NULL) {
- MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
- __func__);
- ret = -ENOMEM;
- goto map_buffer_failed_free_buff;
- }
- }
-
- *priv_handle = (void *)ion_handle;
- return 0;
-
-map_buffer_failed_free_buff:
- ion_free(mpq_demux->ion_client, ion_handle);
-map_buffer_failed:
- return ret;
+ return mpq_map_buffer_to_kernel(
+ mpq_demux->ion_client,
+ dmx_buffer->handle,
+ (struct ion_handle **)priv_handle, kernel_mem);
}
EXPORT_SYMBOL(mpq_dmx_map_buffer);
@@ -889,18 +923,256 @@
}
EXPORT_SYMBOL(mpq_dmx_unmap_buffer);
+/**
+ * Handles the details of internal decoder buffer allocation via ION.
+ * Internal helper function.
+ * @feed_data: decoder feed object
+ * @dec_buffs: buffer information
+ * @client: ION client
+ *
+ * Return error status
+ */
+static int mpq_dmx_init_internal_buffers(
+ struct mpq_video_feed_info *feed_data,
+ struct dmx_decoder_buffers *dec_buffs,
+ struct ion_client *client)
+{
+ struct ion_handle *temp_handle = NULL;
+ void *payload_buffer = NULL;
+ int actual_buffer_size = 0;
+ int ret = 0;
+
+ MPQ_DVB_DBG_PRINT("%s: Internal decoder buffer allocation\n", __func__);
+
+ actual_buffer_size = dec_buffs->buffers_size;
+ actual_buffer_size += (SZ_4K - 1);
+ actual_buffer_size &= ~(SZ_4K - 1);
+
+ temp_handle = ion_alloc(client, actual_buffer_size, SZ_4K,
+ ION_HEAP(video_ion_alloc_heap), ION_FLAG_CACHED);
+
+ if (IS_ERR_OR_NULL(temp_handle)) {
+ ret = PTR_ERR(temp_handle);
+ MPQ_DVB_ERR_PRINT("%s: FAILED to allocate payload buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ payload_buffer = ion_map_kernel(client, temp_handle);
+
+ if (IS_ERR_OR_NULL(payload_buffer)) {
+ ret = PTR_ERR(payload_buffer);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to map payload buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto init_failed_free_payload_buffer;
+ }
+ feed_data->buffer_desc.decoder_buffers_num = 1;
+ feed_data->buffer_desc.ion_handle[0] = temp_handle;
+ feed_data->buffer_desc.desc[0].base = payload_buffer;
+ feed_data->buffer_desc.desc[0].size = actual_buffer_size;
+ feed_data->buffer_desc.desc[0].read_ptr = 0;
+ feed_data->buffer_desc.desc[0].write_ptr = 0;
+ feed_data->buffer_desc.desc[0].handle =
+ ion_share_dma_buf(
+ client,
+ temp_handle);
+ if (IS_ERR_VALUE(feed_data->buffer_desc.desc[0].handle)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to share payload buffer %d\n",
+ __func__, ret);
+ ret = -ENOMEM;
+ goto init_failed_unmap_payload_buffer;
+ }
+
+ return 0;
+
+init_failed_unmap_payload_buffer:
+ ion_unmap_kernel(client, temp_handle);
+ feed_data->buffer_desc.desc[0].base = NULL;
+init_failed_free_payload_buffer:
+ ion_free(client, temp_handle);
+ feed_data->buffer_desc.ion_handle[0] = NULL;
+ feed_data->buffer_desc.desc[0].size = 0;
+ feed_data->buffer_desc.decoder_buffers_num = 0;
+end:
+ return ret;
+}
+
+/**
+ * Handles the details of external decoder buffers allocated by user.
+ * Each buffer is mapped into kernel memory and an ION handle is obtained, and
+ * decoder feed object is updated with related information.
+ * Internal helper function.
+ * @feed_data: decoder feed object
+ * @dec_buffs: buffer information
+ * @client: ION client
+ *
+ * Return error status
+ */
+static int mpq_dmx_init_external_buffers(
+ struct mpq_video_feed_info *feed_data,
+ struct dmx_decoder_buffers *dec_buffs,
+ struct ion_client *client)
+{
+ struct ion_handle *temp_handle = NULL;
+ void *payload_buffer = NULL;
+ int actual_buffer_size = 0;
+ int ret = 0;
+ int i;
+
+ /*
+ * Payload buffer was allocated externally (through ION).
+ * Map the ion handles to kernel memory
+ */
+ MPQ_DVB_DBG_PRINT("%s: External decoder buffer allocation\n", __func__);
+
+ actual_buffer_size = dec_buffs->buffers_size;
+ if (!dec_buffs->is_linear) {
+ MPQ_DVB_DBG_PRINT("%s: Ex. Ring-buffer\n", __func__);
+ feed_data->buffer_desc.decoder_buffers_num = 1;
+ } else {
+ MPQ_DVB_DBG_PRINT("%s: Ex. Linear\n", __func__);
+ feed_data->buffer_desc.decoder_buffers_num =
+ dec_buffs->buffers_num;
+ }
+
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ ret = mpq_map_buffer_to_kernel(
+ client,
+ dec_buffs->handles[i],
+ &temp_handle,
+ &payload_buffer);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Failed mapping buffer %d\n",
+ __func__, i);
+ goto init_failed;
+ }
+ feed_data->buffer_desc.ion_handle[i] = temp_handle;
+ feed_data->buffer_desc.desc[i].base = payload_buffer;
+ feed_data->buffer_desc.desc[i].handle =
+ dec_buffs->handles[i];
+ feed_data->buffer_desc.desc[i].size =
+ dec_buffs->buffers_size;
+ feed_data->buffer_desc.desc[i].read_ptr = 0;
+ feed_data->buffer_desc.desc[i].write_ptr = 0;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Buffer #%d: base=0x%p, handle=%d, size=%d\n",
+ __func__, i ,
+ feed_data->buffer_desc.desc[i].base,
+ feed_data->buffer_desc.desc[i].handle,
+ feed_data->buffer_desc.desc[i].size);
+ }
+
+ return 0;
+
+init_failed:
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ if (feed_data->buffer_desc.ion_handle[i]) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ ion_unmap_kernel(client,
+ feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.desc[i].base = NULL;
+ }
+ ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.ion_handle[i] = NULL;
+ feed_data->buffer_desc.desc[i].size = 0;
+ }
+ }
+ return ret;
+}
+
+/**
+ * Handles the details of initializing the mpq_streambuffer object according
+ * to the user decoder buffer configuration: External/Internal buffers and
+ * ring/linear buffering mode.
+ * Internal helper function.
+ * @feed: dvb demux feed object, contains the buffers configuration
+ * @feed_data: decoder feed object
+ * @stream_buffer: stream buffer object to initialize
+ *
+ * Return error status
+ */
+static int mpq_dmx_init_streambuffer(
+ struct dvb_demux_feed *feed,
+ struct mpq_video_feed_info *feed_data,
+ struct mpq_streambuffer *stream_buffer)
+{
+ int ret;
+ void *packet_buffer = NULL;
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct ion_client *client = mpq_demux->ion_client;
+ struct dmx_decoder_buffers *dec_buffs = NULL;
+ enum mpq_streambuffer_mode mode;
+
+ dec_buffs = feed->feed.ts.decoder_buffers;
+
+ /* Allocate packet buffer holding the meta-data */
+ packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
+
+ if (packet_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate packets buffer\n",
+ __func__);
+
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ MPQ_DVB_DBG_PRINT("%s: dec_buffs: num=%d, size=%d, linear=%d\n",
+ __func__,
+ dec_buffs->buffers_num,
+ dec_buffs->buffers_size,
+ dec_buffs->is_linear);
+
+ feed_data->buffer_desc.decoder_buffers_num = dec_buffs->buffers_num;
+ if (0 == dec_buffs->buffers_num)
+ ret = mpq_dmx_init_internal_buffers(
+ feed_data, dec_buffs, client);
+ else
+ ret = mpq_dmx_init_external_buffers(
+ feed_data, dec_buffs, client);
+
+ if (ret != 0)
+ goto init_failed_free_packet_buffer;
+
+ mode = dec_buffs->is_linear ? MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR :
+ MPQ_STREAMBUFFER_BUFFER_MODE_RING;
+ ret = mpq_streambuffer_init(
+ feed_data->video_buffer,
+ mode,
+ feed_data->buffer_desc.desc,
+ feed_data->buffer_desc.decoder_buffers_num,
+ packet_buffer,
+ VIDEO_META_DATA_BUFFER_SIZE);
+
+ if (ret != 0)
+ goto init_failed_free_packet_buffer;
+
+ goto end;
+
+
+init_failed_free_packet_buffer:
+ vfree(packet_buffer);
+end:
+ return ret;
+}
+
int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed)
{
int ret;
- void *packet_buffer;
- void *payload_buffer;
struct mpq_video_feed_info *feed_data;
struct mpq_demux *mpq_demux = feed->demux->priv;
struct mpq_streambuffer *stream_buffer;
- int actual_buffer_size;
/* Allocate memory for private feed data */
- feed_data = vmalloc(sizeof(struct mpq_video_feed_info));
+ feed_data = vzalloc(sizeof(struct mpq_video_feed_info));
if (feed_data == NULL) {
MPQ_DVB_ERR_PRINT(
@@ -925,78 +1197,6 @@
}
}
- /* Allocate packet buffer holding the meta-data */
- packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
-
- if (packet_buffer == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: FAILED to allocate packets buffer\n",
- __func__);
-
- ret = -ENOMEM;
- goto init_failed_free_priv_data;
- }
-
- /*
- * Allocate payload buffer through ION.
- * TODO: for scrambling support, need to check if the
- * stream is scrambled and allocate the buffer with secure
- * flag set.
- */
-
- actual_buffer_size = feed->buffer_size;
-
- actual_buffer_size += (SZ_4K - 1);
- actual_buffer_size &= ~(SZ_4K - 1);
-
- feed_data->payload_buff_handle =
- ion_alloc(mpq_demux->ion_client,
- actual_buffer_size,
- SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID),
- ION_FLAG_CACHED);
-
- if (IS_ERR_OR_NULL(feed_data->payload_buff_handle)) {
- ret = PTR_ERR(feed_data->payload_buff_handle);
-
- MPQ_DVB_ERR_PRINT(
- "%s: FAILED to allocate payload buffer %d\n",
- __func__, ret);
-
- if (!ret)
- ret = -ENOMEM;
- goto init_failed_free_packet_buffer;
- }
-
- payload_buffer =
- ion_map_kernel(mpq_demux->ion_client,
- feed_data->payload_buff_handle);
-
- if (IS_ERR_OR_NULL(payload_buffer)) {
- ret = PTR_ERR(payload_buffer);
-
- MPQ_DVB_ERR_PRINT(
- "%s: FAILED to map payload buffer %d\n",
- __func__, ret);
-
- if (!ret)
- ret = -ENOMEM;
- goto init_failed_free_payload_buffer;
- }
-
- feed_data->buffer_desc.read_ptr = 0;
- feed_data->buffer_desc.write_ptr = 0;
- feed_data->buffer_desc.base = payload_buffer;
- feed_data->buffer_desc.size = actual_buffer_size;
- feed_data->buffer_desc.handle =
- ion_share_dma_buf(
- mpq_demux->ion_client,
- feed_data->payload_buff_handle);
- if (feed_data->buffer_desc.handle < 0) {
- ret = -EFAULT;
- goto init_failed_unmap_payload_buffer;
- }
-
/* Register the new stream-buffer interface to MPQ adapter */
switch (feed->pes_type) {
case DMX_TS_PES_VIDEO0:
@@ -1025,7 +1225,7 @@
__func__,
feed->pes_type);
ret = -EINVAL;
- goto init_failed_unshare_payload_buffer;
+ goto init_failed_free_priv_data;
}
/* make sure not occupied already */
@@ -1039,26 +1239,12 @@
__func__,
feed_data->stream_interface);
ret = -EBUSY;
- goto init_failed_unshare_payload_buffer;
+ goto init_failed_free_priv_data;
}
feed_data->video_buffer =
&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
- ret = mpq_streambuffer_init(
- feed_data->video_buffer,
- MPQ_STREAMBUFFER_BUFFER_MODE_RING,
- &feed_data->buffer_desc,
- 1,
- packet_buffer,
- VIDEO_META_DATA_BUFFER_SIZE);
- if (ret < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: mpq_streambuffer_init failed, err = %d\n",
- __func__, ret);
- goto init_failed_unshare_payload_buffer;
- }
-
ret = mpq_adapter_register_stream_if(
feed_data->stream_interface,
feed_data->video_buffer);
@@ -1068,10 +1254,18 @@
"%s: mpq_adapter_register_stream_if failed, "
"err = %d\n",
__func__, ret);
- goto init_failed_unshare_payload_buffer;
+ goto init_failed_free_priv_data;
}
- feed->buffer_size = actual_buffer_size;
+ ret = mpq_dmx_init_streambuffer(
+ feed, feed_data, feed_data->video_buffer);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_init_streambuffer failed, err = %d\n",
+ __func__, ret);
+ goto init_failed_unregister_stream_if;
+ }
+
feed_data->pes_payload_address =
(u32)feed_data->video_buffer->raw_data.data;
@@ -1085,7 +1279,6 @@
feed_data->found_sequence_header_pattern = 0;
memset(&feed_data->prefix_size, 0,
sizeof(struct mpq_framing_prefix_size_masks));
- feed_data->first_pattern_offset = 0;
feed_data->first_prefix_size = 0;
feed_data->saved_pts_dts_info.pts_exist = 0;
feed_data->saved_pts_dts_info.dts_exist = 0;
@@ -1101,16 +1294,8 @@
return 0;
-init_failed_unshare_payload_buffer:
- put_unused_fd(feed_data->buffer_desc.handle);
-init_failed_unmap_payload_buffer:
- ion_unmap_kernel(mpq_demux->ion_client,
- feed_data->payload_buff_handle);
-init_failed_free_payload_buffer:
- ion_free(mpq_demux->ion_client,
- feed_data->payload_buff_handle);
-init_failed_free_packet_buffer:
- vfree(packet_buffer);
+init_failed_unregister_stream_if:
+ mpq_adapter_unregister_stream_if(feed_data->stream_interface);
init_failed_free_priv_data:
vfree(feed_data);
feed->priv = NULL;
@@ -1120,6 +1305,41 @@
}
EXPORT_SYMBOL(mpq_dmx_init_video_feed);
+void mpq_dmx_release_streambuffer(
+ struct dvb_demux_feed *feed,
+ struct mpq_video_feed_info *feed_data,
+ struct ion_client *client)
+{
+ int buf_num = 0;
+ struct dmx_decoder_buffers *dec_buffs = feed->feed.ts.decoder_buffers;
+ int i;
+
+ mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+
+ vfree(feed_data->video_buffer->packet_data.data);
+
+ buf_num = feed_data->buffer_desc.decoder_buffers_num;
+ for (i = 0; i < buf_num; i++) {
+ if (feed_data->buffer_desc.ion_handle[i]) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ ion_unmap_kernel(client,
+ feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.desc[i].base = NULL;
+ }
+ ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.ion_handle[i] = NULL;
+ feed_data->buffer_desc.desc[i].size = 0;
+
+ /*
+ * Call put_unused_fd only if kernel it the one that
+ * shared the buffer handle.
+ */
+ if (0 == dec_buffs->buffers_num)
+ put_unused_fd(
+ feed_data->buffer_desc.desc[i].handle);
+ }
+ }
+}
int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed)
{
@@ -1143,17 +1363,7 @@
wake_up_all(&feed_data->video_buffer->raw_data.queue);
- mpq_adapter_unregister_stream_if(feed_data->stream_interface);
-
- vfree(feed_data->video_buffer->packet_data.data);
-
- put_unused_fd(feed_data->buffer_desc.handle);
-
- ion_unmap_kernel(mpq_demux->ion_client,
- feed_data->payload_buff_handle);
-
- ion_free(mpq_demux->ion_client,
- feed_data->payload_buff_handle);
+ mpq_dmx_release_streambuffer(feed, feed_data, mpq_demux->ion_client);
vfree(feed_data);
@@ -1196,78 +1406,98 @@
}
EXPORT_SYMBOL(mpq_dmx_decoder_fullness_init);
+
+static inline int mpq_dmx_check_decoder_fullness(
+ struct mpq_streambuffer *sbuff,
+ size_t required_space)
+{
+ u32 free = mpq_streambuffer_data_free(sbuff);
+ MPQ_DVB_DBG_PRINT("%s: stream buffer free = %d, required = %d\n",
+ __func__, free, required_space);
+
+ /*
+ * For linear buffers, verify there's enough space for this TSP
+ * and an additional buffer is free, as framing might required one
+ * more buffer to be available.
+ */
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode)
+ return (free >= required_space &&
+ sbuff->pending_buffers_count < sbuff->buffers_num-1);
+ else
+ /* Ring buffer mode */
+ return (free >= required_space);
+}
+
int mpq_dmx_decoder_fullness_wait(
struct dvb_demux_feed *feed,
size_t required_space)
{
struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_streambuffer *sbuff = NULL;
+ struct mpq_video_feed_info *feed_data;
+ int ret;
- if (mpq_dmx_is_video_feed(feed)) {
- int ret;
- struct mpq_video_feed_info *feed_data;
- struct dvb_ringbuffer *video_buff;
-
- spin_lock(&mpq_demux->feed_lock);
-
- if (feed->priv == NULL) {
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- feed_data = feed->priv;
- video_buff = &feed_data->video_buffer->raw_data;
-
- ret = 0;
- if ((feed_data != NULL) &&
- (!feed_data->fullness_wait_cancel) &&
- (dvb_ringbuffer_free(video_buff) < required_space)) {
- DEFINE_WAIT(__wait);
- for (;;) {
- prepare_to_wait(
- &video_buff->queue,
- &__wait,
- TASK_INTERRUPTIBLE);
-
- if ((feed->priv == NULL) ||
- (feed_data->fullness_wait_cancel) ||
- (dvb_ringbuffer_free(video_buff) >=
- required_space))
- break;
-
- if (!signal_pending(current)) {
- spin_unlock(&mpq_demux->feed_lock);
- schedule();
- spin_lock(&mpq_demux->feed_lock);
- continue;
- }
- ret = -ERESTARTSYS;
- break;
- }
- finish_wait(&video_buff->queue, &__wait);
- }
-
- if (ret < 0) {
- spin_unlock(&mpq_demux->feed_lock);
- return ret;
- }
-
- if ((feed->priv == NULL) ||
- (feed_data->fullness_wait_cancel)) {
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- spin_unlock(&mpq_demux->feed_lock);
- return 0;
+ if (!mpq_dmx_is_video_feed(feed)) {
+ MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
+ __func__,
+ feed->pes_type);
+ return -EINVAL;
}
- /* else */
- MPQ_DVB_DBG_PRINT(
- "%s: Invalid feed type %d\n",
- __func__,
- feed->pes_type);
+ spin_lock(&mpq_demux->feed_lock);
+ if (feed->priv == NULL) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+ feed_data = feed->priv;
+ sbuff = feed_data->video_buffer;
+ if (sbuff == NULL) {
+ spin_unlock(&mpq_demux->feed_lock);
+ MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
- return -EINVAL;
+ if ((feed_data != NULL) &&
+ (!feed_data->fullness_wait_cancel) &&
+ (!mpq_dmx_check_decoder_fullness(sbuff, required_space))) {
+ DEFINE_WAIT(__wait);
+ for (;;) {
+ prepare_to_wait(&sbuff->raw_data.queue,
+ &__wait,
+ TASK_INTERRUPTIBLE);
+
+ if ((feed->priv == NULL) ||
+ feed_data->fullness_wait_cancel ||
+ mpq_dmx_check_decoder_fullness(sbuff,
+ required_space))
+ break;
+
+ if (!signal_pending(current)) {
+ spin_unlock(&mpq_demux->feed_lock);
+ schedule();
+ spin_lock(&mpq_demux->feed_lock);
+ continue;
+ }
+
+ ret = -ERESTARTSYS;
+ break;
+ }
+ finish_wait(&sbuff->raw_data.queue, &__wait);
+ }
+
+ if (ret < 0) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return ret;
+ }
+
+ if ((feed->priv == NULL) || (feed_data->fullness_wait_cancel)) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
}
EXPORT_SYMBOL(mpq_dmx_decoder_fullness_wait);
@@ -1572,17 +1802,6 @@
pes_header = &feed_data->pes_header;
- /* MPQ_DVB_DBG_PRINT("TS packet: %X %X %X %X %X%X %X %X %X\n",
- ts_header->sync_byte,
- ts_header->transport_error_indicator,
- ts_header->payload_unit_start_indicator,
- ts_header->transport_priority,
- ts_header->pid_msb,
- ts_header->pid_lsb,
- ts_header->transport_scrambling_control,
- ts_header->adaptation_field_control,
- ts_header->continuity_counter); */
-
/* Make sure this TS packet has a payload and not scrambled */
if ((ts_header->sync_byte != 0x47) ||
(ts_header->adaptation_field_control == 0) ||
@@ -1752,8 +1971,11 @@
feed->peslen += bytes_avail;
meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
- packet.raw_data_handle = feed_data->buffer_desc.handle;
- packet.raw_data_offset = 0;
+ packet.raw_data_handle = feed_data->buffer_desc.desc[0].handle;
+ mpq_streambuffer_get_data_rw_offset(
+ stream_buffer,
+ &packet.raw_data_offset,
+ NULL);
packet.user_data_len =
sizeof(struct mpq_adapter_video_meta_data);
@@ -1874,17 +2096,6 @@
pes_header = &feed_data->pes_header;
- /* MPQ_DVB_DBG_PRINT("TS packet: %X %X %X %X %X%X %X %X %X\n",
- ts_header->sync_byte,
- ts_header->transport_error_indicator,
- ts_header->payload_unit_start_indicator,
- ts_header->transport_priority,
- ts_header->pid_msb,
- ts_header->pid_lsb,
- ts_header->transport_scrambling_control,
- ts_header->adaptation_field_control,
- ts_header->continuity_counter); */
-
/* Make sure this TS packet has a payload and not scrambled */
if ((ts_header->sync_byte != 0x47) ||
(ts_header->adaptation_field_control == 0) ||
@@ -1910,8 +2121,11 @@
if (0 == feed_data->pes_header_left_bytes) {
packet.raw_data_len = feed->peslen;
packet.raw_data_handle =
- feed_data->buffer_desc.handle;
- packet.raw_data_offset = 0;
+ feed_data->buffer_desc.desc[0].handle;
+ mpq_streambuffer_get_data_rw_offset(
+ stream_buffer,
+ &packet.raw_data_offset,
+ NULL);
packet.user_data_len =
sizeof(struct
mpq_adapter_video_meta_data);
@@ -2014,43 +2228,57 @@
struct dmx_buffer_status *dmx_buffer_status)
{
struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_video_feed_info *feed_data;
+ struct mpq_streambuffer *video_buff;
- if (mpq_dmx_is_video_feed(feed)) {
- struct mpq_video_feed_info *feed_data;
- struct dvb_ringbuffer *video_buff;
-
- spin_lock(&mpq_demux->feed_lock);
-
- if (feed->priv == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: invalid feed, feed->priv is NULL\n",
- __func__);
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- feed_data = feed->priv;
- video_buff = &feed_data->video_buffer->raw_data;
-
- dmx_buffer_status->error = video_buff->error;
- dmx_buffer_status->fullness = dvb_ringbuffer_avail(video_buff);
- dmx_buffer_status->free_bytes = dvb_ringbuffer_free(video_buff);
- dmx_buffer_status->read_offset = video_buff->pread;
- dmx_buffer_status->write_offset = video_buff->pwrite;
- dmx_buffer_status->size = video_buff->size;
-
- spin_unlock(&mpq_demux->feed_lock);
-
- return 0;
+ if (!mpq_dmx_is_video_feed(feed)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid feed type %d\n",
+ __func__,
+ feed->pes_type);
+ return -EINVAL;
}
- /* else */
- MPQ_DVB_ERR_PRINT(
- "%s: Invalid feed type %d\n",
- __func__,
- feed->pes_type);
+ spin_lock(&mpq_demux->feed_lock);
- return -EINVAL;
+ if (feed->priv == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed->priv is NULL\n",
+ __func__);
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+ feed_data = feed->priv;
+ video_buff = feed_data->video_buffer;
+
+ dmx_buffer_status->error = video_buff->raw_data.error;
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == video_buff->mode) {
+ dmx_buffer_status->fullness =
+ video_buff->buffers[0].size *
+ video_buff->pending_buffers_count;
+ dmx_buffer_status->free_bytes =
+ video_buff->buffers[0].size *
+ (video_buff->buffers_num -
+ video_buff->pending_buffers_count);
+ dmx_buffer_status->size =
+ video_buff->buffers[0].size *
+ video_buff->buffers_num;
+ } else {
+ dmx_buffer_status->fullness =
+ mpq_streambuffer_data_avail(video_buff);
+ dmx_buffer_status->free_bytes =
+ mpq_streambuffer_data_free(video_buff);
+ dmx_buffer_status->size = video_buff->buffers[0].size;
+ }
+
+ mpq_streambuffer_get_data_rw_offset(
+ video_buff,
+ &dmx_buffer_status->read_offset,
+ &dmx_buffer_status->write_offset);
+
+ spin_unlock(&mpq_demux->feed_lock);
+
+ return 0;
}
EXPORT_SYMBOL(mpq_dmx_decoder_buffer_status);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index f7af1ef..daf8aa9 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -269,6 +269,24 @@
u32 size_mask[MPQ_MAX_FOUND_PATTERNS];
};
+/**
+ * mpq_decoder_buffers_desc - decoder buffer(s) management information.
+ *
+ * @desc: Array of buffer descriptors as they are passed to mpq_streambuffer
+ * upon its initialization. These descriptors must remain valid as long as
+ * the mpq_streambuffer object is used.
+ * @ion_handle: Array of ION handles, one for each decoder buffer, used for
+ * kernel memory mapping or allocation. Handles are saved in order to release
+ * resources properly later on.
+ * @decoder_buffers_num: number of buffers that are managed, either externally
+ * or internally by the mpq_streambuffer object
+ */
+struct mpq_decoder_buffers_desc {
+ struct mpq_streambuffer_buffer_desc desc[DMX_MAX_DECODER_BUFFER_NUM];
+ struct ion_handle *ion_handle[DMX_MAX_DECODER_BUFFER_NUM];
+ u32 decoder_buffers_num;
+};
+
/*
* mpq_video_feed_info - private data used for video feed.
*
@@ -286,8 +304,7 @@
* decoder's fullness.
* @pes_payload_address: Used for feeds that output data to decoder,
* holds current PES payload start address.
- * @payload_buff_handle: ION handle for the allocated payload buffer
- * @stream_interface: The ID of the video stream interface registered
+ * @stream_interface: The ID of the video stream interface registered
* with this stream buffer.
* @patterns: pointer to the framing patterns to look for.
* @patterns_num: number of framing patterns.
@@ -320,13 +337,12 @@
struct mpq_video_feed_info {
void *plugin_data;
struct mpq_streambuffer *video_buffer;
- struct mpq_streambuffer_buffer_desc buffer_desc;
+ struct mpq_decoder_buffers_desc buffer_desc;
struct pes_packet_header pes_header;
u32 pes_header_left_bytes;
u32 pes_header_offset;
u32 pes_payload_address;
int fullness_wait_cancel;
- struct ion_handle *payload_buff_handle;
enum mpq_adapter_stream_if stream_interface;
const struct mpq_framing_pattern_lookup_params *patterns;
int patterns_num;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index bbf9d0a..c5c3518 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -572,24 +572,53 @@
caps->max_bitrate = 144;
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
- caps->section.flags = 0;
+
+ /* Buffer requirements */
+ caps->section.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->section.max_buffer_num = 1;
caps->section.max_size = 0xFFFFFFFF;
caps->section.size_alignment = 0;
- caps->pes.flags = 0;
+ caps->pes.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->pes.max_buffer_num = 1;
caps->pes.max_size = 0xFFFFFFFF;
caps->pes.size_alignment = 0;
- caps->recording_188_tsp.flags = 0;
+ caps->recording_188_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->recording_188_tsp.max_buffer_num = 1;
caps->recording_188_tsp.max_size = 0xFFFFFFFF;
caps->recording_188_tsp.size_alignment = 0;
- caps->recording_192_tsp.flags = 0;
+ caps->recording_192_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->recording_192_tsp.max_buffer_num = 1;
caps->recording_192_tsp.max_size = 0xFFFFFFFF;
caps->recording_192_tsp.size_alignment = 0;
- caps->playback_188_tsp.flags = 0;
+ caps->playback_188_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->playback_188_tsp.max_buffer_num = 1;
caps->playback_188_tsp.max_size = 0xFFFFFFFF;
caps->playback_188_tsp.size_alignment = 0;
- caps->playback_192_tsp.flags = 0;
+ caps->playback_192_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->playback_192_tsp.max_buffer_num = 1;
caps->playback_192_tsp.max_size = 0xFFFFFFFF;
caps->playback_192_tsp.size_alignment = 0;
+ caps->decoder.flags =
+ DMX_BUFFER_CONTIGUOUS_MEM |
+ DMX_BUFFER_SECURED_IF_DECRYPTED |
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT |
+ DMX_BUFFER_LINEAR_GROUP_SUPPORT;
+ caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM;
+ caps->decoder.max_size = 0xFFFFFFFF;
+ caps->decoder.size_alignment = SZ_4K;
return 0;
}
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index ac03e43..61c1761 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -868,24 +868,53 @@
caps->max_bitrate = 144;
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
- caps->section.flags = 0;
+
+ /* Buffer requirements */
+ caps->section.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->section.max_buffer_num = 1;
caps->section.max_size = 0xFFFFFFFF;
caps->section.size_alignment = 0;
- caps->pes.flags = 0;
+ caps->pes.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->pes.max_buffer_num = 1;
caps->pes.max_size = 0xFFFFFFFF;
caps->pes.size_alignment = 0;
- caps->recording_188_tsp.flags = 0;
+ caps->recording_188_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->recording_188_tsp.max_buffer_num = 1;
caps->recording_188_tsp.max_size = 0xFFFFFFFF;
caps->recording_188_tsp.size_alignment = 0;
- caps->recording_192_tsp.flags = 0;
+ caps->recording_192_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->recording_192_tsp.max_buffer_num = 1;
caps->recording_192_tsp.max_size = 0xFFFFFFFF;
caps->recording_192_tsp.size_alignment = 0;
- caps->playback_188_tsp.flags = 0;
+ caps->playback_188_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->playback_188_tsp.max_buffer_num = 1;
caps->playback_188_tsp.max_size = 0xFFFFFFFF;
caps->playback_188_tsp.size_alignment = 0;
- caps->playback_192_tsp.flags = 0;
+ caps->playback_192_tsp.flags =
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT;
+ caps->playback_192_tsp.max_buffer_num = 1;
caps->playback_192_tsp.max_size = 0xFFFFFFFF;
caps->playback_192_tsp.size_alignment = 0;
+ caps->decoder.flags =
+ DMX_BUFFER_CONTIGUOUS_MEM |
+ DMX_BUFFER_SECURED_IF_DECRYPTED |
+ DMX_BUFFER_EXTERNAL_SUPPORT |
+ DMX_BUFFER_INTERNAL_SUPPORT |
+ DMX_BUFFER_LINEAR_GROUP_SUPPORT;
+ caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM;
+ caps->decoder.max_size = 0xFFFFFFFF;
+ caps->decoder.size_alignment = SZ_4K;
return 0;
}
diff --git a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
index 9476c73..e5ba635 100644
--- a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
+++ b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
@@ -413,7 +413,21 @@
mpq_streambuffer_pkt_dispose_cb cb_func,
void *user_data);
-
+/**
+ * mpq_streambuffer_data_rw_offset - returns read/write offsets of current data
+ * buffer.
+ * @sbuff: The stream buffer object
+ * @read_offset: returned read offset
+ * @write_offset: returned write offset
+ *
+ * Note: read offset or write offset may be NULL if not required.
+ * Returns error status
+ * -EINVAL if arguments are invalid
+ */
+int mpq_streambuffer_get_data_rw_offset(
+ struct mpq_streambuffer *sbuff,
+ u32 *read_offset,
+ u32 *write_offset);
#endif /* _MPQ_STREAM_BUFFER_H */
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 257e069..fd4447f 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -39,6 +39,9 @@
/* Min recording chunk upon which event is generated */
#define DMX_REC_BUFF_CHUNK_MIN_SIZE (100*188)
+/* Decoder buffers are usually large ~1MB, 10 should suffice */
+#define DMX_MAX_DECODER_BUFFER_NUM (10)
+
typedef enum
{
DMX_OUT_DECODER, /* Streaming directly to decoder. */
@@ -314,13 +317,27 @@
/* Maximum buffer size allowed */
__u32 max_size;
+
+ /* Maximum number of linear buffers handled by demux */
+ __u32 max_buffer_num;
+
+ /* Feature support bitmap as detailed below */
__u32 flags;
-/* Buffer allocated as physically contiguous memory */
-#define DMX_BUFFER_CONTIGEOUS_MEM 0x1
+/* Buffer must be allocated as physically contiguous memory */
+#define DMX_BUFFER_CONTIGUOUS_MEM 0x1
/* If the filter's data is decrypted, the buffer should be secured one */
#define DMX_BUFFER_SECURED_IF_DECRYPTED 0x2
+
+/* Buffer can be allocated externally */
+#define DMX_BUFFER_EXTERNAL_SUPPORT 0x4
+
+/* Buffer can be allocated internally */
+#define DMX_BUFFER_INTERNAL_SUPPORT 0x8
+
+/* Filter output can be output to a linear buffer group */
+#define DMX_BUFFER_LINEAR_GROUP_SUPPORT 0x10
};
typedef struct dmx_caps {
@@ -385,6 +402,9 @@
/* For PES not sent to decoder */
struct dmx_buffer_requirement pes;
+ /* For PES sent to decoder */
+ struct dmx_buffer_requirement decoder;
+
/* Recording buffer for recording of 188 bytes packets */
struct dmx_buffer_requirement recording_188_tsp;
@@ -438,9 +458,9 @@
};
struct dmx_stc {
- unsigned int num; /* input : which STC? 0..N */
- unsigned int base; /* output: divisor for stc to get 90 kHz clock */
- __u64 stc; /* output: stc in 'base'*90 kHz units */
+ unsigned int num; /* input : which STC? 0..N */
+ unsigned int base; /* output: divisor for stc to get 90 kHz clock */
+ __u64 stc; /* output: stc in 'base'*90 kHz units */
};
enum dmx_buffer_mode {
@@ -466,6 +486,27 @@
int handle;
};
+
+struct dmx_decoder_buffers {
+ /*
+ * Specify if linear buffer support is requested. If set, buffers_num
+ * must be greater than 1
+ */
+ int is_linear;
+
+ /*
+ * Specify number of external buffers allocated by user.
+ * If set to 0 means internal buffer allocation is requested
+ */
+ __u32 buffers_num;
+
+ /* Specify buffer size, either external or internal */
+ __u32 buffers_size;
+
+ /* Array of externally allocated buffer handles */
+ int handles[DMX_MAX_DECODER_BUFFER_NUM];
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -487,5 +528,7 @@
#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event)
#define DMX_SET_BUFFER_MODE _IOW('o', 61, enum dmx_buffer_mode)
#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer)
+#define DMX_SET_DECODER_BUFFER _IOW('o', 63, struct dmx_decoder_buffers)
+
#endif /*_DVBDMX_H_*/