Skip to content

Commit

Permalink
[media] saa7146: fix querycap, vbi/video separation and g/s_register
Browse files Browse the repository at this point in the history
The querycap ioctl returned an incorrect version number and incorrect
capabilities (mixing up vbi and video caps).

The reason for that was that video nodes could do vbi activities: that
should be separated between the vbi and video nodes.

There were also a few minor problems with dbg_g/s_register that have
been resolved. The mxb/saa7146 driver now passes the v4l2_compliance tests.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed May 14, 2012
1 parent 537fa49 commit ab49ae0
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 46 deletions.
8 changes: 6 additions & 2 deletions drivers/media/common/saa7146_fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
v4l2_ctrl_handler_free(hdl);
return -ENOMEM;
}
ext_vv->ops = saa7146_video_ioctl_ops;
ext_vv->vid_ops = saa7146_video_ioctl_ops;
ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
ext_vv->core_ops = &saa7146_video_ioctl_ops;

DEB_EE("dev:%p\n", dev);
Expand Down Expand Up @@ -579,7 +580,10 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
return -ENOMEM;

vfd->fops = &video_fops;
vfd->ioctl_ops = &dev->ext_vv_data->ops;
if (type == VFL_TYPE_GRABBER)
vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
else
vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
vfd->release = video_device_release;
/* Locking in file operations other than ioctl should be done by
the driver, not the V4L2 core.
Expand Down
35 changes: 31 additions & 4 deletions drivers/media/common/saa7146_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,18 +446,24 @@ static int video_end(struct saa7146_fh *fh, struct file *file)

static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;

strcpy((char *)cap->driver, "saa7146 v4l2");
strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->version = SAA7146_VERSION_CODE;
cap->device_caps =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
cap->device_caps |= dev->ext_vv_data->capabilities;
if (vdev->vfl_type == VFL_TYPE_GRABBER)
cap->device_caps &=
~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
else
cap->device_caps &=
~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY);
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
Expand Down Expand Up @@ -990,10 +996,14 @@ static int vidioc_g_chip_ident(struct file *file, void *__fh,

chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) {
chip->ident = V4L2_IDENT_SAA7146;
if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
if (v4l2_chip_match_host(&chip->match))
chip->ident = V4L2_IDENT_SAA7146;
return 0;
}
if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
core, g_chip_ident, chip);
}
Expand All @@ -1008,7 +1018,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_chip_ident = vidioc_g_chip_ident,

.vidioc_overlay = vidioc_overlay,
Expand All @@ -1027,6 +1036,24 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};

const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_chip_ident = vidioc_g_chip_ident,

.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};

/*********************************************************************************/
/* buffer handling functions */

Expand Down
24 changes: 12 additions & 12 deletions drivers/media/dvb/ttpci/av7110_v4l.c
Original file line number Diff line number Diff line change
Expand Up @@ -802,18 +802,18 @@ int av7110_init_v4l(struct av7110 *av7110)
ERR("cannot init capture device. skipping\n");
return -ENODEV;
}
vv_data->ops.vidioc_enum_input = vidioc_enum_input;
vv_data->ops.vidioc_g_input = vidioc_g_input;
vv_data->ops.vidioc_s_input = vidioc_s_input;
vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
vv_data->ops.vidioc_g_audio = vidioc_g_audio;
vv_data->ops.vidioc_s_audio = vidioc_s_audio;
vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input;
vv_data->vid_ops.vidioc_g_input = vidioc_g_input;
vv_data->vid_ops.vidioc_s_input = vidioc_s_input;
vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner;
vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner;
vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency;
vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency;
vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio;
vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio;
vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;

if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
ERR("cannot register capture device. skipping\n");
Expand Down
6 changes: 3 additions & 3 deletions drivers/media/dvb/ttpci/budget-av.c
Original file line number Diff line number Diff line change
Expand Up @@ -1483,9 +1483,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
ERR("cannot init vv subsystem\n");
return err;
}
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
vv_data.vid_ops.vidioc_s_input = vidioc_s_input;

