summaryrefslogtreecommitdiff
path: root/drivers/media/usb/tlg2300
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/tlg2300')
-rw-r--r--drivers/media/usb/tlg2300/pd-common.h26
-rw-r--r--drivers/media/usb/tlg2300/pd-main.c16
-rw-r--r--drivers/media/usb/tlg2300/pd-radio.c229
-rw-r--r--drivers/media/usb/tlg2300/pd-video.c303
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 *)&param; /* 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;
}
-