aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/go7007/go7007-v4l2.c
diff options
context:
space:
mode:
authorPete Eberlein <pete@sensoray.com>2008-10-30 12:56:33 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-06 13:52:06 -0800
commitd73f822ce775e004836ffc01ce9feae27d0d65cf (patch)
tree4b731a46fdd6536417ff5f1ee8d2091500ccb83e /drivers/staging/go7007/go7007-v4l2.c
parentb2d6a78d9f5323dcb69f7e10476f9fd001c296ff (diff)
Staging: go7007: saa7134 updates
- Added documentation including README files from the original go7007 driver package. - Added Video4Linux2 MPEG controls. - Added Video4Linux2 audio ioctls, which pass thru to the i2c driver. - Improved saa7134 interface, to pass thru controls and video settings. - Fixed a bug in sony tuner, as reported by Bifferos on the Go7007 wiki. Signed-off-by: Pete Eberlein <pete@sensoray.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/go7007/go7007-v4l2.c')
-rw-r--r--drivers/staging/go7007/go7007-v4l2.c281
1 files changed, 268 insertions, 13 deletions
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
index dfbc2e91c23..e0b17a0145c 100644
--- a/drivers/staging/go7007/go7007-v4l2.c
+++ b/drivers/staging/go7007/go7007-v4l2.c
@@ -38,6 +38,14 @@
#include "go7007-priv.h"
#include "wis-i2c.h"
+/* Temporary defines until accepted in v4l-dvb */
+#ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM
+#define V4L2_MPEG_STREAM_TYPE_MPEG_ELEM 6 /* MPEG elementary stream */
+#endif
+#ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4
+#define V4L2_MPEG_VIDEO_ENCODING_MPEG_4 3
+#endif
+
static void deactivate_buffer(struct go7007_buffer *gobuf)
{
int i;
@@ -375,6 +383,223 @@ static int clip_to_modet_map(struct go7007 *go, int region,
return 0;
}
+static int mpeg_queryctrl(u32 id, struct v4l2_queryctrl *ctrl)
+{
+ static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ 0
+ };
+ static const u32 mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 0
+ };
+ static const u32 *ctrl_classes[] = {
+ user_ctrls,
+ mpeg_ctrls,
+ NULL
+ };
+
+ /* The ctrl may already contain the queried i2c controls,
+ * query the mpeg controls if the existing ctrl id is
+ * greater than the next mpeg ctrl id.
+ */
+ id = v4l2_ctrl_next(ctrl_classes, id);
+ if (id >= ctrl->id && ctrl->name[0])
+ return 0;
+
+ memset(ctrl, 0, sizeof(*ctrl));
+ ctrl->id = id;
+
+ switch (ctrl->id) {
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill_std(ctrl);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(ctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_DVD,
+ V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG_ELEM);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(ctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(ctrl,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
+ V4L2_MPEG_VIDEO_ASPECT_1x1);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill_std(ctrl);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(ctrl,
+ 64000,
+ 10000000, 1,
+ 9800000);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int mpeg_s_control(struct v4l2_control *ctrl, struct go7007 *go)
+{
+ /* pretty sure we can't change any of these while streaming */
+ if (go->streaming)
+ return -EBUSY;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ switch (ctrl->value) {
+ case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD:
+ go->format = GO7007_FORMAT_MPEG2;
+ go->bitrate = 9800000;
+ go->gop_size = 15;
+ go->pali = 0x48;
+ go->closed_gop = 1;
+ go->repeat_seqhead = 0;
+ go->seq_header_enable = 1;
+ go->gop_header_enable = 1;
+ go->dvd_mode = 1;
+ break;
+ case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM:
+ /* todo: */
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ switch (ctrl->value) {
+ case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
+ go->format = GO7007_FORMAT_MPEG1;
+ go->pali = 0;
+ break;
+ case V4L2_MPEG_VIDEO_ENCODING_MPEG_2:
+ go->format = GO7007_FORMAT_MPEG2;
+ /*if (mpeg->pali >> 24 == 2)
+ go->pali = mpeg->pali & 0xff;
+ else*/
+ go->pali = 0x48;
+ break;
+ case V4L2_MPEG_VIDEO_ENCODING_MPEG_4:
+ go->format = GO7007_FORMAT_MPEG4;
+ /*if (mpeg->pali >> 24 == 4)
+ go->pali = mpeg->pali & 0xff;
+ else*/
+ go->pali = 0xf5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ go->gop_header_enable =
+ /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
+ ? 0 :*/ 1;
+ /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
+ go->repeat_seqhead = 1;
+ else*/
+ go->repeat_seqhead = 0;
+ go->dvd_mode = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ if (go->format == GO7007_FORMAT_MJPEG)
+ return -EINVAL;
+ switch (ctrl->value) {
+ case V4L2_MPEG_VIDEO_ASPECT_1x1:
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
+ go->aspect_ratio = GO7007_RATIO_4_3;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
+ go->aspect_ratio = GO7007_RATIO_16_9;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_221x100:
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ go->gop_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ if (ctrl->value != 0 && ctrl->value != 1)
+ return -EINVAL;
+ go->closed_gop = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ /* Upper bound is kind of arbitrary here */
+ if (ctrl->value < 64000 || ctrl->value > 10000000)
+ return -EINVAL;
+ go->bitrate = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mpeg_g_control(struct v4l2_control *ctrl, struct go7007 *go)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ if (go->dvd_mode)
+ ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
+ else
+ ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ switch (go->format) {
+ case GO7007_FORMAT_MPEG1:
+ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ break;
+ case GO7007_FORMAT_MPEG2:
+ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ break;
+ case GO7007_FORMAT_MPEG4:
+ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ switch (go->aspect_ratio) {
+ case GO7007_RATIO_1_1:
+ ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1;
+ break;
+ case GO7007_RATIO_4_3:
+ ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ break;
+ case GO7007_RATIO_16_9:
+ ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = go->gop_size;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ ctrl->value = go->closed_gop;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = go->bitrate;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct go7007_file *gofh = file->private_data;
@@ -392,7 +617,7 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
strncpy(cap->card, go->name, sizeof(cap->card));
cap->version = KERNEL_VERSION(0, 9, 8);
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
+ V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
@@ -464,6 +689,19 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return -EBUSY;
return set_capture_size(go, fmt, 0);
}
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *audio = arg;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter, cmd, arg);
+ if (cmd == VIDIOC_ENUMAUDIO && !audio->name[0])
+ return -EINVAL;
+ return 0;
+ }
case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
return -EINVAL;
@@ -699,12 +937,16 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_queryctrl *ctrl = arg;
u32 id;
- if (!go->i2c_adapter_online)
- return -EIO;
id = ctrl->id;
memset(ctrl, 0, sizeof(*ctrl));
ctrl->id = id;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, arg);
+ if (go->i2c_adapter_online)
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_QUERYCTRL, arg);
+ else if (go->hpi_ops && go->hpi_ops->send_command)
+ go->hpi_ops->send_command(go, cmd, arg);
+ if (id & V4L2_CTRL_FLAG_NEXT_CTRL || ctrl->name[0] == 0)
+ return mpeg_queryctrl(id, ctrl);
return ctrl->name[0] == 0 ? -EINVAL : 0;
}
case VIDIOC_G_CTRL:
@@ -712,13 +954,16 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_control *ctrl = arg;
struct v4l2_queryctrl query;
- if (!go->i2c_adapter_online)
- return -EIO;
memset(&query, 0, sizeof(query));
query.id = ctrl->id;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+ if (go->i2c_adapter_online)
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_QUERYCTRL, &query);
+ else if (go->hpi_ops && go->hpi_ops->send_command)
+ if (0 == go->hpi_ops->send_command(go, cmd, arg))
+ return 0;
if (query.name[0] == 0)
- return -EINVAL;
+ return mpeg_g_control(ctrl, go);
i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, arg);
return 0;
}
@@ -727,13 +972,16 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_control *ctrl = arg;
struct v4l2_queryctrl query;
- if (!go->i2c_adapter_online)
- return -EIO;
memset(&query, 0, sizeof(query));
query.id = ctrl->id;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+ if (go->i2c_adapter_online)
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_QUERYCTRL, &query);
+ else if (go->hpi_ops && go->hpi_ops->send_command)
+ if (0 == go->hpi_ops->send_command(go, cmd, arg))
+ return 0;
if (query.name[0] == 0)
- return -EINVAL;
+ return mpeg_s_control(ctrl, go);
i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, arg);
return 0;
}
@@ -826,6 +1074,8 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
*std = V4L2_STD_NTSC;
else
*std = V4L2_STD_PAL | V4L2_STD_SECAM;
+ } else if (go->hpi_ops && go->hpi_ops->send_command) {
+ go->hpi_ops->send_command(go, cmd, arg);
} else
*std = 0;
return 0;
@@ -864,6 +1114,9 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (go->i2c_adapter_online)
i2c_clients_command(&go->i2c_adapter,
VIDIOC_S_STD, std);
+ if (go->hpi_ops && go->hpi_ops->send_command)
+ go->hpi_ops->send_command(go, cmd, arg);
+
set_capture_size(go, NULL, 0);
return 0;
}
@@ -1316,7 +1569,7 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return clip_to_modet_map(go, region->region, region->clips);
}
default:
- printk(KERN_DEBUG "go7007: unsupported ioctl %d\n", cmd);
+ printk(KERN_INFO "go7007-v4l2: unsupported ioctl %d\n", cmd);
return -ENOIOCTLCMD;
}
return 0;
@@ -1474,6 +1727,8 @@ int go7007_v4l2_init(struct go7007 *go)
}
video_set_drvdata(go->video_dev, go);
++go->ref_count;
+ printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
+ go->video_dev->name, go->video_dev->num);
return 0;
}