if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
/* fixme: proper cleanup here */
Expand Down
12 changes: 6 additions & 6 deletions drivers/media/video/hexium_gemini.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,12 +399,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
hexium->cur_input = 0;

saa7146_vv_init(dev, &vv_data);
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
vv_data.vid_ops.vidioc_queryctrl = vidioc_queryctrl;
vv_data.vid_ops.vidioc_g_ctrl = vidioc_g_ctrl;
vv_data.vid_ops.vidioc_s_ctrl = vidioc_s_ctrl;
vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
if (ret < 0) {
pr_err("cannot register capture v4l2 device. skipping.\n");
Expand Down
6 changes: 3 additions & 3 deletions drivers/media/video/hexium_orion.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
DEB_EE("\n");

saa7146_vv_init(dev, &vv_data);
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
pr_err("cannot register capture v4l2 device. skipping.\n");
return -1;
Expand Down
41 changes: 28 additions & 13 deletions drivers/media/video/mxb.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,13 +662,28 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;

return call_all(dev, core, g_register, reg);
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (v4l2_chip_match_host(&reg->match)) {
reg->val = saa7146_read(dev, reg->reg);
reg->size = 4;
return 0;
}
call_all(dev, core, g_register, reg);
return 0;
}

static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (v4l2_chip_match_host(&reg->match)) {
saa7146_write(dev, reg->reg, reg->val);
reg->size = 4;
return 0;
}
return call_all(dev, core, s_register, reg);
}
#endif
Expand All @@ -689,19 +704,19 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
}
mxb = (struct mxb *)dev->ext_priv;

vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
vv_data.ops.vidioc_enumaudio = vidioc_enumaudio;
vv_data.ops.vidioc_g_audio = vidioc_g_audio;
vv_data.ops.vidioc_s_audio = vidioc_s_audio;
vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
vv_data.vid_ops.vidioc_g_tuner = vidioc_g_tuner;
vv_data.vid_ops.vidioc_s_tuner = vidioc_s_tuner;
vv_data.vid_ops.vidioc_g_frequency = vidioc_g_frequency;
vv_data.vid_ops.vidioc_s_frequency = vidioc_s_frequency;
vv_data.vid_ops.vidioc_enumaudio = vidioc_enumaudio;
vv_data.vid_ops.vidioc_g_audio = vidioc_g_audio;
vv_data.vid_ops.vidioc_s_audio = vidioc_s_audio;
#ifdef CONFIG_VIDEO_ADV_DEBUG
vv_data.ops.vidioc_g_register = vidioc_g_register;
vv_data.ops.vidioc_s_register = vidioc_s_register;
vv_data.vid_ops.vidioc_g_register = vidioc_g_register;
vv_data.vid_ops.vidioc_s_register = vidioc_s_register;
#endif
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR("cannot register capture v4l2 device. skipping.\n");
Expand Down
2 changes: 0 additions & 2 deletions include/media/saa7146.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
#include <linux/vmalloc.h> /* for vmalloc() */
#include <linux/mm.h> /* for vmalloc_to_page() */

#define SAA7146_VERSION_CODE 0x000600 /* 0.6.0 */

#define saa7146_write(sxy,adr,dat) writel((dat),(sxy->mem+(adr)))
#define saa7146_read(sxy,adr) readl(sxy->mem+(adr))

Expand Down
4 changes: 3 additions & 1 deletion include/media/saa7146_vv.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ struct saa7146_ext_vv
int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);

/* the extension can override this */
struct v4l2_ioctl_ops ops;
struct v4l2_ioctl_ops vid_ops;
struct v4l2_ioctl_ops vbi_ops;
/* pointer to the saa7146 core ops */
const struct v4l2_ioctl_ops *core_ops;

Expand Down Expand Up @@ -200,6 +201,7 @@ void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);

/* from saa7146_video.c */
extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops;
extern struct saa7146_use_ops saa7146_video_uops;
int saa7146_start_preview(struct saa7146_fh *fh);
int saa7146_stop_preview(struct saa7146_fh *fh);
Expand Down

0 comments on commit ab49ae0

Please sign in to comment.