diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-30 09:01:04 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-30 09:01:04 -0300 |
commit | df90e2258950fd631cdbf322c1ee1f22068391aa (patch) | |
tree | 0b6dd2717c04bb7f93db6abdeda208aeea4cd74e /drivers/media/usb/tlg2300/pd-radio.c | |
parent | aad797c89903d570c17f6affc770eb98afd74e62 (diff) | |
parent | 02615ed5e1b2283db2495af3cf8f4ee172c77d80 (diff) | |
download | talos-op-linux-df90e2258950fd631cdbf322c1ee1f22068391aa.tar.gz talos-op-linux-df90e2258950fd631cdbf322c1ee1f22068391aa.zip |
Merge branch 'devel-for-v3.10' into v4l_for_linus
* patchwork: (831 commits)
[media] cx88: make core less verbose
[media] em28xx: fix oops at em28xx_dvb_bus_ctrl()
[media] s5c73m3: fix indentation of the help section in Kconfig
[media] cx25821-alsa: get rid of a __must_check warning
[media] cx25821-video: declare cx25821_vidioc_s_std as static
[media] cx25821-video: remove maxw from cx25821_vidioc_try_fmt_vid_cap
[media] r820t: Remove a warning for an unused value
[media] dib0090: Fix a warning at dib0090_set_EFUSE
[media] dib8000: fix a warning
[media] dib8000: Fix sub-channel range
[media] dib8000: store dtv_property_cache in a temp var
[media] dib8000: warning fix: declare internal functions as static
[media] r820t: quiet gcc warning on n_ring
[media] r820t: memory leak in release()
[media] r820t: precendence bug in r820t_xtal_check()
[media] videodev2.h: Remove the unused old V4L1 buffer types
[media] anysee: Grammar s/report the/report to/
[media] anysee: Initialize ret = 0 in anysee_frontend_attach()
[media] media: videobuf2: fix the length check for mmap
[media] em28xx: save isoc endpoint number for DVB only if endpoint has alt settings with xMaxPacketSize != 0
...
Conflicts:
drivers/media/pci/cx25821/cx25821-video.c
drivers/media/platform/Kconfig
Diffstat (limited to 'drivers/media/usb/tlg2300/pd-radio.c')
-rw-r--r-- | drivers/media/usb/tlg2300/pd-radio.c | 229 |
1 files changed, 74 insertions, 155 deletions
diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 25eeb166aa0b..ea6070ba835e 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -9,6 +9,8 @@ #include <linux/mm.h> #include <linux/mutex.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fh.h> #include <linux/sched.h> #include "pd-common.h" @@ -18,8 +20,8 @@ static int set_frequency(struct poseidon *p, __u32 frequency); static int poseidon_fm_close(struct file *filp); static int poseidon_fm_open(struct file *filp); -#define TUNER_FREQ_MIN_FM 76000000 -#define TUNER_FREQ_MAX_FM 108000000 +#define TUNER_FREQ_MIN_FM 76000000U +#define TUNER_FREQ_MAX_FM 108000000U #define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1) static int preemphasis[MAX_PREEMPHASIS] = { @@ -77,13 +79,9 @@ static int pm_fm_resume(struct poseidon *p) static int poseidon_fm_open(struct file *filp) { - struct video_device *vfd = video_devdata(filp); - struct poseidon *p = video_get_drvdata(vfd); + struct poseidon *p = video_drvdata(filp); int ret = 0; - if (!p) - return -1; - mutex_lock(&p->lock); if (p->state & POSEIDON_STATE_DISCONNECT) { ret = -ENODEV; @@ -94,9 +92,14 @@ static int poseidon_fm_open(struct file *filp) ret = -EBUSY; goto out; } + ret = v4l2_fh_open(filp); + if (ret) + goto out; usb_autopm_get_interface(p->interface); if (0 == p->state) { + struct video_device *vfd = &p->radio_data.fm_dev; + /* default pre-emphasis */ if (p->radio_data.pre_emphasis == 0) p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR; @@ -109,9 +112,7 @@ static int poseidon_fm_open(struct file *filp) } p->state |= POSEIDON_STATE_FM; } - p->radio_data.users++; kref_get(&p->kref); - filp->private_data = p; out: mutex_unlock(&p->lock); return ret; @@ -119,13 +120,12 @@ out: static int poseidon_fm_close(struct file *filp) { - struct poseidon *p = filp->private_data; + struct poseidon *p = video_drvdata(filp); struct radio_data *fm = &p->radio_data; uint32_t status; mutex_lock(&p->lock); - fm->users--; - if (0 == fm->users) + if (v4l2_fh_is_singular_file(filp)) p->state &= ~POSEIDON_STATE_FM; if (fm->is_radio_streaming && filp == p->file_for_stream) { @@ -136,19 +136,23 @@ static int poseidon_fm_close(struct file *filp) mutex_unlock(&p->lock); kref_put(&p->kref, poseidon_delete); - filp->private_data = NULL; - return 0; + return v4l2_fh_release(filp); } static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - struct poseidon *p = file->private_data; + struct poseidon *p = video_drvdata(file); strlcpy(v->driver, "tele-radio", sizeof(v->driver)); strlcpy(v->card, "Telegent Poseidon", sizeof(v->card)); usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info)); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + /* Report all capabilities of the USB device */ + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_AUDIO | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; return 0; } @@ -156,27 +160,29 @@ static const struct v4l2_file_operations poseidon_fm_fops = { .owner = THIS_MODULE, .open = poseidon_fm_open, .release = poseidon_fm_close, - .ioctl = video_ioctl2, + .poll = v4l2_ctrl_poll, + .unlocked_ioctl = video_ioctl2, }; static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { + struct poseidon *p = video_drvdata(file); struct tuner_fm_sig_stat_s fm_stat = {}; int ret, status, count = 5; - struct poseidon *p = file->private_data; if (vt->index != 0) return -EINVAL; vt->type = V4L2_TUNER_RADIO; - vt->capability = V4L2_TUNER_CAP_STEREO; - vt->rangelow = TUNER_FREQ_MIN_FM / 62500; - vt->rangehigh = TUNER_FREQ_MAX_FM / 62500; + vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; + vt->rangelow = TUNER_FREQ_MIN_FM * 2 / 125; + vt->rangehigh = TUNER_FREQ_MAX_FM * 2 / 125; vt->rxsubchans = V4L2_TUNER_SUB_STEREO; vt->audmode = V4L2_TUNER_MODE_STEREO; vt->signal = 0; vt->afc = 0; + strlcpy(vt->name, "Radio", sizeof(vt->name)); mutex_lock(&p->lock); ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO, @@ -205,8 +211,10 @@ static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, static int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp) { - struct poseidon *p = file->private_data; + struct poseidon *p = video_drvdata(file); + if (argp->tuner) + return -EINVAL; argp->frequency = p->radio_data.fm_freq; return 0; } @@ -221,11 +229,8 @@ static int set_frequency(struct poseidon *p, __u32 frequency) ret = send_set_req(p, TUNER_AUD_ANA_STD, p->radio_data.pre_emphasis, &status); - freq = (frequency * 125) * 500 / 1000;/* kHZ */ - if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) { - ret = -EINVAL; - goto error; - } + freq = (frequency * 125) / 2; /* Hz */ + freq = clamp(freq, TUNER_FREQ_MIN_FM, TUNER_FREQ_MAX_FM); ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status); if (ret < 0) @@ -240,18 +245,20 @@ static int set_frequency(struct poseidon *p, __u32 frequency) TLG_TUNE_PLAY_SVC_START, &status); p->radio_data.is_radio_streaming = 1; } - p->radio_data.fm_freq = frequency; + p->radio_data.fm_freq = freq * 2 / 125; error: mutex_unlock(&p->lock); return ret; } static int fm_set_freq(struct file *file, void *priv, - struct v4l2_frequency *argp) + const struct v4l2_frequency *argp) { - struct poseidon *p = file->private_data; + struct poseidon *p = video_drvdata(file); - p->file_for_stream = file; + if (argp->tuner) + return -EINVAL; + p->file_for_stream = file; #ifdef CONFIG_PM p->pm_suspend = pm_fm_suspend; p->pm_resume = pm_fm_resume; @@ -259,163 +266,75 @@ static int fm_set_freq(struct file *file, void *priv, return set_frequency(p, argp->frequency); } -static int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *arg) -{ - return 0; -} - -static int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *ctrls) -{ - struct poseidon *p = file->private_data; - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) - continue; - - if (i < MAX_PREEMPHASIS) - ctrl->value = p->radio_data.pre_emphasis; - } - return 0; -} - -static int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *ctrls) -{ - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) - continue; - - if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) { - struct poseidon *p = file->private_data; - int pre_emphasis = preemphasis[ctrl->value]; - u32 status; - - send_set_req(p, TUNER_AUD_ANA_STD, - pre_emphasis, &status); - p->radio_data.pre_emphasis = pre_emphasis; - } - } - return 0; -} - -static int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl) { - return 0; -} - -static int tlg_fm_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *ctrl) -{ - if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) - return -EINVAL; + struct poseidon *p = container_of(ctrl->handler, struct poseidon, + radio_data.ctrl_handler); + int pre_emphasis; + u32 status; - ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL; - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) { - /* return the next supported control */ - ctrl->id = V4L2_CID_TUNE_PREEMPHASIS; - v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED, - V4L2_PREEMPHASIS_75_uS, 1, - V4L2_PREEMPHASIS_50_uS); - ctrl->flags = V4L2_CTRL_FLAG_UPDATE; + switch (ctrl->id) { + case V4L2_CID_TUNE_PREEMPHASIS: + pre_emphasis = preemphasis[ctrl->val]; + send_set_req(p, TUNER_AUD_ANA_STD, pre_emphasis, &status); + p->radio_data.pre_emphasis = pre_emphasis; return 0; } return -EINVAL; } -static int tlg_fm_vidioc_querymenu(struct file *file, void *fh, - struct v4l2_querymenu *qmenu) -{ - return v4l2_ctrl_query_menu(qmenu, NULL, NULL); -} - -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { return vt->index > 0 ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *va) -{ - return (va->index != 0) ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - a->index = 0; - a->mode = 0; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "Radio"); - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, u32 i) -{ - return (i != 0) ? -EINVAL : 0; -} -static int vidioc_g_input(struct file *filp, void *priv, u32 *i) -{ - return (*i != 0) ? -EINVAL : 0; -} +static const struct v4l2_ctrl_ops tlg_fm_ctrl_ops = { + .s_ctrl = tlg_fm_s_ctrl, +}; static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = tlg_fm_vidioc_queryctrl, - .vidioc_querymenu = tlg_fm_vidioc_querymenu, - .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl, - .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl, - .vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl, - .vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_tuner = tlg_fm_vidioc_g_tuner, .vidioc_g_frequency = fm_get_freq, .vidioc_s_frequency = fm_set_freq, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device poseidon_fm_template = { .name = "Telegent-Radio", .fops = &poseidon_fm_fops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &poseidon_fm_ioctl_ops, }; int poseidon_fm_init(struct poseidon *p) { - struct video_device *fm_dev; - - fm_dev = vdev_init(p, &poseidon_fm_template); - if (fm_dev == NULL) - return -1; - - if (video_register_device(fm_dev, VFL_TYPE_RADIO, -1) < 0) { - video_device_release(fm_dev); - return -1; + struct video_device *vfd = &p->radio_data.fm_dev; + struct v4l2_ctrl_handler *hdl = &p->radio_data.ctrl_handler; + + *vfd = poseidon_fm_template; + + set_frequency(p, TUNER_FREQ_MIN_FM); + v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_new_std_menu(hdl, &tlg_fm_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS, + V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS); + if (hdl->error) { + v4l2_ctrl_handler_free(hdl); + return hdl->error; } - p->radio_data.fm_dev = fm_dev; - return 0; + vfd->v4l2_dev = &p->v4l2_dev; + vfd->ctrl_handler = hdl; + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); + video_set_drvdata(vfd, p); + return video_register_device(vfd, VFL_TYPE_RADIO, -1); } int poseidon_fm_exit(struct poseidon *p) { - destroy_video_device(&p->radio_data.fm_dev); + video_unregister_device(&p->radio_data.fm_dev); + v4l2_ctrl_handler_free(&p->radio_data.ctrl_handler); return 0; } |