From 2e208c64e3aa7abe7b79963bb29f5d14a4b96e58 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 11 Mar 2016 16:02:14 -0300 Subject: [media] au0828: disable tuner links and cache tuner/decoder For au0828_enable_source() to work, the tuner links should be disabled and the tuner/decoder should be cached at au0828 struct. While here, put dev->decoder cache together with dev->tuner, as it makes easier to drop both latter if/when we move the enable routines to the V4L2 core. Fixes: 9822f4173f84 ('[media] au0828: use v4l2_mc_create_media_graph()') Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Shuah Khan Tested-by: Shuah Khan diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index ca861ae..6b469e8 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -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 */ diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 5dc82e8..ecfa189 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -456,7 +456,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; @@ -482,26 +483,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); - } } } -- cgit v0.10.2 From 0fed3fcef48aff793f00aca44f366ff77fa95a01 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 11 Mar 2016 12:55:16 -0300 Subject: [media] v4l2-mc: cleanup a warning A previous patch removing dtv_demod needed to be rebased, but the hunk removing the data was not merged by mistake. Fixes: 840f5b0572ea ('media: au0828 disable tuner to demod link in au0828_media_device_register()'] Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index 2a7b79b..2228cd3 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -34,7 +34,7 @@ int v4l2_mc_create_media_graph(struct media_device *mdev) { struct media_entity *entity; struct media_entity *if_vid = NULL, *if_aud = NULL; - struct media_entity *tuner = NULL, *decoder = NULL, *dtv_demod = NULL; + struct media_entity *tuner = NULL, *decoder = NULL; struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL; bool is_webcam = false; u32 flags; -- cgit v0.10.2 From ffa8576a5380e098c4f066f50c5ec812b9abef43 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Sun, 13 Mar 2016 00:57:40 -0300 Subject: [media] media: au0828 fix to clear enable/disable/change source handlers Fix to clear enable/disable/change source handlers in the media device when media device is unregistered in au0828_unregister_media_device(). When au0828 module is removed, snd-usb-audio shouldn't call the handlers. Clearing will ensure snd-usb-audio won't call them once au0828 is removed. [mchehab@osg.samsung.com: fix a compilation breakage] Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index ecfa189..2fcd17d 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -137,6 +137,11 @@ 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); dev->media_dev = NULL; -- cgit v0.10.2 From ed940cd27416f9887864b95e1f8f8845aa9d6391 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 22 Mar 2016 01:04:05 -0300 Subject: [media] au0828: fix au0828_v4l2_close() dev_state race condition au0828_v4l2_close() check for dev_state == DEV_DISCONNECTED will fail to detect the device disconnected state correctly, if au0828_v4l2_open() runs to set the DEV_INITIALIZED bit. A loop test of bind/unbind found this bug by increasing the likelihood of au0828_v4l2_open() occurring while unbind is in progress. When au0828_v4l2_close() fails to detect that the device is in disconnect state, it attempts to power down the device and fails with the following general protection fault: [ 260.992962] Call Trace: [ 260.993008] [] ? xc5000_sleep+0x8f/0xd0 [xc5000] [ 260.993095] [] ? fe_standby+0x3c/0x50 [tuner] [ 260.993186] [] au0828_v4l2_close+0x53c/0x620 [au0828] [ 260.993298] [] v4l2_release+0xf0/0x210 [videodev] [ 260.993382] [] __fput+0x1fc/0x6c0 [ 260.993449] [] ____fput+0xe/0x10 [ 260.993519] [] task_work_run+0x133/0x1f0 [ 260.993602] [] exit_to_usermode_loop+0x140/0x170 [ 260.993681] [] syscall_return_slowpath+0x16a/0x1a0 [ 260.993754] [] entry_SYSCALL_64_fastpath+0xa6/0xa8 Cc: stable@vger.kernel.org Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 13f6dab..88dcc6e 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1075,7 +1075,7 @@ static int au0828_v4l2_close(struct file *filp) del_timer_sync(&dev->vbi_timeout); } - if (dev->dev_state == DEV_DISCONNECTED) + if (dev->dev_state & DEV_DISCONNECTED) goto end; if (dev->users == 1) { -- cgit v0.10.2 From e8e3039f5b941f7825d335f8ca11c12a8104db11 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Mar 2016 09:21:57 -0300 Subject: [media] au0828: Fix dev_state handling The au0828 dev_state is actually a bit mask. It should not be checking with "==" but, instead, with a logic and. There are some places where it was doing it wrong. Fix that by replacing the dev_state set/clear/test with the bitops. As reviewed by Shuah: "Looks good. Tested running bind/unbind au0828 loop for 1000 times. Didn't see any problems and the v4l2_querycap() problem has been fixed with this patch. After the above test, ran bind/unbind snd_usb_audio 1000 times. Didn't see any problems. Generated media graph and the graph looks good." Cc: stable@vger.kernel.org Reviewed-by: Shuah Khan Tested-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 2fcd17d..a40958ad 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -171,7 +171,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 */ diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index b0f0679..3d6687f 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -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 */ @@ -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); } diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 88dcc6e..32d7db9 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -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; @@ -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) { @@ -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; } @@ -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); @@ -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); @@ -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); @@ -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) { @@ -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) @@ -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)); @@ -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; @@ -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); @@ -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); @@ -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) @@ -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; @@ -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; @@ -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; @@ -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) { @@ -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; @@ -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; } @@ -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"); @@ -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); @@ -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; @@ -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); @@ -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; @@ -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; @@ -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); @@ -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); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index ff7f851..87f3284 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -21,6 +21,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -121,9 +122,9 @@ enum au0828_stream_state { /* device state */ enum au0828_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04 + DEV_INITIALIZED = 0, + DEV_DISCONNECTED = 1, + DEV_MISCONFIGURED = 2 }; struct au0828_dev; @@ -247,7 +248,7 @@ struct au0828_dev { int input_type; int std_set_in_tuner_core; unsigned int ctrl_input; - enum au0828_dev_state dev_state; + long unsigned int dev_state; /* defined at enum au0828_dev_state */; enum au0828_stream_state stream_state; wait_queue_head_t open; -- cgit v0.10.2 From c89178f57a19300b2056f58167e183e966a4836d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 31 Mar 2016 09:57:29 -0300 Subject: [media] Revert "[media] sound/usb: Use Media Controller API to share media resources" Unfortunately, this patch caused several regressions at au0828 and snd-usb-audio, like this one: https://bugzilla.kernel.org/show_bug.cgi?id=115561 It also showed several troubles at the MC core that handles pretty poorly the memory protections and data lifetime management. So, better to revert it and fix the core before reapplying this change. This reverts commit aebb2b89bff0 ("[media] sound/usb: Use Media Controller API to share media resources")' Signed-off-by: Mauro Carvalho Chehab diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index d14bf41..a452ad7 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -15,7 +15,6 @@ config SND_USB_AUDIO select SND_RAWMIDI select SND_PCM select BITREVERSE - select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO) help Say Y here to include support for USB audio and USB MIDI devices. @@ -23,9 +22,6 @@ config SND_USB_AUDIO To compile this driver as a module, choose M here: the module will be called snd-usb-audio. -config SND_USB_AUDIO_USE_MEDIA_CONTROLLER - bool - config SND_USB_UA101 tristate "Edirol UA-101/UA-1000 driver" select SND_PCM diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 8dca3c4..2d2d122 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -15,8 +15,6 @@ snd-usb-audio-objs := card.o \ quirks.o \ stream.o -snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o - snd-usbmidi-lib-objs := midi.o # Toplevel Module Dependency diff --git a/sound/usb/card.c b/sound/usb/card.c index 63244bb..3fc6358 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -66,7 +66,6 @@ #include "format.h" #include "power.h" #include "stream.h" -#include "media.h" MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("USB Audio"); @@ -612,11 +611,6 @@ static int usb_audio_probe(struct usb_interface *intf, if (err < 0) goto __error; - if (quirk->media_device) { - /* don't want to fail when media_snd_device_create() fails */ - media_snd_device_create(chip, intf); - } - usb_chip[chip->index] = chip; chip->num_interfaces++; usb_set_intfdata(intf, chip); @@ -673,14 +667,6 @@ static void usb_audio_disconnect(struct usb_interface *intf) list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); } - /* - * Nice to check quirk && quirk->media_device - * need some special handlings. Doesn't look like - * we have access to quirk here - * Acceses mixer_list - */ - media_snd_device_delete(chip); - /* release mixer resources */ list_for_each_entry(mixer, &chip->mixer_list, list) { snd_usb_mixer_disconnect(mixer); diff --git a/sound/usb/card.h b/sound/usb/card.h index 34a0898..71778ca 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -105,8 +105,6 @@ struct snd_usb_endpoint { struct list_head list; }; -struct media_ctl; - struct snd_usb_substream { struct snd_usb_stream *stream; struct usb_device *dev; @@ -158,7 +156,6 @@ struct snd_usb_substream { } dsd_dop; bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ - struct media_ctl *media_ctl; }; struct snd_usb_stream { diff --git a/sound/usb/media.c b/sound/usb/media.c deleted file mode 100644 index 93a50d01..0000000 --- a/sound/usb/media.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * media.c - Media Controller specific ALSA driver code - * - * Copyright (c) 2016 Shuah Khan - * Copyright (c) 2016 Samsung Electronics Co., Ltd. - * - * This file is released under the GPLv2. - */ - -/* - * This file adds Media Controller support to ALSA driver - * to use the Media Controller API to share tuner with DVB - * and V4L2 drivers that control media device. Media device - * is created based on existing quirks framework. Using this - * approach, the media controller API usage can be added for - * a specific device. -*/ - -#include -#include -#include -#include -#include - -#include -#include - -#include "usbaudio.h" -#include "card.h" -#include "mixer.h" -#include "media.h" - -static int media_snd_enable_source(struct media_ctl *mctl) -{ - if (mctl && mctl->media_dev->enable_source) - return mctl->media_dev->enable_source(&mctl->media_entity, - &mctl->media_pipe); - return 0; -} - -static void media_snd_disable_source(struct media_ctl *mctl) -{ - if (mctl && mctl->media_dev->disable_source) - mctl->media_dev->disable_source(&mctl->media_entity); -} - -int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, - int stream) -{ - struct media_device *mdev; - struct media_ctl *mctl; - struct device *pcm_dev = &pcm->streams[stream].dev; - u32 intf_type; - int ret = 0; - u16 mixer_pad; - struct media_entity *entity; - - mdev = subs->stream->chip->media_dev; - if (!mdev) - return -ENODEV; - - if (subs->media_ctl) - return 0; - - /* allocate media_ctl */ - mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); - if (!mctl) - return -ENOMEM; - - mctl->media_dev = mdev; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK; - mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK; - mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE; - mixer_pad = 1; - } else { - intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE; - mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE; - mctl->media_pad.flags = MEDIA_PAD_FL_SINK; - mixer_pad = 2; - } - mctl->media_entity.name = pcm->name; - media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad); - ret = media_device_register_entity(mctl->media_dev, - &mctl->media_entity); - if (ret) - goto free_mctl; - - mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0, - MAJOR(pcm_dev->devt), - MINOR(pcm_dev->devt)); - if (!mctl->intf_devnode) { - ret = -ENOMEM; - goto unregister_entity; - } - mctl->intf_link = media_create_intf_link(&mctl->media_entity, - &mctl->intf_devnode->intf, - MEDIA_LNK_FL_ENABLED); - if (!mctl->intf_link) { - ret = -ENOMEM; - goto devnode_remove; - } - - /* create link between mixer and audio */ - media_device_for_each_entity(entity, mdev) { - switch (entity->function) { - case MEDIA_ENT_F_AUDIO_MIXER: - ret = media_create_pad_link(entity, mixer_pad, - &mctl->media_entity, 0, - MEDIA_LNK_FL_ENABLED); - if (ret) - goto remove_intf_link; - break; - } - } - - subs->media_ctl = mctl; - return 0; - -remove_intf_link: - media_remove_intf_link(mctl->intf_link); -devnode_remove: - media_devnode_remove(mctl->intf_devnode); -unregister_entity: - media_device_unregister_entity(&mctl->media_entity); -free_mctl: - kfree(mctl); - return ret; -} - -void media_snd_stream_delete(struct snd_usb_substream *subs) -{ - struct media_ctl *mctl = subs->media_ctl; - - if (mctl && mctl->media_dev) { - struct media_device *mdev; - - mdev = subs->stream->chip->media_dev; - if (mdev && media_devnode_is_registered(&mdev->devnode)) { - media_devnode_remove(mctl->intf_devnode); - media_device_unregister_entity(&mctl->media_entity); - media_entity_cleanup(&mctl->media_entity); - } - kfree(mctl); - subs->media_ctl = NULL; - } -} - -int media_snd_start_pipeline(struct snd_usb_substream *subs) -{ - struct media_ctl *mctl = subs->media_ctl; - - if (mctl) - return media_snd_enable_source(mctl); - return 0; -} - -void media_snd_stop_pipeline(struct snd_usb_substream *subs) -{ - struct media_ctl *mctl = subs->media_ctl; - - if (mctl) - media_snd_disable_source(mctl); -} - -int media_snd_mixer_init(struct snd_usb_audio *chip) -{ - struct device *ctl_dev = &chip->card->ctl_dev; - struct media_intf_devnode *ctl_intf; - struct usb_mixer_interface *mixer; - struct media_device *mdev = chip->media_dev; - struct media_mixer_ctl *mctl; - u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL; - int ret; - - if (!mdev) - return -ENODEV; - - ctl_intf = chip->ctl_intf_media_devnode; - if (!ctl_intf) { - ctl_intf = media_devnode_create(mdev, intf_type, 0, - MAJOR(ctl_dev->devt), - MINOR(ctl_dev->devt)); - if (!ctl_intf) - return -ENOMEM; - chip->ctl_intf_media_devnode = ctl_intf; - } - - list_for_each_entry(mixer, &chip->mixer_list, list) { - - if (mixer->media_mixer_ctl) - continue; - - /* allocate media_mixer_ctl */ - mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); - if (!mctl) - return -ENOMEM; - - mctl->media_dev = mdev; - mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER; - mctl->media_entity.name = chip->card->mixername; - mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK; - mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE; - mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE; - media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX, - mctl->media_pad); - ret = media_device_register_entity(mctl->media_dev, - &mctl->media_entity); - if (ret) { - kfree(mctl); - return ret; - } - - mctl->intf_link = media_create_intf_link(&mctl->media_entity, - &ctl_intf->intf, - MEDIA_LNK_FL_ENABLED); - if (!mctl->intf_link) { - media_device_unregister_entity(&mctl->media_entity); - media_entity_cleanup(&mctl->media_entity); - kfree(mctl); - return -ENOMEM; - } - mctl->intf_devnode = ctl_intf; - mixer->media_mixer_ctl = mctl; - } - return 0; -} - -static void media_snd_mixer_delete(struct snd_usb_audio *chip) -{ - struct usb_mixer_interface *mixer; - struct media_device *mdev = chip->media_dev; - - if (!mdev) - return; - - list_for_each_entry(mixer, &chip->mixer_list, list) { - struct media_mixer_ctl *mctl; - - mctl = mixer->media_mixer_ctl; - if (!mixer->media_mixer_ctl) - continue; - - if (media_devnode_is_registered(&mdev->devnode)) { - media_device_unregister_entity(&mctl->media_entity); - media_entity_cleanup(&mctl->media_entity); - } - kfree(mctl); - mixer->media_mixer_ctl = NULL; - } - if (media_devnode_is_registered(&mdev->devnode)) - media_devnode_remove(chip->ctl_intf_media_devnode); - chip->ctl_intf_media_devnode = NULL; -} - -int media_snd_device_create(struct snd_usb_audio *chip, - struct usb_interface *iface) -{ - struct media_device *mdev; - struct usb_device *usbdev = interface_to_usbdev(iface); - int ret; - - mdev = media_device_get_devres(&usbdev->dev); - if (!mdev) - return -ENOMEM; - if (!mdev->dev) { - /* register media device */ - mdev->dev = &usbdev->dev; - if (usbdev->product) - strlcpy(mdev->model, usbdev->product, - sizeof(mdev->model)); - if (usbdev->serial) - strlcpy(mdev->serial, usbdev->serial, - sizeof(mdev->serial)); - strcpy(mdev->bus_info, usbdev->devpath); - mdev->hw_revision = le16_to_cpu(usbdev->descriptor.bcdDevice); - media_device_init(mdev); - } - if (!media_devnode_is_registered(&mdev->devnode)) { - ret = media_device_register(mdev); - if (ret) { - dev_err(&usbdev->dev, - "Couldn't register media device. Error: %d\n", - ret); - return ret; - } - } - - /* save media device - avoid lookups */ - chip->media_dev = mdev; - - /* Create media entities for mixer and control dev */ - ret = media_snd_mixer_init(chip); - if (ret) { - dev_err(&usbdev->dev, - "Couldn't create media mixer entities. Error: %d\n", - ret); - - /* clear saved media_dev */ - chip->media_dev = NULL; - - return ret; - } - return 0; -} - -void media_snd_device_delete(struct snd_usb_audio *chip) -{ - struct media_device *mdev = chip->media_dev; - - media_snd_mixer_delete(chip); - - if (mdev) { - if (media_devnode_is_registered(&mdev->devnode)) - media_device_unregister(mdev); - chip->media_dev = NULL; - } -} diff --git a/sound/usb/media.h b/sound/usb/media.h deleted file mode 100644 index 1dcdcdc..0000000 --- a/sound/usb/media.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * media.h - Media Controller specific ALSA driver code - * - * Copyright (c) 2016 Shuah Khan - * Copyright (c) 2016 Samsung Electronics Co., Ltd. - * - * This file is released under the GPLv2. - */ - -/* - * This file adds Media Controller support to ALSA driver - * to use the Media Controller API to share tuner with DVB - * and V4L2 drivers that control media device. Media device - * is created based on existing quirks framework. Using this - * approach, the media controller API usage can be added for - * a specific device. -*/ -#ifndef __MEDIA_H - -#ifdef CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER - -#include -#include -#include - -struct media_ctl { - struct media_device *media_dev; - struct media_entity media_entity; - struct media_intf_devnode *intf_devnode; - struct media_link *intf_link; - struct media_pad media_pad; - struct media_pipeline media_pipe; -}; - -/* - * One source pad each for SNDRV_PCM_STREAM_CAPTURE and - * SNDRV_PCM_STREAM_PLAYBACK. One for sink pad to link - * to AUDIO Source -*/ -#define MEDIA_MIXER_PAD_MAX (SNDRV_PCM_STREAM_LAST + 2) - -struct media_mixer_ctl { - struct media_device *media_dev; - struct media_entity media_entity; - struct media_intf_devnode *intf_devnode; - struct media_link *intf_link; - struct media_pad media_pad[MEDIA_MIXER_PAD_MAX]; - struct media_pipeline media_pipe; -}; - -int media_snd_device_create(struct snd_usb_audio *chip, - struct usb_interface *iface); -void media_snd_device_delete(struct snd_usb_audio *chip); -int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, - int stream); -void media_snd_stream_delete(struct snd_usb_substream *subs); -int media_snd_start_pipeline(struct snd_usb_substream *subs); -void media_snd_stop_pipeline(struct snd_usb_substream *subs); -#else -static inline int media_snd_device_create(struct snd_usb_audio *chip, - struct usb_interface *iface) - { return 0; } -static inline void media_snd_device_delete(struct snd_usb_audio *chip) { } -static inline int media_snd_stream_init(struct snd_usb_substream *subs, - struct snd_pcm *pcm, int stream) - { return 0; } -static inline void media_snd_stream_delete(struct snd_usb_substream *subs) { } -static inline int media_snd_start_pipeline(struct snd_usb_substream *subs) - { return 0; } -static inline void media_snd_stop_pipeline(struct snd_usb_substream *subs) { } -#endif -#endif /* __MEDIA_H */ diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index f378944..3417ef3 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -3,8 +3,6 @@ #include -struct media_mixer_ctl; - struct usb_mixer_interface { struct snd_usb_audio *chip; struct usb_host_interface *hostif; @@ -24,7 +22,6 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; - struct media_mixer_ctl *media_mixer_ctl; }; #define MAX_CHANNELS 16 /* max logical channels */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0e4e0640..44d178e 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -35,7 +35,6 @@ #include "pcm.h" #include "clock.h" #include "power.h" -#include "media.h" #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 @@ -718,14 +717,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, struct audioformat *fmt; int ret; - ret = media_snd_start_pipeline(subs); - if (ret) - return ret; - ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); if (ret < 0) - goto err_ret; + return ret; subs->pcm_format = params_format(hw_params); subs->period_bytes = params_period_bytes(hw_params); @@ -739,27 +734,22 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, dev_dbg(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", subs->pcm_format, subs->cur_rate, subs->channels); - ret = -EINVAL; - goto err_ret; + return -EINVAL; } ret = snd_usb_lock_shutdown(subs->stream->chip); if (ret < 0) - goto err_ret; + return ret; ret = set_format(subs, fmt); snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) - goto err_ret; + return ret; subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; subs->need_setup_ep = true; return 0; - -err_ret: - media_snd_stop_pipeline(subs); - return ret; } /* @@ -771,7 +761,6 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) { struct snd_usb_substream *subs = substream->runtime->private_data; - media_snd_stop_pipeline(subs); subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; @@ -1232,7 +1221,6 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = &as->substream[direction]; - int ret; subs->interface = -1; subs->altset_idx = 0; @@ -1246,12 +1234,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) subs->dsd_dop.channel = 0; subs->dsd_dop.marker = 1; - ret = setup_hw_info(runtime, subs); - if (ret == 0) - ret = media_snd_stream_init(subs, as->pcm, direction); - if (ret) - snd_usb_autosuspend(subs->stream->chip); - return ret; + return setup_hw_info(runtime, subs); } static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) @@ -1260,7 +1243,6 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) struct snd_usb_substream *subs = &as->substream[direction]; stop_endpoints(subs, true); - media_snd_stop_pipeline(subs); if (subs->interface >= 0 && !snd_usb_lock_shutdown(subs->stream->chip)) { diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 9d087b1..c60a776 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2886,7 +2886,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), .product_name = pname, \ .ifnum = QUIRK_ANY_INTERFACE, \ .type = QUIRK_AUDIO_ALIGN_TRANSFER, \ - .media_device = 1, \ } \ } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 51258a1..c4dc577 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -36,7 +36,6 @@ #include "format.h" #include "clock.h" #include "stream.h" -#include "media.h" /* * free a substream @@ -53,7 +52,6 @@ static void free_substream(struct snd_usb_substream *subs) kfree(fp); } kfree(subs->rate_list.list); - media_snd_stream_delete(subs); } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index a161c7c..b665d85 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -30,9 +30,6 @@ * */ -struct media_device; -struct media_intf_devnode; - struct snd_usb_audio { int index; struct usb_device *dev; @@ -63,8 +60,6 @@ struct snd_usb_audio { bool autoclock; /* from the 'autoclock' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ - struct media_device *media_dev; - struct media_intf_devnode *ctl_intf_media_devnode; }; #define usb_audio_err(chip, fmt, args...) \ @@ -115,7 +110,6 @@ struct snd_usb_audio_quirk { const char *product_name; int16_t ifnum; uint16_t type; - bool media_device; const void *data; }; -- cgit v0.10.2 From 405ddbfa68177b6169d09bc2308a39196a8eb64a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 31 Mar 2016 10:54:05 -0300 Subject: [media] Revert "[media] media: au0828 change to use Managed Media Controller API" Extending the lifetime of the media_device struct is not handled well by the core, as it will erase some data from the struct, when media_device_cleanup() is called after unregistering it. While we have a fixup patch for it already, the usage of those new functions are needed only when we share data with other drivers. So, better to revert the changes. This reverts commit 182dde7c5d4c ("[media] media: au0828 change to use Managed Media Controller API") Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index a40958ad..cc22b32 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -144,6 +144,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev) media_device_unregister(dev->media_dev); media_device_cleanup(dev->media_dev); + kfree(dev->media_dev); dev->media_dev = NULL; } #endif @@ -197,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; -- cgit v0.10.2