Skip to content

Commit

Permalink
Merge tag 'media/v4.6-3' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mchehab/linux-media

Pull media fixes from Mauro Carvalho Chehab:
 "Some bug fixes on au0828 and snd-usb-audio:

   - the au0828+snd-usb-audio MC patch broke several things and produced
     some race conditions.  Better to revert the patches, and re-work on
     them for a next version

   - fix a regression at tuner disable links logic

   - properly handle dev_state as a bitmask"

* tag 'media/v4.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  [media] Revert "[media] media: au0828 change to use Managed Media Controller API"
  [media] Revert "[media] sound/usb: Use Media Controller API to share media resources"
  [media] au0828: Fix dev_state handling
  [media] au0828: fix au0828_v4l2_close() dev_state race condition
  [media] media: au0828 fix to clear enable/disable/change source handlers
  [media] v4l2-mc: cleanup a warning
  [media] au0828: disable tuner links and cache tuner/decoder
  • Loading branch information
torvalds committed Apr 5, 2016
2 parents 1e1e5ce + 405ddbf commit 62d2def
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 507 deletions.
4 changes: 0 additions & 4 deletions drivers/media/usb/au0828/au0828-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,6 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev)
"au8522", 0x8e >> 1, NULL);
if (sd == NULL)
pr_err("analog subdev registration failed\n");
#ifdef CONFIG_MEDIA_CONTROLLER
if (sd)
dev->decoder = &sd->entity;
#endif
}

/* Setup tuners */
Expand Down
52 changes: 35 additions & 17 deletions drivers/media/usb/au0828/au0828-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,14 @@ static void au0828_unregister_media_device(struct au0828_dev *dev)
#ifdef CONFIG_MEDIA_CONTROLLER
if (dev->media_dev &&
media_devnode_is_registered(&dev->media_dev->devnode)) {
/* clear enable_source, disable_source */
dev->media_dev->source_priv = NULL;
dev->media_dev->enable_source = NULL;
dev->media_dev->disable_source = NULL;

media_device_unregister(dev->media_dev);
media_device_cleanup(dev->media_dev);
kfree(dev->media_dev);
dev->media_dev = NULL;
}
#endif
Expand Down Expand Up @@ -166,7 +172,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
Set the status so poll routines can check and avoid
access after disconnect.
*/
dev->dev_state = DEV_DISCONNECTED;
set_bit(DEV_DISCONNECTED, &dev->dev_state);

au0828_rc_unregister(dev);
/* Digital TV */
Expand All @@ -192,7 +198,7 @@ static int au0828_media_device_init(struct au0828_dev *dev,
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device *mdev;

mdev = media_device_get_devres(&udev->dev);
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev)
return -ENOMEM;

