From patchwork Mon Sep 22 15:00:46 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shuah Khan X-Patchwork-Id: 4948391 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 751C29F2BB for ; Mon, 22 Sep 2014 15:08:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CF7132010E for ; Mon, 22 Sep 2014 15:08:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C1AC12010C for ; Mon, 22 Sep 2014 15:08:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754051AbaIVPHM (ORCPT ); Mon, 22 Sep 2014 11:07:12 -0400 Received: from resqmta-po-03v.sys.comcast.net ([96.114.154.162]:43039 "EHLO resqmta-po-03v.sys.comcast.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754033AbaIVPHK (ORCPT ); Mon, 22 Sep 2014 11:07:10 -0400 Received: from resomta-po-16v.sys.comcast.net ([96.114.154.240]) by resqmta-po-03v.sys.comcast.net with comcast id uF0D1o0035BUCh401F14TA; Mon, 22 Sep 2014 15:01:04 +0000 Received: from mail.gonehiking.org ([50.134.149.16]) by resomta-po-16v.sys.comcast.net with comcast id uF131o00J0MU7Qa01F14Su; Mon, 22 Sep 2014 15:01:04 +0000 Received: from lorien.internal (lorien-wl.internal [192.168.1.40]) by mail.gonehiking.org (Postfix) with ESMTP id 505403FF0F; Mon, 22 Sep 2014 09:01:03 -0600 (MDT) From: Shuah Khan To: m.chehab@samsung.com, akpm@linux-foundation.org, gregkh@linuxfoundation.org, crope@iki.fi, olebowle@gmx.com, dheitmueller@kernellabs.co, hverkuil@xs4all.nl, ramakrmu@cisco.com, sakari.ailus@linux.intel.com, laurent.pinchart@ideasonboard.com Cc: Shuah Khan , linux-kernel@vger.kernel.org, linux-media@vger.kernel.org Subject: [PATCH 2/5] media: v4l2-core changes to use media tuner token api Date: Mon, 22 Sep 2014 09:00:46 -0600 Message-Id: X-Mailer: git-send-email 1.9.1 In-Reply-To: References: In-Reply-To: References: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=comcast.net; s=q20140121; t=1411398064; bh=/opBZcO1A81Tr6nM/tE2vS0O4WIFKX4R++N2k2g08uk=; h=Received:Received:Received:From:To:Subject:Date:Message-Id; b=L+wIdyPCbEeGly3kc5ap5wsPvQJuazXafm2H6xPN62c1uh1Q57ZjZLhRi7SWO67+/ FPs5w8KwsnOvAmSCtTk5D9cH7h18LJ/1ObOwlHBV0UugN9VjiIr31x1EdqwFs5o5d/ xUj5GlQYl4t4q5g8K/Kqe0t13i1hxu7b0aAOM2rfivwvSHfa7fIifZowDVscVVYuEb U+UNAhU4BfbtpsZi0un2DNkYwPHMX0cxGPA64AREQi3I0Im856DPnBdWujytNmJlGW 1b9rZqA4ZtNYmaFTtXNqu5BOqCeux0EPWJTyypd1+RUaddVKhBtzAgAS07SPdJvjrf Cb7o3q0f24NXA== Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-7.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Changes to v4l2-core to hold tuner token in v4l2 ioctl that change the tuner modes, and reset the token from fh exit. The changes are limited to vb2 calls that disrupt digital stream. vb1 changes are made in the driver. The following ioctls are changed: S_INPUT, S_OUTPUT, S_FMT, S_TUNER, S_MODULATOR, S_FREQUENCY, S_STD, S_HW_FREQ_SEEK: - hold tuner in shared analog mode before calling appropriate ops->vidioc_s_* - return leaving tuner in shared mode. - Note that S_MODULATOR is now implemented in the core previously FCN. QUERYSTD: - hold tuner in shared analog mode before calling ops->vidioc_querystd - return after calling put tuner - this simply decrements the owners. Leaves tuner in shared analog mode if owners > 0 v4l2_fh_exit: - resets the media tuner token. A simple put token could leave the token in shared mode. The nature of analog token holds is unbalanced requiring a reset to clear it. Signed-off-by: Shuah Khan --- drivers/media/v4l2-core/v4l2-fh.c | 16 ++++++ drivers/media/v4l2-core/v4l2-ioctl.c | 96 +++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index c97067a..81ce3f9 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -25,7 +25,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -92,6 +95,19 @@ void v4l2_fh_exit(struct v4l2_fh *fh) { if (fh->vdev == NULL) return; + + if (fh->vdev->dev_parent) { + enum media_tkn_mode mode; + + mode = (fh->vdev->vfl_type == V4L2_TUNER_RADIO) ? + MEDIA_MODE_RADIO : MEDIA_MODE_ANALOG; + /* reset the token - the nature of token get in + analog mode is shared and unbalanced. There is + no clear start and stop, so shared token might + never get cleared */ + media_reset_shared_tuner_tkn(fh->vdev->dev_parent, mode); + } + v4l2_event_unsubscribe_all(fh); fh->vdev = NULL; } diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d15e167..9e1f042 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -1003,6 +1004,37 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) sizeof(fmt->fmt.pix) - offset); } +static int v4l_get_tuner_tkn(struct video_device *vfd, + enum v4l2_tuner_type type) +{ + int ret = 0; + + if (vfd->dev_parent) { + enum media_tkn_mode mode; + + mode = (type == V4L2_TUNER_RADIO) ? + MEDIA_MODE_RADIO : MEDIA_MODE_ANALOG; + ret = media_get_shared_tuner_tkn(vfd->dev_parent, mode); + if (ret) + dev_info(vfd->dev_parent, + "%s: Tuner is busy\n", __func__); + } + dev_dbg(vfd->dev_parent, "%s: No token?? %d\n", __func__, ret); + return ret; +} + +static void v4l_put_tuner_tkn(struct video_device *vfd, + enum v4l2_tuner_type type) +{ + if (vfd->dev_parent) { + enum media_tkn_mode mode; + + mode = (type == V4L2_TUNER_RADIO) ? + MEDIA_MODE_RADIO : MEDIA_MODE_ANALOG; + media_put_tuner_tkn(vfd->dev_parent, mode); + } +} + static int v4l_querycap(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1022,12 +1054,24 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, static int v4l_s_input(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); + int ret = 0; + + ret = v4l_get_tuner_tkn(vfd, V4L2_TUNER_ANALOG_TV); + if (ret) + return ret; return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); } static int v4l_s_output(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); + int ret = 0; + + ret = v4l_get_tuner_tkn(vfd, V4L2_TUNER_ANALOG_TV); + if (ret) + return ret; return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); } @@ -1236,6 +1280,10 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, bool is_tx = vfd->vfl_dir != VFL_DIR_RX; int ret; + ret = v4l_get_tuner_tkn(vfd, V4L2_TUNER_ANALOG_TV); + if (ret) + return ret; + v4l_sanitize_format(p); switch (p->type) { @@ -1415,9 +1463,13 @@ static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_tuner *p = arg; + int ret; p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + ret = v4l_get_tuner_tkn(vfd, p->type); + if (ret) + return ret; return ops->vidioc_s_tuner(file, fh, p); } @@ -1433,6 +1485,26 @@ static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops, return err; } +static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + + if (vfh != NULL) { + int ret; + enum v4l2_tuner_type type; + + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + ret = v4l_get_tuner_tkn(vfd, type); + if (ret) + return ret; + } + return ops->vidioc_s_modulator(file, fh, arg); +} + static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1453,6 +1525,7 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, struct video_device *vfd = video_devdata(file); const struct v4l2_frequency *p = arg; enum v4l2_tuner_type type; + int ret; if (vfd->vfl_type == VFL_TYPE_SDR) { if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF) @@ -1462,6 +1535,9 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; if (type != p->type) return -EINVAL; + ret = v4l_get_tuner_tkn(vfd, type); + if (ret) + return ret; } return ops->vidioc_s_frequency(file, fh, p); } @@ -1508,11 +1584,16 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); v4l2_std_id id = *(v4l2_std_id *)arg, norm; + int ret = 0; norm = id & vfd->tvnorms; if (vfd->tvnorms && !norm) /* Check if std is supported */ return -EINVAL; + ret = v4l_get_tuner_tkn(vfd, V4L2_TUNER_ANALOG_TV); + if (ret) + return ret; + /* Calls the specific handler */ return ops->vidioc_s_std(file, fh, norm); } @@ -1522,7 +1603,11 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); v4l2_std_id *p = arg; + int ret = 0; + ret = v4l_get_tuner_tkn(vfd, V4L2_TUNER_ANALOG_TV); + if (ret) + return ret; /* * If no signal is detected, then the driver should return * V4L2_STD_UNKNOWN. Otherwise it should return tvnorms with @@ -1532,7 +1617,9 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops, * their efforts to improve the standards detection. */ *p = vfd->tvnorms; - return ops->vidioc_querystd(file, fh, arg); + ret = ops->vidioc_querystd(file, fh, arg); + v4l_put_tuner_tkn(vfd, V4L2_TUNER_ANALOG_TV); + return ret; } static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, @@ -1541,6 +1628,7 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, struct video_device *vfd = video_devdata(file); struct v4l2_hw_freq_seek *p = arg; enum v4l2_tuner_type type; + int ret; /* s_hw_freq_seek is not supported for SDR for now */ if (vfd->vfl_type == VFL_TYPE_SDR) @@ -1550,6 +1638,9 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; if (p->type != type) return -EINVAL; + ret = v4l_get_tuner_tkn(vfd, type); + if (ret) + return ret; return ops->vidioc_s_hw_freq_seek(file, fh, p); } @@ -2217,7 +2308,8 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0), IOCTL_INFO_STD(VIDIOC_S_AUDOUT, vidioc_s_audout, v4l_print_audioout, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_G_MODULATOR, v4l_g_modulator, v4l_print_modulator, INFO_FL_CLEAR(v4l2_modulator, index)), - IOCTL_INFO_STD(VIDIOC_S_MODULATOR, vidioc_s_modulator, v4l_print_modulator, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_modulator, + v4l_print_frequency, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_G_FREQUENCY, v4l_g_frequency, v4l_print_frequency, INFO_FL_CLEAR(v4l2_frequency, tuner)), IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_frequency, v4l_print_frequency, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_CROPCAP, v4l_cropcap, v4l_print_cropcap, INFO_FL_CLEAR(v4l2_cropcap, type)),