summaryrefslogtreecommitdiff
path: root/drivers/media/video/saa7164/saa7164-encoder.c
diff options
context:
space:
mode:
authorSteven Toth <stoth@kernellabs.com>2010-07-31 16:01:00 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 07:55:01 -0200
commit1b0e8e46297a214336d85c8e278a8a004f97889e (patch)
tree8bcfe776bfc8926b2636cf8bfe6efb630404e4f6 /drivers/media/video/saa7164/saa7164-encoder.c
parent7c1618227e6932fcd92597507ee63c01da73e623 (diff)
downloadlwn-1b0e8e46297a214336d85c8e278a8a004f97889e.tar.gz
lwn-1b0e8e46297a214336d85c8e278a8a004f97889e.zip
[media] saa7164: allow DMA engine buffers to vary in size between analog and digital
Signed-off-by: Steven Toth <stoth@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/saa7164/saa7164-encoder.c')
-rw-r--r--drivers/media/video/saa7164/saa7164-encoder.c245
1 files changed, 144 insertions, 101 deletions
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index 08b62e41c466..0859448bae05 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -76,15 +76,131 @@ static void saa7164_encoder_configure(struct saa7164_port *port)
saa7164_api_set_audio_std(port);
}
-/* One time configuration at registration time */
-static int saa7164_encoder_initialize(struct saa7164_port *port)
+static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port)
+{
+ struct list_head *c, *n, *p, *q, *l, *v;
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+
+ /* Remove any allocated buffers */
+ mutex_lock(&port->dmaqueue_lock);
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+ list_del(c);
+ saa7164_buffer_dealloc(buf);
+ }
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
+ list_for_each_safe(p, q, &port->list_buf_used.list) {
+ ubuf = list_entry(p, struct saa7164_user_buffer, list);
+ list_del(p);
+ saa7164_buffer_dealloc_user(ubuf);
+ }
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
+ list_for_each_safe(l, v, &port->list_buf_free.list) {
+ ubuf = list_entry(l, struct saa7164_user_buffer, list);
+ list_del(l);
+ saa7164_buffer_dealloc_user(ubuf);
+ }
+
+ mutex_unlock(&port->dmaqueue_lock);
+ dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+
+ return 0;
+}
+
+/* Dynamic buffer switch at encoder start time */
+static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+ tmHWStreamParameters_t *params = &port->hw_streamingparams;
+ int result = -ENODEV, i;
+ int len = 0;
dprintk(DBGLVL_ENC, "%s()\n", __func__);
- saa7164_encoder_configure(port);
+ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+ dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n", __func__);
+ params->samplesperline = 128;
+ params->numberoflines = 256;
+ params->pitch = 128;
+ params->numpagetables = 2 +
+ ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
+ } else
+ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
+ dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n", __func__);
+ params->samplesperline = 188;
+ params->numberoflines = 312;
+ params->pitch = 188;
+ params->numpagetables = 2 +
+ ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
+ } else
+ BUG();
+
+ /* Init and establish defaults */
+ params->bitspersample = 8;
+ params->linethreshold = 0;
+ params->pagetablelistvirt = 0;
+ params->pagetablelistphys = 0;
+ params->numpagetableentries = port->hwcfg.buffercount;
+
+ /* Allocate the PCI resources, buffers (hard) */
+ for (i = 0; i < port->hwcfg.buffercount; i++) {
+ buf = saa7164_buffer_alloc(port,
+ params->numberoflines *
+ params->pitch);
+
+ if (!buf) {
+ printk(KERN_ERR "%s() failed "
+ "(errno = %d), unable to allocate buffer\n",
+ __func__, result);
+ result = -ENOMEM;
+ goto failed;
+ } else {
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_add_tail(&buf->list, &port->dmaqueue.list);
+ mutex_unlock(&port->dmaqueue_lock);
+
+ }
+ }
+
+ /* Allocate some kenrel kernel buffers for copying
+ * to userpsace.
+ */
+ len = params->numberoflines * params->pitch;
+
+ if (encoder_buffers < 16)
+ encoder_buffers = 16;
+ if (encoder_buffers > 512)
+ encoder_buffers = 512;
+
+ for (i = 0; i < encoder_buffers; i++) {
+
+ ubuf = saa7164_buffer_alloc_user(dev, len);
+ if (ubuf) {
+ mutex_lock(&port->dmaqueue_lock);
+ list_add_tail(&ubuf->list, &port->list_buf_free.list);
+ mutex_unlock(&port->dmaqueue_lock);
+ }
+
+ }
+
+ result = 0;
+failed:
+ return result;
+}
+
+static int saa7164_encoder_initialize(struct saa7164_port *port)
+{
+ saa7164_encoder_configure(port);
return 0;
}
@@ -835,6 +951,7 @@ static int saa7164_encoder_stop_streaming(struct saa7164_port *port)
dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
port->nr);
+ /* Reset the state of any allocated buffer resources */
mutex_lock(&port->dmaqueue_lock);
/* Reset the hard and soft buffer state */
@@ -851,6 +968,10 @@ static int saa7164_encoder_stop_streaming(struct saa7164_port *port)
}
mutex_unlock(&port->dmaqueue_lock);
+
+ /* Free any allocated resources */
+ saa7164_encoder_buffers_dealloc(port);
+
dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
return ret;
@@ -863,10 +984,19 @@ static int saa7164_encoder_start_streaming(struct saa7164_port *port)
dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+ port->done_first_interrupt = 0;
+
+ /* allocate all of the PCIe DMA buffer resources on the fly,
+ * allowing switching between TS and PS payloads without
+ * requiring a complete driver reload.
+ */
+ saa7164_encoder_buffers_alloc(port);
+
/* Configure the encoder with any cache values */
saa7164_api_set_encoder(port);
saa7164_api_get_encoder(port);
+ /* Place the empty buffers on the hardware */
saa7164_buffer_cfg_port(port);
/* Acquire the hardware */
@@ -1005,27 +1135,29 @@ static int fops_release(struct file *file)
struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
{
- struct saa7164_user_buffer *buf = 0;
+ struct saa7164_user_buffer *ubuf = 0;
struct saa7164_dev *dev = port->dev;
u32 crc;
mutex_lock(&port->dmaqueue_lock);
if (!list_empty(&port->list_buf_used.list)) {
- buf = list_first_entry(&port->list_buf_used.list,
+ ubuf = list_first_entry(&port->list_buf_used.list,
struct saa7164_user_buffer, list);
- crc = crc32(0, buf->data, buf->actual_size);
- if (crc != buf->crc) {
- printk(KERN_ERR "%s() buf %p crc became invalid, was 0x%x became 0x%x\n", __func__,
- buf, buf->crc, crc);
+ if (crc_checking) {
+ crc = crc32(0, ubuf->data, ubuf->actual_size);
+ if (crc != ubuf->crc) {
+ printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__,
+ ubuf, ubuf->crc, crc);
+ }
}
}
mutex_unlock(&port->dmaqueue_lock);
- dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, buf);
+ dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
- return buf;
+ return ubuf;
}
static ssize_t fops_read(struct file *file, char __user *buffer,
@@ -1292,10 +1424,7 @@ static struct video_device *saa7164_encoder_alloc(
int saa7164_encoder_register(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
- struct saa7164_buffer *buf;
- struct saa7164_user_buffer *ubuf;
- int result = -ENODEV, i;
- int len = 0;
+ int result = -ENODEV;
dprintk(DBGLVL_ENC, "%s()\n", __func__);
@@ -1311,64 +1440,6 @@ int saa7164_encoder_register(struct saa7164_port *port)
goto failed;
}
- /* Init and establish defaults */
- /* TODO: Check the umber of lines for PS */
- port->hw_streamingparams.bitspersample = 8;
- port->hw_streamingparams.samplesperline = 128;
- port->hw_streamingparams.numberoflines = 256;
-
- port->hw_streamingparams.pitch = 128;
- port->hw_streamingparams.linethreshold = 0;
- port->hw_streamingparams.pagetablelistvirt = 0;
- port->hw_streamingparams.pagetablelistphys = 0;
- port->hw_streamingparams.numpagetables = 2 +
- ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
-
- port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount;
-
- /* Allocate the PCI resources, buffers (hard) */
- for (i = 0; i < port->hwcfg.buffercount; i++) {
- buf = saa7164_buffer_alloc(port,
- port->hw_streamingparams.numberoflines *
- port->hw_streamingparams.pitch);
-
- if (!buf) {
- printk(KERN_ERR "%s() failed "
- "(errno = %d), unable to allocate buffer\n",
- __func__, result);
- result = -ENOMEM;
- goto failed;
- } else {
-
- mutex_lock(&port->dmaqueue_lock);
- list_add_tail(&buf->list, &port->dmaqueue.list);
- mutex_unlock(&port->dmaqueue_lock);
-
- }
- }
-
- /* Allocate some kenrel kernel buffers for copying
- * to userpsace.
- */
- len = port->hw_streamingparams.numberoflines *
- port->hw_streamingparams.pitch;
-
- if (encoder_buffers < 16)
- encoder_buffers = 16;
- if (encoder_buffers > 512)
- encoder_buffers = 512;
-
- for (i = 0; i < encoder_buffers; i++) {
-
- ubuf = saa7164_buffer_alloc_user(dev, len);
- if (ubuf) {
- mutex_lock(&port->dmaqueue_lock);
- list_add_tail(&ubuf->list, &port->list_buf_free.list);
- mutex_unlock(&port->dmaqueue_lock);
- }
-
- }
-
/* Establish encoder defaults here */
/* Set default TV standard */
port->encodernorm = saa7164_tvnorms[0];
@@ -1446,9 +1517,6 @@ failed:
void saa7164_encoder_unregister(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
- struct saa7164_buffer *buf;
- struct saa7164_user_buffer *ubuf;
- struct list_head *c, *n, *p, *q, *l, *v;
dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
@@ -1464,31 +1532,6 @@ void saa7164_encoder_unregister(struct saa7164_port *port)
port->v4l_device = NULL;
}
- /* Remove any allocated buffers */
- mutex_lock(&port->dmaqueue_lock);
-
- dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
- list_for_each_safe(c, n, &port->dmaqueue.list) {
- buf = list_entry(c, struct saa7164_buffer, list);
- list_del(c);
- saa7164_buffer_dealloc(buf);
- }
-
- dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
- list_for_each_safe(p, q, &port->list_buf_used.list) {
- ubuf = list_entry(p, struct saa7164_user_buffer, list);
- list_del(p);
- saa7164_buffer_dealloc_user(ubuf);
- }
-
- dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
- list_for_each_safe(l, v, &port->list_buf_free.list) {
- ubuf = list_entry(l, struct saa7164_user_buffer, list);
- list_del(l);
- saa7164_buffer_dealloc_user(ubuf);
- }
-
- mutex_unlock(&port->dmaqueue_lock);
dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
}