Expand Down Expand Up @@ -456,7 +462,8 @@ static int au0828_media_device_register(struct au0828_dev *dev,
{
#ifdef CONFIG_MEDIA_CONTROLLER
int ret;
struct media_entity *entity, *demod = NULL, *tuner = NULL;
struct media_entity *entity, *demod = NULL;
struct media_link *link;

if (!dev->media_dev)
return 0;
Expand All @@ -482,26 +489,37 @@ static int au0828_media_device_register(struct au0828_dev *dev,
}

/*
* Find tuner and demod to disable the link between
* the two to avoid disable step when tuner is requested
* by video or audio. Note that this step can't be done
* until dvb graph is created during dvb register.
* Find tuner, decoder and demod.
*
* The tuner and decoder should be cached, as they'll be used by
* au0828_enable_source.
*
* It also needs to disable the link between tuner and
* decoder/demod, to avoid disable step when tuner is requested
* by video or audio. Note that this step can't be done until dvb
* graph is created during dvb register.
*/
media_device_for_each_entity(entity, dev->media_dev) {
if (entity->function == MEDIA_ENT_F_DTV_DEMOD)
switch (entity->function) {
case MEDIA_ENT_F_TUNER:
dev->tuner = entity;
break;
case MEDIA_ENT_F_ATV_DECODER:
dev->decoder = entity;
break;
case MEDIA_ENT_F_DTV_DEMOD:
demod = entity;
else if (entity->function == MEDIA_ENT_F_TUNER)
tuner = entity;
break;
}
}
/* Disable link between tuner and demod */
if (tuner && demod) {
struct media_link *link;

list_for_each_entry(link, &demod->links, list) {
if (link->sink->entity == demod &&
link->source->entity == tuner) {
/* Disable link between tuner->demod and/or tuner->decoder */
if (dev->tuner) {
list_for_each_entry(link, &dev->tuner->links, list) {
if (demod && link->sink->entity == demod)
media_entity_setup_link(link, 0);
if (dev->decoder && link->sink->entity == dev->decoder)
media_entity_setup_link(link, 0);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/media/usb/au0828/au0828-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
bool first = true;

/* do nothing if device is disconnected */
if (ir->dev->dev_state == DEV_DISCONNECTED)
if (test_bit(DEV_DISCONNECTED, &ir->dev->dev_state))
return 0;

/* Check IR int */
Expand Down Expand Up @@ -260,7 +260,7 @@ static void au0828_rc_stop(struct rc_dev *rc)
cancel_delayed_work_sync(&ir->work);

/* do nothing if device is disconnected */
if (ir->dev->dev_state != DEV_DISCONNECTED) {
if (!test_bit(DEV_DISCONNECTED, &ir->dev->dev_state)) {
/* Disable IR */
au8522_rc_clear(ir, 0xe0, 1 << 4);
}
Expand Down
63 changes: 31 additions & 32 deletions drivers/media/usb/au0828/au0828-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,13 @@ static inline void print_err_status(struct au0828_dev *dev,

static int check_dev(struct au0828_dev *dev)
{
if (dev->dev_state & DEV_DISCONNECTED) {
if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) {
pr_info("v4l2 ioctl: device not present\n");
return -ENODEV;
}

if (dev->dev_state & DEV_MISCONFIGURED) {
pr_info("v4l2 ioctl: device is misconfigured; "
"close and open it again\n");
if (test_bit(DEV_MISCONFIGURED, &dev->dev_state)) {
pr_info("v4l2 ioctl: device is misconfigured; close and open it again\n");
return -EIO;
}
return 0;
Expand Down Expand Up @@ -521,8 +520,8 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
if (!dev)
return 0;

if ((dev->dev_state & DEV_DISCONNECTED) ||
(dev->dev_state & DEV_MISCONFIGURED))
if (test_bit(DEV_DISCONNECTED, &dev->dev_state) ||
test_bit(DEV_MISCONFIGURED, &dev->dev_state))
return 0;

if (urb->status < 0) {
Expand Down Expand Up @@ -824,10 +823,10 @@ static int au0828_stream_interrupt(struct au0828_dev *dev)
int ret = 0;

dev->stream_state = STREAM_INTERRUPT;
if (dev->dev_state == DEV_DISCONNECTED)
if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
return -ENODEV;
else if (ret) {
dev->dev_state = DEV_MISCONFIGURED;
set_bit(DEV_MISCONFIGURED, &dev->dev_state);
dprintk(1, "%s device is misconfigured!\n", __func__);
return ret;
}
Expand Down Expand Up @@ -1026,7 +1025,7 @@ static int au0828_v4l2_open(struct file *filp)
int ret;

dprintk(1,
"%s called std_set %d dev_state %d stream users %d users %d\n",
"%s called std_set %d dev_state %ld stream users %d users %d\n",
__func__, dev->std_set_in_tuner_core, dev->dev_state,
dev->streaming_users, dev->users);

Expand All @@ -1045,7 +1044,7 @@ static int au0828_v4l2_open(struct file *filp)
au0828_analog_stream_enable(dev);
au0828_analog_stream_reset(dev);
dev->stream_state = STREAM_OFF;
dev->dev_state |= DEV_INITIALIZED;
set_bit(DEV_INITIALIZED, &dev->dev_state);
}
dev->users++;
mutex_unlock(&dev->lock);
Expand All @@ -1059,7 +1058,7 @@ static int au0828_v4l2_close(struct file *filp)
struct video_device *vdev = video_devdata(filp);

dprintk(1,
"%s called std_set %d dev_state %d stream users %d users %d\n",
"%s called std_set %d dev_state %ld stream users %d users %d\n",
__func__, dev->std_set_in_tuner_core, dev->dev_state,
dev->streaming_users, dev->users);

Expand All @@ -1075,7 +1074,7 @@ static int au0828_v4l2_close(struct file *filp)
del_timer_sync(&dev->vbi_timeout);
}

if (dev->dev_state == DEV_DISCONNECTED)
if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
goto end;

if (dev->users == 1) {
Expand Down Expand Up @@ -1135,7 +1134,7 @@ static void au0828_init_tuner(struct au0828_dev *dev)
.type = V4L2_TUNER_ANALOG_TV,
};

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

if (dev->std_set_in_tuner_core)
Expand Down Expand Up @@ -1207,7 +1206,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

strlcpy(cap->driver, "au0828", sizeof(cap->driver));
Expand Down Expand Up @@ -1250,7 +1249,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

f->fmt.pix.width = dev->width;
Expand All @@ -1269,7 +1268,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
Expand All @@ -1281,7 +1280,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct au0828_dev *dev = video_drvdata(file);
int rc;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

rc = check_dev(dev);
Expand All @@ -1303,7 +1302,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

if (norm == dev->std)
Expand Down Expand Up @@ -1335,7 +1334,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

*norm = dev->std;
Expand All @@ -1357,7 +1356,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
[AU0828_VMUX_DVB] = "DVB",
};

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

tmp = input->index;
Expand Down Expand Up @@ -1387,7 +1386,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

*i = dev->ctrl_input;
Expand All @@ -1398,7 +1397,7 @@ static void au0828_s_input(struct au0828_dev *dev, int index)
{
int i;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

switch (AUVI_INPUT(index).type) {
Expand Down Expand Up @@ -1496,7 +1495,7 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

a->index = dev->ctrl_ainput;
Expand All @@ -1516,7 +1515,7 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
if (a->index != dev->ctrl_ainput)
return -EINVAL;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);
return 0;
}
Expand All @@ -1534,7 +1533,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (ret)
return ret;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

strcpy(t->name, "Auvitek tuner");
Expand All @@ -1554,7 +1553,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

au0828_init_tuner(dev);
Expand All @@ -1576,7 +1575,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,

if (freq->tuner != 0)
return -EINVAL;
dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);
freq->frequency = dev->ctrl_freq;
return 0;
Expand All @@ -1591,7 +1590,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (freq->tuner != 0)
return -EINVAL;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

au0828_init_tuner(dev);
Expand All @@ -1617,7 +1616,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

format->fmt.vbi.samples_per_line = dev->vbi_width;
Expand All @@ -1643,7 +1642,7 @@ static int vidioc_cropcap(struct file *file, void *priv,
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

cc->bounds.left = 0;
Expand All @@ -1665,7 +1664,7 @@ static int vidioc_g_register(struct file *file, void *priv,
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

reg->val = au0828_read(dev, reg->reg);
Expand All @@ -1678,7 +1677,7 @@ static int vidioc_s_register(struct file *file, void *priv,
{
struct au0828_dev *dev = video_drvdata(file);

dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);

return au0828_writereg(dev, reg->reg, reg->val);
Expand Down
Loading

0 comments on commit 62d2def

Please sign in to comment.