au0828 is changed to use token devres as a large locking for exclusive access to tuner function. A new tuner_tkn field is added to struct au0828_dev. Tuner token is created from au0828 probe() and destroyed from disconnect(). Two new routines au0828_create_token_resources() and au0828_destroy_token_resources() create and destroy the tuner token. au0828-dvb exports the tuner token to dvb-frontend when it registers the digital frontend using the tuner_tkn field in struct dvb_frontend. au0828-video exports the tuner token to v4l2-core when it registers the analog function using tuner_tkn field in struct video_device. Before this change: - digital tv app disrupts an active analog app when it tries to use the tuner e.g: tvtime analog video stream stops when kaffeine starts - analog tv app disrupts another analog app when it tries to use the tuner e.g: tvtime audio glitches when xawtv starts and vice versa. - analog tv app disrupts an active digital app when it tries to use the tuner e.g: kaffeine digital stream stops when tvtime starts - digital tv app disrupts another digital tv app when it tries to use the tuner e.g: kaffeine digital stream stops when vlc starts and vice versa After this change: - digital tv app detects tuner is busy without disrupting the active app. - analog tv app detects tuner is busy without disrupting the active analog app. - analog tv app detects tuner is busy without disrupting the active digital app. - digital tv app detects tuner is busy without disrupting the active digital app. Signed-off-by: Shuah Khan <shuah.kh@xxxxxxxxxxx> --- drivers/media/usb/au0828/au0828-core.c | 42 +++++++++++++++++++++++++++++++ drivers/media/usb/au0828/au0828-dvb.c | 1 + drivers/media/usb/au0828/au0828-video.c | 4 +++ drivers/media/usb/au0828/au0828.h | 4 +++ 4 files changed, 51 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index ab45a6f..df04a99 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -125,6 +125,37 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, return status; } +/* interfaces to create and destroy token resources */ +static int au0828_create_token_resources(struct au0828_dev *dev) +{ + int rc = 0, len; + char buf[64]; + + /* create token devres for tuner */ + len = snprintf(buf, sizeof(buf), + "tuner:%s-%s-%d", + dev_name(&dev->usbdev->dev), + dev->usbdev->bus->bus_name, + dev->board.tuner_addr); + + dev->tuner_tkn = devm_kzalloc(&dev->usbdev->dev, len + 1, GFP_KERNEL); + if (!dev->tuner_tkn) + return -ENOMEM; + + strcpy(dev->tuner_tkn, buf); + rc = devm_token_create(&dev->usbdev->dev, dev->tuner_tkn); + if (rc) + return rc; + + pr_info("au0828_create_token_resources(): Tuner token created\n"); + return rc; +} + +static void au0828_destroy_token_resources(struct au0828_dev *dev) +{ + devm_token_destroy(&dev->usbdev->dev, dev->tuner_tkn); +} + static void au0828_usb_release(struct au0828_dev *dev) { /* I2C */ @@ -154,6 +185,8 @@ static void au0828_usb_disconnect(struct usb_interface *interface) /* Digital TV */ au0828_dvb_unregister(dev); + au0828_destroy_token_resources(dev); + usb_set_intfdata(interface, NULL); mutex_lock(&dev->mutex); dev->usbdev = NULL; @@ -213,6 +246,13 @@ static int au0828_usb_probe(struct usb_interface *interface, dev->usbdev = usbdev; dev->boardnr = id->driver_info; + /* create token resources */ + if (au0828_create_token_resources(dev)) { + mutex_unlock(&dev->lock); + kfree(dev); + return -ENOMEM; + } + #ifdef CONFIG_VIDEO_AU0828_V4L2 dev->v4l2_dev.release = au0828_usb_v4l2_release; @@ -221,6 +261,7 @@ static int au0828_usb_probe(struct usb_interface *interface, if (retval) { pr_err("%s() v4l2_device_register failed\n", __func__); + au0828_destroy_token_resources(dev); mutex_unlock(&dev->lock); kfree(dev); return retval; @@ -230,6 +271,7 @@ static int au0828_usb_probe(struct usb_interface *interface, if (retval) { pr_err("%s() v4l2_ctrl_handler_init failed\n", __func__); + au0828_destroy_token_resources(dev); mutex_unlock(&dev->lock); kfree(dev); return retval; diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index d8b5d94..1195d29 100755 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -412,6 +412,7 @@ static int dvb_register(struct au0828_dev *dev) goto fail_adapter; } dvb->adapter.priv = dev; + dvb->frontend->tuner_tkn = dev->tuner_tkn; /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->frontend); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 385894a..0b50bda 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -2018,6 +2018,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vdev->lock = &dev->lock; set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags); strcpy(dev->vdev->name, "au0828a video"); + /* is there another way v4l2 core can get struct device ?? */ + dev->vdev->dev_parent = &dev->usbdev->dev; + dev->vdev->tuner_tkn = dev->tuner_tkn; /* Setup the VBI device */ *dev->vbi_dev = au0828_video_template; @@ -2025,6 +2028,7 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vbi_dev->lock = &dev->lock; set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags); strcpy(dev->vbi_dev->name, "au0828a vbi"); + dev->vbi_dev->tuner_tkn = dev->tuner_tkn; /* Register the v4l2 device */ video_set_drvdata(dev->vdev, dev); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 7112b9d..11bc933 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -23,6 +23,7 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <media/tveeprom.h> +#include <linux/token_devres.h> /* Analog */ #include <linux/videodev2.h> @@ -198,6 +199,9 @@ struct au0828_dev { struct au0828_board board; u8 ctrlmsg[64]; + /* token resources */ + char *tuner_tkn; /* tuner token id */ + /* I2C */ struct i2c_adapter i2c_adap; struct i2c_algorithm i2c_algo; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html