MicrodiaのdriverでYUYVがVIDIOC_S_FMTできない
ioctl
で VIDIOC_S_FMT
をセットするとerrno 22が返ってくるので調べてみた。
以下環境 - OS: Ubuntu 8.04 - Kernel: linux 2.6.24.22 - microdia driver: http://groups.google.com/group/microdia?hl=en - Groovy GR-CAM130N2 - ベンダーID及びプロダクトID 0c45:627b - Bridge : SN9C201 - Image Sensor : OV7660
まずはsystem callのioctl
を呼ぶとcallされるkernel内のv4lのioctl
関数を発見。
linux-source-2.6.24/drivers/media/video/videodev.c
433 static int __video_do_ioctl(struct inode *inode, struct file *file, 434 unsigned int cmd, void *arg) 435 {
VIDIOC_S_FMT
を ioctl
に渡すと以下のcase文にくる。どうも659行目が失敗しているかんじ。
647 case VIDIOC_S_FMT: 648 { 649 struct v4l2_format *f = (struct v4l2_format *)arg; 650 651 /* FIXME: Should be one dump per type */ 652 dbgarg (cmd, "type=%s\n", prt_names(f->type, 653 v4l2_type_names_FIXME)); 654 655 switch (f->type) { 656 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 657 v4l_print_pix_fmt(vfd,&f->fmt.pix); 658 if (vfd->vidioc_s_fmt_cap) 659 ret=vfd->vidioc_s_fmt_cap(file, fh, f); 660 break;
vidioc_s_fmt_cap
は vfd
のメンバ変数なので調べてみる。以下の157目が呼ばれる。
84 struct video_device 85 { ・・・ 155 /* VIDIOC_S_FMT handlers */ 156 int (*vidioc_s_fmt_cap) (struct file *file, void *fh, 157 struct v4l2_format *f);
続いて microdia driver内のコードで vidioc_s_fmt_cap
に実体を代入している箇所を調べる。
microdia-v4l.c
1353 int v4l_microdia_register_video_device(struct usb_microdia *dev) 1354 { ・・・ 1382 dev->vdev->vidioc_s_fmt_cap = microdia_vidioc_s_fmt_cap;
v4l_microdia_register_video_device
関数内で microdia_vidioc_s_fmt_cap
を代入しているので実体を調べる。
1026 int microdia_vidioc_s_fmt_cap(struct file *file, void *priv, 1027 struct v4l2_format *fmt) 1028 { ・・・ 1042 ret = microdia_vidioc_try_fmt_cap(file, priv, fmt); 1043 if (ret) 1044 return -EINVAL;
1042行目があやしい・・
ついに、printk
を仕込み977行目で EINVAL
を返しているのを確認。どうもここが NULL
なのがダメみたい。
956 int microdia_vidioc_try_fmt_cap(struct file *file, void *priv, 957 struct v4l2_format *fmt) 958 { ・・・ 970 for (index = 0; index < dev->camera.nfmts; index++) 971 if (dev->camera.fmts[index].pix_fmt == fmt->fmt.pix.pixelformat) 972 break; 973 974 if (index >= dev->camera.nfmts) 975 return -EINVAL; 976 977 if (dev->camera.fmts[index].set_format == NULL) 978 return -EINVAL;
ちょっと fmts
の構造体を調べてみる。
microdia-dev.c
208 static struct microdia_video_format default_fmts[] = { 209 { ・・・ 243 { 244 .pix_fmt = V4L2_PIX_FMT_YUYV, 245 .desc = "YUV 4:2:2 (YUYV)", 246 .depth = 16, 247 .modes = { 248 {160, 120, SN9C20X_1_4_SCALE, 249 {0, 0, 1280, 480}, 250 {0, 0, 320, 120} }, 251 {320, 240, SN9C20X_1_2_SCALE, 252 {0, 0, 1280, 480}, 253 {0, 0, 640, 240} }, 254 {640, 480, SN9C20X_NO_SCALE, 255 {0, 0, 1280, 480}, 256 {0, 0, 1280, 480} }, 257 }, 258 .set_format = NULL 259 },
V4L2_PIX_FMT_YUYV
のところをみると .set_format
に NULL
が・・・。
これは絶対上記の977行目ではじかれるんじゃね?っと思いつつもう少しコードを読んでみるとどうも後から .set_format
をセットしてるような箇所を発見した。
262 int dev_microdia_assign_fmts(struct usb_microdia *dev) 263 { 264 int i, j; 265 266 dev->camera.fmts = default_fmts; 267 dev->camera.nfmts = ARRAY_SIZE(default_fmts); 268 269 for (i = 0; i < ARRAY_SIZE(default_fmts); i++) { 270 if (dev->camera.sensor->set_yuv422 != NULL) && 271 (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_YUYV) 272 dev->camera.fmts[i].set_format = 273 dev->camera.sensor->set_yuv422; 274 if (dev->camera.sensor->set_bayer != NULL) && 275 (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_SBGGR8) 276 dev->camera.fmts[i].set_format = 277 dev->camera.sensor->set_bayer; 278 for (j = 0; j < N_MODES; j++) { 279 dev->camera.fmts[i].modes[j].hw_window[0] = 280 dev->camera.sensor->hstart; 281 dev->camera.fmts[i].modes[j].hw_window[1] = 282 dev->camera.sensor->vstart; 283 } 284 } 285 286 return 0; 287 }
pix_fmt == V4L2_PIX_FMT_YUYV
なので pix_fmt == V4L2_PIX_FMT_YUYV
が存在していたら set_format
にセットするようなので sensor
変数を見てみた。
36 static struct sensor_info sensors[] = { ・・・ 76 { 77 .id = OV7660_SENSOR, 78 .name = "OV7660", 79 .address = 0x21, 80 .initialize = ov_initialize, 81 .set_exposure = ov7660_set_exposure, 82 .set_auto_gain = ov_set_autogain, 83 .hstart = 1, 84 .vstart = 1, 85 .get_yavg = ov965x_get_yavg, 86 .min_yavg = 30, 87 .max_yavg = 60, 88 .min_stable_yavg = 32, 89 .max_stable_yavg = 58, 90 },
set_format
がない。。つまり未定義なので NULL
。
ここまできてなんとなくわかったのはYUYVは基本的に未サポートでセンサーごとに実装するようなつくりになっているということ。
つまり、現段階ではOV7660のYUYVは未サポートでした。
(http://groups.google.com/group/microdia/web/project-status?hl=enのStatusはSupportedになっているのに。)
ちなみに以下の箇所をコメントアウトして動作させるとノイズだらけの映像が出力されたとさ
977 if (dev->camera.fmts[index].set_format == NULL) 978 return -EINVAL;