[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>
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index 08b62e4..0859448 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -76,15 +76,131 @@
 	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 @@
 	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 @@
 	}
 
 	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 @@
 
 	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 @@
 
 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 @@
 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 @@
 		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 @@
 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 @@
 		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);
 }