diff options
Diffstat (limited to 'drivers/media/usb/tlg2300')
-rw-r--r-- | drivers/media/usb/tlg2300/pd-common.h | 26 | ||||
-rw-r--r-- | drivers/media/usb/tlg2300/pd-main.c | 16 | ||||
-rw-r--r-- | drivers/media/usb/tlg2300/pd-radio.c | 229 | ||||
-rw-r--r-- | drivers/media/usb/tlg2300/pd-video.c | 303 |
4 files changed, 191 insertions, 383 deletions
diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 5dd73b7857d1..9e23ad32d2fe 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -10,6 +10,7 @@ #include <linux/poll.h> #include <media/videobuf-vmalloc.h> #include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> #include "dvb_frontend.h" #include "dvbdev.h" @@ -25,7 +26,6 @@ #define POSEIDON_STATE_ANALOG (0x0001) #define POSEIDON_STATE_FM (0x0002) #define POSEIDON_STATE_DVBT (0x0004) -#define POSEIDON_STATE_VBI (0x0008) #define POSEIDON_STATE_DISCONNECT (0x0080) #define PM_SUSPEND_DELAY 3 @@ -35,11 +35,11 @@ #define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2) #define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2) -#define TUNER_FREQ_MIN (45000000) -#define TUNER_FREQ_MAX (862000000) +#define TUNER_FREQ_MIN (45000000U) +#define TUNER_FREQ_MAX (862000000U) struct vbi_data { - struct video_device *v_dev; + struct video_device v_dev; struct video_data *video; struct front_face *front; @@ -62,7 +62,8 @@ struct running_context { struct video_data { /* v4l2 video device */ - struct video_device *v_dev; + struct video_device v_dev; + struct v4l2_ctrl_handler ctrl_handler; /* the working context */ struct running_context context; @@ -115,10 +116,10 @@ struct poseidon_audio { struct radio_data { __u32 fm_freq; - int users; unsigned int is_radio_streaming; int pre_emphasis; - struct video_device *fm_dev; + struct video_device fm_dev; + struct v4l2_ctrl_handler ctrl_handler; }; #define DVB_SBUF_NUM 4 @@ -233,7 +234,6 @@ void dvb_stop_streaming(struct pd_dvb_adapter *); /* FM */ int poseidon_fm_init(struct poseidon *); int poseidon_fm_exit(struct poseidon *); -struct video_device *vdev_init(struct poseidon *, struct video_device *); /* vendor command ops */ int send_set_req(struct poseidon*, u8, s32, s32*); @@ -249,7 +249,6 @@ void free_all_urb_generic(struct urb **urb_array, int num); /* misc */ void poseidon_delete(struct kref *kref); -void destroy_video_device(struct video_device **v_dev); extern int debug_mode; void set_debug_mode(struct video_device *vfd, int debug_mode); @@ -269,13 +268,4 @@ void set_debug_mode(struct video_device *vfd, int debug_mode); log();\ } while (0) -#define logs(f) do { \ - if ((debug_mode & 0x4) && \ - (f)->type == V4L2_BUF_TYPE_VBI_CAPTURE) \ - log("type : VBI");\ - \ - if ((debug_mode & 0x8) && \ - (f)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) \ - log("type : VIDEO");\ - } while (0) #endif diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c index 7b1f6ebd0e2c..e07e4c699cc2 100644 --- a/drivers/media/usb/tlg2300/pd-main.c +++ b/drivers/media/usb/tlg2300/pd-main.c @@ -55,7 +55,6 @@ MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose"); #define TLG2300_FIRMWARE "tlg2300_firmware.bin" static const char *firmware_name = TLG2300_FIRMWARE; -static struct usb_driver poseidon_driver; static LIST_HEAD(pd_device_list); /* @@ -268,7 +267,8 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) static inline int get_autopm_ref(struct poseidon *pd) { return pd->video_data.users + pd->vbi_data.users + pd->audio.users - + atomic_read(&pd->dvb_data.users) + pd->radio_data.users; + + atomic_read(&pd->dvb_data.users) + + !list_empty(&pd->radio_data.fm_dev.fh_list); } /* fixup something for poseidon */ @@ -316,7 +316,7 @@ static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg) if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) { pd->msg.event = PM_EVENT_AUTO_SUSPEND; pd->pm_resume = NULL; /* a good guard */ - printk(KERN_DEBUG "\n\t+ TLG2300 auto suspend +\n\n"); + printk(KERN_DEBUG "TLG2300 auto suspend\n"); } return 0; } @@ -331,7 +331,7 @@ static int poseidon_resume(struct usb_interface *intf) if (!pd) return 0; - printk(KERN_DEBUG "\n\t ++ TLG2300 resume ++\n\n"); + printk(KERN_DEBUG "TLG2300 resume\n"); if (!is_working(pd)) { if (PM_EVENT_AUTO_SUSPEND == pd->msg.event) @@ -431,15 +431,11 @@ static int poseidon_probe(struct usb_interface *interface, usb_set_intfdata(interface, pd); if (new_one) { - struct device *dev = &interface->dev; - logpm(pd); mutex_init(&pd->lock); /* register v4l2 device */ - snprintf(pd->v4l2_dev.name, sizeof(pd->v4l2_dev.name), "%s %s", - dev->driver->name, dev_name(dev)); - ret = v4l2_device_register(NULL, &pd->v4l2_dev); + ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev); /* register devices in directory /dev */ ret = pd_video_init(pd); @@ -530,7 +526,7 @@ module_init(poseidon_init); module_exit(poseidon_exit); MODULE_AUTHOR("Telegent Systems"); -MODULE_DESCRIPTION("For tlg2300-based USB device "); +MODULE_DESCRIPTION("For tlg2300-based USB device"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.0.2"); MODULE_FIRMWARE(TLG2300_FIRMWARE); 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; } diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 21723378bb8f..8df668d06552 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -8,6 +8,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-dev.h> +#include <media/v4l2-ctrls.h> #include "pd-common.h" #include "vendorcmds.h" @@ -82,31 +83,6 @@ static const struct pd_input pd_inputs[] = { }; static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs); -struct poseidon_control { - struct v4l2_queryctrl v4l2_ctrl; - enum cmd_custom_param_id vc_id; -}; - -static struct poseidon_control controls[] = { - { - { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, - "brightness", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_BRIGHTNESS_CTRL - }, { - { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, - "contrast", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_CONTRAST_CTRL, - }, { - { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, - "hue", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_HUE_CTRL, - }, { - { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, - "saturation", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_SATURATION_CTRL, - }, -}; - struct video_std_to_audio_std { v4l2_std_id video_std; int audio_std; @@ -142,17 +118,20 @@ static int get_audio_std(v4l2_std_id v4l2_std) static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct front_face *front = fh; - struct poseidon *p = front->pd; - - logs(front); + struct video_device *vdev = video_devdata(file); + struct poseidon *p = video_get_drvdata(vdev); strcpy(cap->driver, "tele-video"); strcpy(cap->card, "Telegent Poseidon"); usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | - V4L2_CAP_AUDIO | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; + cap->device_caps = V4L2_CAP_TUNER | V4L2_CAP_AUDIO | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_RADIO | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE; return 0; } @@ -223,7 +202,6 @@ static void submit_frame(struct front_face *front) */ static void end_field(struct video_data *video) { - /* logs(video->front); */ if (1 == video->field_count) submit_frame(video->front); else @@ -718,17 +696,10 @@ static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) struct front_face *front = fh; struct poseidon *pd = front->pd; - logs(front); f->fmt.pix = pd->video_data.context.pix; return 0; } -static int vidioc_try_fmt(struct file *file, void *fh, - struct v4l2_format *f) -{ - return 0; -} - /* * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while * Mplayer calls them in the reverse order. @@ -787,7 +758,6 @@ static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) struct front_face *front = fh; struct poseidon *pd = front->pd; - logs(front); /* stop VBI here */ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) return -EINVAL; @@ -828,11 +798,10 @@ static int vidioc_g_fmt_vbi(struct file *file, void *fh, vbi_fmt->count[1] = V4L_PAL_VBI_LINES; } vbi_fmt->flags = V4L2_VBI_UNSYNC; - logs(front); return 0; } -static int set_std(struct poseidon *pd, v4l2_std_id *norm) +static int set_std(struct poseidon *pd, v4l2_std_id norm) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; @@ -842,7 +811,7 @@ static int set_std(struct poseidon *pd, v4l2_std_id *norm) int height; for (i = 0; i < POSEIDON_TVNORMS; i++) { - if (*norm & poseidon_tvnorms[i].v4l2_id) { + if (norm & poseidon_tvnorms[i].v4l2_id) { param = poseidon_tvnorms[i].tlg_tvnorm; log("name : %s", poseidon_tvnorms[i].name); goto found; @@ -877,17 +846,23 @@ out: return ret; } -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id norm) { struct front_face *front = fh; - logs(front); + return set_std(front->pd, norm); } -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) +static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) { struct front_face *front = fh; + *norm = front->pd->video_data.context.tvnormid; + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) +{ if (in->index >= POSEIDON_INPUTS) return -EINVAL; strcpy(in->name, pd_inputs[in->index].name); @@ -897,11 +872,10 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) * the audio input index mixed with this video input, * Poseidon only have one audio/video, set to "0" */ - in->audioset = 0; + in->audioset = 1; in->tuner = 0; in->std = V4L2_STD_ALL; in->status = 0; - logs(front); return 0; } @@ -911,7 +885,6 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) struct poseidon *pd = front->pd; struct running_context *context = &pd->video_data.context; - logs(front); *i = context->sig_index; return 0; } @@ -934,68 +907,28 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int i) return 0; } -static struct poseidon_control *check_control_id(__u32 id) -{ - struct poseidon_control *control = &controls[0]; - int array_size = ARRAY_SIZE(controls); - - for (; control < &controls[array_size]; control++) - if (control->v4l2_ctrl.id == id) - return control; - return NULL; -} - -static int vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *a) -{ - struct poseidon_control *control = NULL; - - control = check_control_id(a->id); - if (!control) - return -EINVAL; - - *a = control->v4l2_ctrl; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct poseidon_control *control = NULL; - struct tuner_custom_parameter_s tuner_param; - s32 ret = 0, cmd_status; - - control = check_control_id(ctrl->id); - if (!control) - return -EINVAL; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_CUSTOM_PARAMETER, control->vc_id, - &tuner_param, &cmd_status, sizeof(tuner_param)); - mutex_unlock(&pd->lock); - - if (ret || cmd_status) - return -1; - - ctrl->value = tuner_param.param_value; - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) +static int tlg_s_ctrl(struct v4l2_ctrl *c) { + struct poseidon *pd = container_of(c->handler, struct poseidon, + video_data.ctrl_handler); struct tuner_custom_parameter_s param = {0}; - struct poseidon_control *control = NULL; - struct front_face *front = fh; - struct poseidon *pd = front->pd; s32 ret = 0, cmd_status, params; - control = check_control_id(a->id); - if (!control) - return -EINVAL; - - param.param_value = a->value; - param.param_id = control->vc_id; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + param.param_id = CUST_PARM_ID_BRIGHTNESS_CTRL; + break; + case V4L2_CID_CONTRAST: + param.param_id = CUST_PARM_ID_CONTRAST_CTRL; + break; + case V4L2_CID_HUE: + param.param_id = CUST_PARM_ID_HUE_CTRL; + break; + case V4L2_CID_SATURATION: + param.param_id = CUST_PARM_ID_SATURATION_CTRL; + break; + } + param.param_value = c->val; params = *(s32 *)¶m; /* temp code */ mutex_lock(&pd->lock); @@ -1079,7 +1012,6 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner) tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub; tuner->audmode = pd_audio_modes[index].v4l2_audio_mode; tuner->afc = 0; - logs(front); return 0; } @@ -1099,7 +1031,7 @@ static int pd_vidioc_s_tuner(struct poseidon *pd, int index) return ret; } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *a) { struct front_face *front = fh; struct poseidon *pd = front->pd; @@ -1107,7 +1039,6 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a) if (0 != a->index) return -EINVAL; - logs(front); for (index = 0; index < POSEIDON_AUDIOMODS; index++) if (a->audmode == pd_audio_modes[index].v4l2_audio_mode) return pd_vidioc_s_tuner(pd, index); @@ -1128,51 +1059,51 @@ static int vidioc_g_frequency(struct file *file, void *fh, return 0; } -static int set_frequency(struct poseidon *pd, __u32 frequency) +static int set_frequency(struct poseidon *pd, u32 *frequency) { s32 ret = 0, param, cmd_status; struct running_context *context = &pd->video_data.context; - param = frequency * 62500 / 1000; - if (param < TUNER_FREQ_MIN/1000 || param > TUNER_FREQ_MAX / 1000) - return -EINVAL; + *frequency = clamp(*frequency, + TUNER_FREQ_MIN / 62500, TUNER_FREQ_MAX / 62500); + param = (*frequency) * 62500 / 1000; mutex_lock(&pd->lock); ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status); ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); msleep(250); /* wait for a while until the hardware is ready. */ - context->freq = frequency; + context->freq = *frequency; mutex_unlock(&pd->lock); return ret; } static int vidioc_s_frequency(struct file *file, void *fh, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct front_face *front = fh; struct poseidon *pd = front->pd; + u32 frequency = freq->frequency; - logs(front); + if (freq->tuner) + return -EINVAL; #ifdef CONFIG_PM pd->pm_suspend = pm_video_suspend; pd->pm_resume = pm_video_resume; #endif - return set_frequency(pd, freq->frequency); + return set_frequency(pd, &frequency); } static int vidioc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) { struct front_face *front = file->private_data; - logs(front); return videobuf_reqbufs(&front->q, b); } static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) { struct front_face *front = file->private_data; - logs(front); return videobuf_querybuf(&front->q, b); } @@ -1261,7 +1192,6 @@ static int vidioc_streamon(struct file *file, void *fh, { struct front_face *front = fh; - logs(front); if (unlikely(type != front->type)) return -EINVAL; return videobuf_streamon(&front->q); @@ -1272,7 +1202,6 @@ static int vidioc_streamoff(struct file *file, void *fh, { struct front_face *front = file->private_data; - logs(front); if (unlikely(type != front->type)) return -EINVAL; return videobuf_streamoff(&front->q); @@ -1341,11 +1270,11 @@ static int restore_v4l2_context(struct poseidon *pd, pd_video_checkmode(pd); - set_std(pd, &context->tvnormid); + set_std(pd, context->tvnormid); vidioc_s_input(NULL, front, context->sig_index); pd_vidioc_s_tuner(pd, context->audio_idx); pd_vidioc_s_fmt(pd, &context->pix); - set_frequency(pd, context->freq); + set_frequency(pd, &context->freq); return 0; } @@ -1406,12 +1335,14 @@ static int pd_video_open(struct file *file) mutex_lock(&pd->lock); usb_autopm_get_interface(pd->interface); - if (vfd->vfl_type == VFL_TYPE_GRABBER - && !(pd->state & POSEIDON_STATE_ANALOG)) { - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - + if (pd->state && !(pd->state & POSEIDON_STATE_ANALOG)) { + ret = -EBUSY; + goto out; + } + front = kzalloc(sizeof(struct front_face), GFP_KERNEL); + if (!front) + goto out; + if (vfd->vfl_type == VFL_TYPE_GRABBER) { pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */ init_video_context(&pd->video_data.context); @@ -1422,7 +1353,6 @@ static int pd_video_open(struct file *file) goto out; } - pd->state |= POSEIDON_STATE_ANALOG; front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; pd->video_data.users++; set_debug_mode(vfd, debug_mode); @@ -1433,13 +1363,7 @@ static int pd_video_open(struct file *file) V4L2_FIELD_INTERLACED,/* video is interlacd */ sizeof(struct videobuf_buffer),/*it's enough*/ front, NULL); - } else if (vfd->vfl_type == VFL_TYPE_VBI - && !(pd->state & POSEIDON_STATE_VBI)) { - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - - pd->state |= POSEIDON_STATE_VBI; + } else { front->type = V4L2_BUF_TYPE_VBI_CAPTURE; pd->vbi_data.front = front; pd->vbi_data.users++; @@ -1450,19 +1374,15 @@ static int pd_video_open(struct file *file) V4L2_FIELD_NONE, /* vbi is NONE mode */ sizeof(struct videobuf_buffer), front, NULL); - } else { - /* maybe add FM support here */ - log("other "); - ret = -EINVAL; - goto out; } - front->pd = pd; - front->curr_frame = NULL; + pd->state |= POSEIDON_STATE_ANALOG; + front->pd = pd; + front->curr_frame = NULL; INIT_LIST_HEAD(&front->active); spin_lock_init(&front->queue_lock); - file->private_data = front; + file->private_data = front; kref_get(&pd->kref); mutex_unlock(&pd->lock); @@ -1479,12 +1399,9 @@ static int pd_video_release(struct file *file) struct poseidon *pd = front->pd; s32 cmd_status = 0; - logs(front); mutex_lock(&pd->lock); if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pd->state &= ~POSEIDON_STATE_ANALOG; - /* stop the device, and free the URBs */ usb_transfer_stop(&pd->video_data); free_all_urb(&pd->video_data); @@ -1496,10 +1413,11 @@ static int pd_video_release(struct file *file) pd->file_for_stream = NULL; pd->video_data.users--; } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - pd->state &= ~POSEIDON_STATE_VBI; pd->vbi_data.front = NULL; pd->vbi_data.users--; } + if (!pd->vbi_data.users && !pd->video_data.users) + pd->state &= ~POSEIDON_STATE_ANALOG; videobuf_stop(&front->q); videobuf_mmap_free(&front->q); @@ -1551,7 +1469,6 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, .vidioc_s_fmt_vid_cap = vidioc_s_fmt, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */ - .vidioc_try_fmt_vid_cap = vidioc_try_fmt, /* Input */ .vidioc_g_input = vidioc_g_input, @@ -1566,6 +1483,7 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { /* Tuner ioctls */ .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, @@ -1579,59 +1497,29 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { /* Stream on/off */ .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - - /* Control handling */ - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static struct video_device pd_video_template = { .name = "Telegent-Video", .fops = &pd_video_fops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, .tvnorms = V4L2_STD_ALL, .ioctl_ops = &pd_video_ioctl_ops, }; -struct video_device *vdev_init(struct poseidon *pd, struct video_device *tmp) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (vfd == NULL) - return NULL; - *vfd = *tmp; - vfd->minor = -1; - vfd->v4l2_dev = &pd->v4l2_dev; - /*vfd->parent = &(pd->udev->dev); */ - vfd->release = video_device_release; - video_set_drvdata(vfd, pd); - return vfd; -} - -void destroy_video_device(struct video_device **v_dev) -{ - struct video_device *dev = *v_dev; - - if (dev == NULL) - return; - - if (video_is_registered(dev)) - video_unregister_device(dev); - else - video_device_release(dev); - *v_dev = NULL; -} +static const struct v4l2_ctrl_ops tlg_ctrl_ops = { + .s_ctrl = tlg_s_ctrl, +}; void pd_video_exit(struct poseidon *pd) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; - destroy_video_device(&video->v_dev); - destroy_video_device(&vbi->v_dev); + video_unregister_device(&video->v_dev); + video_unregister_device(&vbi->v_dev); + v4l2_ctrl_handler_free(&video->ctrl_handler); log(); } @@ -1639,23 +1527,39 @@ int pd_video_init(struct poseidon *pd) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; + struct v4l2_ctrl_handler *hdl = &video->ctrl_handler; + u32 freq = TUNER_FREQ_MIN / 62500; int ret = -ENOMEM; - video->v_dev = vdev_init(pd, &pd_video_template); - if (video->v_dev == NULL) - goto out; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_BRIGHTNESS, + 0, 10000, 1, 100); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_CONTRAST, + 0, 10000, 1, 100); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_HUE, + 0, 10000, 1, 100); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_SATURATION, + 0, 10000, 1, 100); + if (hdl->error) { + v4l2_ctrl_handler_free(hdl); + return hdl->error; + } + set_frequency(pd, &freq); + video->v_dev = pd_video_template; + video->v_dev.v4l2_dev = &pd->v4l2_dev; + video->v_dev.ctrl_handler = hdl; + video_set_drvdata(&video->v_dev, pd); - ret = video_register_device(video->v_dev, VFL_TYPE_GRABBER, -1); + ret = video_register_device(&video->v_dev, VFL_TYPE_GRABBER, -1); if (ret != 0) goto out; /* VBI uses the same template as video */ - vbi->v_dev = vdev_init(pd, &pd_video_template); - if (vbi->v_dev == NULL) { - ret = -ENOMEM; - goto out; - } - ret = video_register_device(vbi->v_dev, VFL_TYPE_VBI, -1); + vbi->v_dev = pd_video_template; + vbi->v_dev.v4l2_dev = &pd->v4l2_dev; + vbi->v_dev.ctrl_handler = hdl; + video_set_drvdata(&vbi->v_dev, pd); + ret = video_register_device(&vbi->v_dev, VFL_TYPE_VBI, -1); if (ret != 0) goto out; log("register VIDEO/VBI devices"); @@ -1665,4 +1569,3 @@ out: pd_video_exit(pd); return ret; } - |