Commit 96d7ca5e authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[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: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 61356eea
...@@ -260,135 +260,152 @@ static int wait_schedule(void *ptr) ...@@ -260,135 +260,152 @@ static int wait_schedule(void *ptr)
return 0; return 0;
} }
static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
int count)
{ {
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
struct dvb_usb_device *d = adap_to_d(adap); struct dvb_usb_device *d = adap_to_d(adap);
int ret; int ret = 0;
dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d '%s'\n", struct usb_data_stream_properties stream_props;
dev_dbg(&d->udev->dev,
"%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n",
__func__, adap->id, adap->active_fe, dvbdmxfeed->type, __func__, adap->id, adap->active_fe, dvbdmxfeed->type,
adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
dvbdmxfeed->pid, dvbdmxfeed->index, dvbdmxfeed->pid, dvbdmxfeed->index);
(count == 1) ? "on" : "off");
/* wait init is done */
wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule, wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
if (adap->active_fe == -1) if (adap->active_fe == -1)
return -EINVAL; return -EINVAL;
adap->feed_count += count; /* skip feed setup if we are already feeding */
if (adap->feed_count++ > 0)
/* stop feeding if it is last pid */ goto skip_feed_start;
if (adap->feed_count == 0) {
dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__);
if (d->props->streaming_ctrl) {
ret = d->props->streaming_ctrl(
adap->fe[adap->active_fe], 0);
if (ret < 0) {
dev_err(&d->udev->dev,
"%s: streaming_ctrl() failed=%d\n",
KBUILD_MODNAME, ret);
usb_urb_killv2(&adap->stream);
goto err_clear_wait;
}
}
usb_urb_killv2(&adap->stream);
clear_bit(ADAP_STREAMING, &adap->state_bits); /* set 'streaming' status bit */
smp_mb__after_clear_bit(); set_bit(ADAP_STREAMING, &adap->state_bits);
wake_up_bit(&adap->state_bits, ADAP_STREAMING);
/* resolve input and output streaming parameters */
if (d->props->get_stream_config) {
memcpy(&stream_props, &adap->props->stream,
sizeof(struct usb_data_stream_properties));
ret = d->props->get_stream_config(adap->fe[adap->active_fe],
&adap->ts_type, &stream_props);
if (ret)
dev_err(&d->udev->dev,
"%s: get_stream_config() failed=%d\n",
KBUILD_MODNAME, ret);
} else {
stream_props = adap->props->stream;
}
switch (adap->ts_type) {
case DVB_USB_FE_TS_TYPE_204:
adap->stream.complete = dvb_usb_data_complete_204;
break;
case DVB_USB_FE_TS_TYPE_RAW:
adap->stream.complete = dvb_usb_data_complete_raw;
break;
case DVB_USB_FE_TS_TYPE_188:
default:
adap->stream.complete = dvb_usb_data_complete;
break;
}
/* submit USB streaming packets */
usb_urb_submitv2(&adap->stream, &stream_props);
/* enable HW PID filter */
if (adap->pid_filtering && adap->props->pid_filter_ctrl) {
ret = adap->props->pid_filter_ctrl(adap, 1);
if (ret)
dev_err(&d->udev->dev,
"%s: pid_filter_ctrl() failed=%d\n",
KBUILD_MODNAME, ret);
} }
/* activate the pid on the device pid filter */ /* ask device to start streaming */
if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && if (d->props->streaming_ctrl) {
adap->pid_filtering && adap->props->pid_filter) { ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 1);
if (ret)
dev_err(&d->udev->dev,
"%s: streaming_ctrl() failed=%d\n",
KBUILD_MODNAME, ret);
}
skip_feed_start:
/* add PID to device HW PID filter */
if (adap->pid_filtering && adap->props->pid_filter) {
ret = adap->props->pid_filter(adap, dvbdmxfeed->index, ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
dvbdmxfeed->pid, (count == 1) ? 1 : 0); dvbdmxfeed->pid, 1);
if (ret < 0) if (ret)
dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
KBUILD_MODNAME, ret); KBUILD_MODNAME, ret);
} }
/* start feeding if it is first pid */ if (ret)
if (adap->feed_count == 1 && count == 1) { dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
struct usb_data_stream_properties stream_props; return ret;
set_bit(ADAP_STREAMING, &adap->state_bits); }
dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__);
/* resolve input and output streaming paramters */ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
if (d->props->get_stream_config) { {
memcpy(&stream_props, &adap->props->stream, struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
sizeof(struct usb_data_stream_properties)); struct dvb_usb_device *d = adap_to_d(adap);
ret = d->props->get_stream_config( int ret = 0;
adap->fe[adap->active_fe], dev_dbg(&d->udev->dev,
&adap->ts_type, &stream_props); "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n",
if (ret < 0) __func__, adap->id, adap->active_fe, dvbdmxfeed->type,
goto err_clear_wait; adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
} else { dvbdmxfeed->pid, dvbdmxfeed->index);
stream_props = adap->props->stream;
}
switch (adap->ts_type) { if (adap->active_fe == -1)
case DVB_USB_FE_TS_TYPE_204: return -EINVAL;
adap->stream.complete = dvb_usb_data_complete_204;
break;
case DVB_USB_FE_TS_TYPE_RAW:
adap->stream.complete = dvb_usb_data_complete_raw;
break;
case DVB_USB_FE_TS_TYPE_188:
default:
adap->stream.complete = dvb_usb_data_complete;
break;
}
usb_urb_submitv2(&adap->stream, &stream_props); /* remove PID from device HW PID filter */
if (adap->pid_filtering && adap->props->pid_filter) {
if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
adap->props->caps & dvbdmxfeed->pid, 0);
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && if (ret)
adap->props->pid_filter_ctrl) { dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
ret = adap->props->pid_filter_ctrl(adap, KBUILD_MODNAME, ret);
adap->pid_filtering); }
if (ret < 0) {
dev_err(&d->udev->dev,
"%s: pid_filter_ctrl() failed=%d\n",
KBUILD_MODNAME, ret);
goto err_clear_wait;
}
}
if (d->props->streaming_ctrl) { /* we cannot stop streaming until last PID is removed */
ret = d->props->streaming_ctrl( if (--adap->feed_count > 0)
adap->fe[adap->active_fe], 1); goto skip_feed_stop;
if (ret < 0) {
dev_err(&d->udev->dev, /* ask device to stop streaming */
"%s: streaming_ctrl() failed=%d\n", if (d->props->streaming_ctrl) {
KBUILD_MODNAME, ret); ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 0);
goto err_clear_wait; if (ret)
} dev_err(&d->udev->dev,
} "%s: streaming_ctrl() failed=%d\n",
KBUILD_MODNAME, ret);
} }
return 0; /* disable HW PID filter */
err_clear_wait: if (adap->pid_filtering && adap->props->pid_filter_ctrl) {
ret = adap->props->pid_filter_ctrl(adap, 0);
if (ret)
dev_err(&d->udev->dev,
"%s: pid_filter_ctrl() failed=%d\n",
KBUILD_MODNAME, ret);
}
/* kill USB streaming packets */
usb_urb_killv2(&adap->stream);
/* clear 'streaming' status bit */
clear_bit(ADAP_STREAMING, &adap->state_bits); clear_bit(ADAP_STREAMING, &adap->state_bits);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
wake_up_bit(&adap->state_bits, ADAP_STREAMING); wake_up_bit(&adap->state_bits, ADAP_STREAMING);
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); skip_feed_stop:
return ret;
}
static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
}
static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) if (ret)
{ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return dvb_usb_ctrl_feed(dvbdmxfeed, -1); return ret;
} }
static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment