diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-streams.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 70 |
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 = { | |||
56 | static struct { | 57 | static 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 | } |