aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-streams.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-streams.c')
-rw-r--r--drivers/media/video/cx18/cx18-streams.c70
1 files changed, 42 insertions, 28 deletions
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 0da57f583bf7..0c8e7542cf60 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -22,6 +22,7 @@
22 */ 22 */
23 23
24#include "cx18-driver.h" 24#include "cx18-driver.h"
25#include "cx18-io.h"
25#include "cx18-fileops.h" 26#include "cx18-fileops.h"
26#include "cx18-mailbox.h" 27#include "cx18-mailbox.h"
27#include "cx18-i2c.h" 28#include "cx18-i2c.h"
@@ -56,7 +57,7 @@ static struct file_operations cx18_v4l2_enc_fops = {
56static struct { 57static struct {
57 const char *name; 58 const char *name;
58 int vfl_type; 59 int vfl_type;
59 int minor_offset; 60 int num_offset;
60 int dma; 61 int dma;
61 enum v4l2_buf_type buf_type; 62 enum v4l2_buf_type buf_type;
62 struct file_operations *fops; 63 struct file_operations *fops;
@@ -119,7 +120,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
119 s->cx = cx; 120 s->cx = cx;
120 s->type = type; 121 s->type = type;
121 s->name = cx18_stream_info[type].name; 122 s->name = cx18_stream_info[type].name;
122 s->handle = 0xffffffff; 123 s->handle = CX18_INVALID_TASK_HANDLE;
123 124
124 s->dma = cx18_stream_info[type].dma; 125 s->dma = cx18_stream_info[type].dma;
125 s->buf_size = cx->stream_buf_size[type]; 126 s->buf_size = cx->stream_buf_size[type];
@@ -143,8 +144,8 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
143{ 144{
144 struct cx18_stream *s = &cx->streams[type]; 145 struct cx18_stream *s = &cx->streams[type];
145 u32 cap = cx->v4l2_cap; 146 u32 cap = cx->v4l2_cap;
146 int minor_offset = cx18_stream_info[type].minor_offset; 147 int num_offset = cx18_stream_info[type].num_offset;
147 int minor; 148 int num = cx->num + cx18_first_minor + num_offset;
148 149
149 /* These four fields are always initialized. If v4l2dev == NULL, then 150 /* These four fields are always initialized. If v4l2dev == NULL, then
150 this stream is not in use. In that case no other fields but these 151 this stream is not in use. In that case no other fields but these
@@ -163,9 +164,6 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
163 !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) 164 !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
164 return 0; 165 return 0;
165 166
166 /* card number + user defined offset + device offset */
167 minor = cx->num + cx18_first_minor + minor_offset;
168
169 /* User explicitly selected 0 buffers for these streams, so don't 167 /* User explicitly selected 0 buffers for these streams, so don't
170 create them. */ 168 create them. */
171 if (cx18_stream_info[type].dma != PCI_DMA_NONE && 169 if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
@@ -176,7 +174,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
176 174
177 cx18_stream_init(cx, type); 175 cx18_stream_init(cx, type);
178 176
179 if (minor_offset == -1) 177 if (num_offset == -1)
180 return 0; 178 return 0;
181 179
182 /* allocate and initialize the v4l2 video device structure */ 180 /* allocate and initialize the v4l2 video device structure */
@@ -190,7 +188,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
190 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", 188 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
191 cx->num); 189 cx->num);
192 190
193 s->v4l2dev->minor = minor; 191 s->v4l2dev->num = num;
194 s->v4l2dev->parent = &cx->dev->dev; 192 s->v4l2dev->parent = &cx->dev->dev;
195 s->v4l2dev->fops = cx18_stream_info[type].fops; 193 s->v4l2dev->fops = cx18_stream_info[type].fops;
196 s->v4l2dev->release = video_device_release; 194 s->v4l2dev->release = video_device_release;
@@ -226,7 +224,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
226{ 224{
227 struct cx18_stream *s = &cx->streams[type]; 225 struct cx18_stream *s = &cx->streams[type];
228 int vfl_type = cx18_stream_info[type].vfl_type; 226 int vfl_type = cx18_stream_info[type].vfl_type;
229 int minor; 227 int num;
230 228
231 /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? 229 /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
232 * We need a VFL_TYPE_TS defined. 230 * We need a VFL_TYPE_TS defined.
@@ -244,38 +242,44 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
244 if (s->v4l2dev == NULL) 242 if (s->v4l2dev == NULL)
245 return 0; 243 return 0;
246 244
247 minor = s->v4l2dev->minor; 245 num = s->v4l2dev->num;
246 /* card number + user defined offset + device offset */
247 if (type != CX18_ENC_STREAM_TYPE_MPG) {
248 struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
249
250 if (s_mpg->v4l2dev)
251 num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset;
252 }
248 253
249 /* Register device. First try the desired minor, then any free one. */ 254 /* Register device. First try the desired minor, then any free one. */
250 if (video_register_device(s->v4l2dev, vfl_type, minor) && 255 if (video_register_device(s->v4l2dev, vfl_type, num)) {
251 video_register_device(s->v4l2dev, vfl_type, -1)) { 256 CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
252 CX18_ERR("Couldn't register v4l2 device for %s minor %d\n", 257 s->name, num);
253 s->name, minor);
254 video_device_release(s->v4l2dev); 258 video_device_release(s->v4l2dev);
255 s->v4l2dev = NULL; 259 s->v4l2dev = NULL;
256 return -ENOMEM; 260 return -ENOMEM;
257 } 261 }
258 minor = s->v4l2dev->minor; 262 num = s->v4l2dev->num;
259 263
260 switch (vfl_type) { 264 switch (vfl_type) {
261 case VFL_TYPE_GRABBER: 265 case VFL_TYPE_GRABBER:
262 CX18_INFO("Registered device video%d for %s (%d MB)\n", 266 CX18_INFO("Registered device video%d for %s (%d MB)\n",
263 minor, s->name, cx->options.megabytes[type]); 267 num, s->name, cx->options.megabytes[type]);
264 break; 268 break;
265 269
266 case VFL_TYPE_RADIO: 270 case VFL_TYPE_RADIO:
267 CX18_INFO("Registered device radio%d for %s\n", 271 CX18_INFO("Registered device radio%d for %s\n",
268 minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); 272 num, s->name);
269 break; 273 break;
270 274
271 case VFL_TYPE_VBI: 275 case VFL_TYPE_VBI:
272 if (cx->options.megabytes[type]) 276 if (cx->options.megabytes[type])
273 CX18_INFO("Registered device vbi%d for %s (%d MB)\n", 277 CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
274 minor - MINOR_VFL_TYPE_VBI_MIN, 278 num,
275 s->name, cx->options.megabytes[type]); 279 s->name, cx->options.megabytes[type]);
276 else 280 else
277 CX18_INFO("Registered device vbi%d for %s\n", 281 CX18_INFO("Registered device vbi%d for %s\n",
278 minor - MINOR_VFL_TYPE_VBI_MIN, s->name); 282 num, s->name);
279 break; 283 break;
280 } 284 }
281 285
@@ -432,7 +436,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
432 default: 436 default:
433 return -EINVAL; 437 return -EINVAL;
434 } 438 }
435 s->buffers_stolen = 0;
436 439
437 /* mute/unmute video */ 440 /* mute/unmute video */
438 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, 441 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
@@ -470,7 +473,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
470 473
471 if (atomic_read(&cx->tot_capturing) == 0) { 474 if (atomic_read(&cx->tot_capturing) == 0) {
472 clear_bit(CX18_F_I_EOS, &cx->i_flags); 475 clear_bit(CX18_F_I_EOS, &cx->i_flags);
473 write_reg(7, CX18_DSP0_INTERRUPT_MASK); 476 cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
474 } 477 }
475 478
476 cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, 479 cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
@@ -480,8 +483,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
480 list_for_each(p, &s->q_free.list) { 483 list_for_each(p, &s->q_free.list) {
481 struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); 484 struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
482 485
483 writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); 486 cx18_writel(cx, buf->dma_handle,
484 writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length); 487 &cx->scb->cpu_mdl[buf->id].paddr);
488 cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
485 cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, 489 cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
486 (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 490 (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
487 1, buf->id, s->buf_size); 491 1, buf->id, s->buf_size);
@@ -489,7 +493,14 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
489 /* begin_capture */ 493 /* begin_capture */
490 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { 494 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
491 CX18_DEBUG_WARN("Error starting capture!\n"); 495 CX18_DEBUG_WARN("Error starting capture!\n");
496 /* Ensure we're really not capturing before releasing MDLs */
497 if (s->type == CX18_ENC_STREAM_TYPE_MPG)
498 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
499 else
500 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
501 cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
492 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); 502 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
503 /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
493 return -EINVAL; 504 return -EINVAL;
494 } 505 }
495 506
@@ -541,6 +552,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
541 CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); 552 CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
542 } 553 }
543 554
555 /* Tell the CX23418 it can't use our buffers anymore */
556 cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
557
544 if (s->type != CX18_ENC_STREAM_TYPE_TS) 558 if (s->type != CX18_ENC_STREAM_TYPE_TS)
545 atomic_dec(&cx->ana_capturing); 559 atomic_dec(&cx->ana_capturing);
546 atomic_dec(&cx->tot_capturing); 560 atomic_dec(&cx->tot_capturing);
@@ -549,12 +563,12 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
549 clear_bit(CX18_F_S_STREAMING, &s->s_flags); 563 clear_bit(CX18_F_S_STREAMING, &s->s_flags);
550 564
551 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); 565 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
552 s->handle = 0xffffffff; 566 s->handle = CX18_INVALID_TASK_HANDLE;
553 567
554 if (atomic_read(&cx->tot_capturing) > 0) 568 if (atomic_read(&cx->tot_capturing) > 0)
555 return 0; 569 return 0;
556 570
557 write_reg(5, CX18_DSP0_INTERRUPT_MASK); 571 cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
558 wake_up(&s->waitq); 572 wake_up(&s->waitq);
559 573
560 return 0; 574 return 0;
@@ -568,8 +582,8 @@ u32 cx18_find_handle(struct cx18 *cx)
568 for (i = 0; i < CX18_MAX_STREAMS; i++) { 582 for (i = 0; i < CX18_MAX_STREAMS; i++) {
569 struct cx18_stream *s = &cx->streams[i]; 583 struct cx18_stream *s = &cx->streams[i];
570 584
571 if (s->v4l2dev && s->handle) 585 if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE))
572 return s->handle; 586 return s->handle;
573 } 587 }
574 return 0; 588 return CX18_INVALID_TASK_HANDLE;
575} 589}