diff options
author | Antti Palosaari <crope@iki.fi> | 2013-03-09 14:10:55 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-23 09:02:04 -0400 |
commit | 96d7ca5ec9baac231ab3dfd62abcb75141d80626 (patch) | |
tree | ee45b36c9c4de19fb9b8d83467fc651696bc8b85 | |
parent | 61356eea6742ad38ad9ecfd5c65e2662e4c9d8ab (diff) |
[media] dvb_usb_v2: rework USB streaming logic
Control flow order changed a little bit. HW PID filter is now
disabled also when streaming is stopped - earlier it was just
set only when streaming was started.
Control flow is now:
* set streaming status bit
* submit USB streaming packets
* enable HW PID filter
* ask device to start streaming
* N x add PID to device HW PID filter
... streaming video ...
* N x remove PID from device HW PID filter
* ask device to stop streaming
* disable HW PID filter
* kill USB streaming packets
* clear streaming status bit
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 215 |
1 files changed, 116 insertions, 99 deletions
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 9b24a0e9675a..19f6737d9817 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | |||
@@ -260,135 +260,152 @@ static int wait_schedule(void *ptr) | |||
260 | return 0; | 260 | return 0; |
261 | } | 261 | } |
262 | 262 | ||
263 | static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, | 263 | static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) |
264 | int count) | ||
265 | { | 264 | { |
266 | struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; | 265 | struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; |
267 | struct dvb_usb_device *d = adap_to_d(adap); | 266 | struct dvb_usb_device *d = adap_to_d(adap); |
268 | int ret; | 267 | int ret = 0; |
269 | dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d '%s'\n", | 268 | struct usb_data_stream_properties stream_props; |
269 | dev_dbg(&d->udev->dev, | ||
270 | "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n", | ||
270 | __func__, adap->id, adap->active_fe, dvbdmxfeed->type, | 271 | __func__, adap->id, adap->active_fe, dvbdmxfeed->type, |
271 | adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, | 272 | adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, |
272 | dvbdmxfeed->pid, dvbdmxfeed->index, | 273 | dvbdmxfeed->pid, dvbdmxfeed->index); |
273 | (count == 1) ? "on" : "off"); | ||
274 | 274 | ||
275 | /* wait init is done */ | ||
275 | wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule, | 276 | wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule, |
276 | TASK_UNINTERRUPTIBLE); | 277 | TASK_UNINTERRUPTIBLE); |
277 | 278 | ||
278 | if (adap->active_fe == -1) | 279 | if (adap->active_fe == -1) |
279 | return -EINVAL; | 280 | return -EINVAL; |
280 | 281 | ||
281 | adap->feed_count += count; | 282 | /* skip feed setup if we are already feeding */ |
282 | 283 | if (adap->feed_count++ > 0) | |
283 | /* stop feeding if it is last pid */ | 284 | goto skip_feed_start; |
284 | if (adap->feed_count == 0) { | ||
285 | dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); | ||
286 | |||
287 | if (d->props->streaming_ctrl) { | ||
288 | ret = d->props->streaming_ctrl( | ||
289 | adap->fe[adap->active_fe], 0); | ||
290 | if (ret < 0) { | ||
291 | dev_err(&d->udev->dev, | ||
292 | "%s: streaming_ctrl() failed=%d\n", | ||
293 | KBUILD_MODNAME, ret); | ||
294 | usb_urb_killv2(&adap->stream); | ||
295 | goto err_clear_wait; | ||
296 | } | ||
297 | } | ||
298 | usb_urb_killv2(&adap->stream); | ||
299 | 285 | ||
300 | clear_bit(ADAP_STREAMING, &adap->state_bits); | 286 | /* set 'streaming' status bit */ |
301 | smp_mb__after_clear_bit(); | 287 | set_bit(ADAP_STREAMING, &adap->state_bits); |
302 | wake_up_bit(&adap->state_bits, ADAP_STREAMING); | 288 | |
289 | /* resolve input and output streaming parameters */ | ||
290 | if (d->props->get_stream_config) { | ||
291 | memcpy(&stream_props, &adap->props->stream, | ||
292 | sizeof(struct usb_data_stream_properties)); | ||
293 | ret = d->props->get_stream_config(adap->fe[adap->active_fe], | ||
294 | &adap->ts_type, &stream_props); | ||
295 | if (ret) | ||
296 | dev_err(&d->udev->dev, | ||
297 | "%s: get_stream_config() failed=%d\n", | ||
298 | KBUILD_MODNAME, ret); | ||
299 | } else { | ||
300 | stream_props = adap->props->stream; | ||
301 | } | ||
302 | |||
303 | switch (adap->ts_type) { | ||
304 | case DVB_USB_FE_TS_TYPE_204: | ||
305 | adap->stream.complete = dvb_usb_data_complete_204; | ||
306 | break; | ||
307 | case DVB_USB_FE_TS_TYPE_RAW: | ||
308 | adap->stream.complete = dvb_usb_data_complete_raw; | ||
309 | break; | ||
310 | case DVB_USB_FE_TS_TYPE_188: | ||
311 | default: | ||
312 | adap->stream.complete = dvb_usb_data_complete; | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | /* submit USB streaming packets */ | ||
317 | usb_urb_submitv2(&adap->stream, &stream_props); | ||
318 | |||
319 | /* enable HW PID filter */ | ||
320 | if (adap->pid_filtering && adap->props->pid_filter_ctrl) { | ||
321 | ret = adap->props->pid_filter_ctrl(adap, 1); | ||
322 | if (ret) | ||
323 | dev_err(&d->udev->dev, | ||
324 | "%s: pid_filter_ctrl() failed=%d\n", | ||
325 | KBUILD_MODNAME, ret); | ||
303 | } | 326 | } |
304 | 327 | ||
305 | /* activate the pid on the device pid filter */ | 328 | /* ask device to start streaming */ |
306 | if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && | 329 | if (d->props->streaming_ctrl) { |
307 | adap->pid_filtering && adap->props->pid_filter) { | 330 | ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 1); |
331 | if (ret) | ||
332 | dev_err(&d->udev->dev, | ||
333 | "%s: streaming_ctrl() failed=%d\n", | ||
334 | KBUILD_MODNAME, ret); | ||
335 | } | ||
336 | skip_feed_start: | ||
337 | |||
338 | /* add PID to device HW PID filter */ | ||
339 | if (adap->pid_filtering && adap->props->pid_filter) { | ||
308 | ret = adap->props->pid_filter(adap, dvbdmxfeed->index, | 340 | ret = adap->props->pid_filter(adap, dvbdmxfeed->index, |
309 | dvbdmxfeed->pid, (count == 1) ? 1 : 0); | 341 | dvbdmxfeed->pid, 1); |
310 | if (ret < 0) | 342 | if (ret) |
311 | dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", | 343 | dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", |
312 | KBUILD_MODNAME, ret); | 344 | KBUILD_MODNAME, ret); |
313 | } | 345 | } |
314 | 346 | ||
315 | /* start feeding if it is first pid */ | 347 | if (ret) |
316 | if (adap->feed_count == 1 && count == 1) { | 348 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); |
317 | struct usb_data_stream_properties stream_props; | 349 | return ret; |
318 | set_bit(ADAP_STREAMING, &adap->state_bits); | 350 | } |
319 | dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); | ||
320 | 351 | ||
321 | /* resolve input and output streaming paramters */ | 352 | static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) |
322 | if (d->props->get_stream_config) { | 353 | { |
323 | memcpy(&stream_props, &adap->props->stream, | 354 | struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; |
324 | sizeof(struct usb_data_stream_properties)); | 355 | struct dvb_usb_device *d = adap_to_d(adap); |
325 | ret = d->props->get_stream_config( | 356 | int ret = 0; |
326 | adap->fe[adap->active_fe], | 357 | dev_dbg(&d->udev->dev, |
327 | &adap->ts_type, &stream_props); | 358 | "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n", |
328 | if (ret < 0) | 359 | __func__, adap->id, adap->active_fe, dvbdmxfeed->type, |
329 | goto err_clear_wait; | 360 | adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, |
330 | } else { | 361 | dvbdmxfeed->pid, dvbdmxfeed->index); |
331 | stream_props = adap->props->stream; | ||
332 | } | ||
333 | 362 | ||
334 | switch (adap->ts_type) { | 363 | if (adap->active_fe == -1) |
335 | case DVB_USB_FE_TS_TYPE_204: | 364 | return -EINVAL; |
336 | adap->stream.complete = dvb_usb_data_complete_204; | ||
337 | break; | ||
338 | case DVB_USB_FE_TS_TYPE_RAW: | ||
339 | adap->stream.complete = dvb_usb_data_complete_raw; | ||
340 | break; | ||
341 | case DVB_USB_FE_TS_TYPE_188: | ||
342 | default: | ||
343 | adap->stream.complete = dvb_usb_data_complete; | ||
344 | break; | ||
345 | } | ||
346 | 365 | ||
347 | usb_urb_submitv2(&adap->stream, &stream_props); | 366 | /* remove PID from device HW PID filter */ |
348 | 367 | if (adap->pid_filtering && adap->props->pid_filter) { | |
349 | if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && | 368 | ret = adap->props->pid_filter(adap, dvbdmxfeed->index, |
350 | adap->props->caps & | 369 | dvbdmxfeed->pid, 0); |
351 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && | 370 | if (ret) |
352 | adap->props->pid_filter_ctrl) { | 371 | dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", |
353 | ret = adap->props->pid_filter_ctrl(adap, | 372 | KBUILD_MODNAME, ret); |
354 | adap->pid_filtering); | 373 | } |
355 | if (ret < 0) { | ||
356 | dev_err(&d->udev->dev, | ||
357 | "%s: pid_filter_ctrl() failed=%d\n", | ||
358 | KBUILD_MODNAME, ret); | ||
359 | goto err_clear_wait; | ||
360 | } | ||
361 | } | ||
362 | 374 | ||
363 | if (d->props->streaming_ctrl) { | 375 | /* we cannot stop streaming until last PID is removed */ |
364 | ret = d->props->streaming_ctrl( | 376 | if (--adap->feed_count > 0) |
365 | adap->fe[adap->active_fe], 1); | 377 | goto skip_feed_stop; |
366 | if (ret < 0) { | 378 | |
367 | dev_err(&d->udev->dev, | 379 | /* ask device to stop streaming */ |
368 | "%s: streaming_ctrl() failed=%d\n", | 380 | if (d->props->streaming_ctrl) { |
369 | KBUILD_MODNAME, ret); | 381 | ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 0); |
370 | goto err_clear_wait; | 382 | if (ret) |
371 | } | 383 | dev_err(&d->udev->dev, |
372 | } | 384 | "%s: streaming_ctrl() failed=%d\n", |
385 | KBUILD_MODNAME, ret); | ||
373 | } | 386 | } |
374 | 387 | ||
375 | return 0; | 388 | /* disable HW PID filter */ |
376 | err_clear_wait: | 389 | if (adap->pid_filtering && adap->props->pid_filter_ctrl) { |
390 | ret = adap->props->pid_filter_ctrl(adap, 0); | ||
391 | if (ret) | ||
392 | dev_err(&d->udev->dev, | ||
393 | "%s: pid_filter_ctrl() failed=%d\n", | ||
394 | KBUILD_MODNAME, ret); | ||
395 | } | ||
396 | |||
397 | /* kill USB streaming packets */ | ||
398 | usb_urb_killv2(&adap->stream); | ||
399 | |||
400 | /* clear 'streaming' status bit */ | ||
377 | clear_bit(ADAP_STREAMING, &adap->state_bits); | 401 | clear_bit(ADAP_STREAMING, &adap->state_bits); |
378 | smp_mb__after_clear_bit(); | 402 | smp_mb__after_clear_bit(); |
379 | wake_up_bit(&adap->state_bits, ADAP_STREAMING); | 403 | wake_up_bit(&adap->state_bits, ADAP_STREAMING); |
380 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 404 | skip_feed_stop: |
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
385 | { | ||
386 | return dvb_usb_ctrl_feed(dvbdmxfeed, 1); | ||
387 | } | ||
388 | 405 | ||
389 | static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | 406 | if (ret) |
390 | { | 407 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); |
391 | return dvb_usb_ctrl_feed(dvbdmxfeed, -1); | 408 | return ret; |
392 | } | 409 | } |
393 | 410 | ||
394 | static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) | 411 | static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) |