fimc_capture.c在FIMC系統中的位置,網上偷來的一幅圖片
- 43 static const struct v4l2_fmtdesc capture_fmts[] = {
- 44 {
- 45 .index = 0,
- 46 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 47 .flags = FORMAT_FLAGS_PACKED,
- 48 .description = "RGB-5-6-5",
- 49 .pixelformat = V4L2_PIX_FMT_RGB565,
- 50 }, {
- 51 .index = 1,
- 52 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 53 .flags = FORMAT_FLAGS_PACKED,
- 54 .description = "RGB-8-8-8, unpacked 24 bpp",
- 55 .pixelformat = V4L2_PIX_FMT_RGB32,
- 56 }, {
- 57 .index = 2,
- 58 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 59 .flags = FORMAT_FLAGS_PACKED,
- 60 .description = "YUV 4:2:2 packed, YCbYCr",
- 61 .pixelformat = V4L2_PIX_FMT_YUYV,
- 62 }, {
- 63 .index = 3,
- 64 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 65 .flags = FORMAT_FLAGS_PACKED,
- 66 .description = "YUV 4:2:2 packed, CbYCrY",
- 67 .pixelformat = V4L2_PIX_FMT_UYVY,
- 68 }, {
- 69 .index = 4,
- 70 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 71 .flags = FORMAT_FLAGS_PACKED,
- 72 .description = "YUV 4:2:2 packed, CrYCbY",
- 73 .pixelformat = V4L2_PIX_FMT_VYUY,
- 74 }, {
- 75 .index = 5,
- 76 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 77 .flags = FORMAT_FLAGS_PACKED,
- 78 .description = "YUV 4:2:2 packed, YCrYCb",
- 79 .pixelformat = V4L2_PIX_FMT_YVYU,
- 80 }, {
- 81 .index = 6,
- 82 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 83 .flags = FORMAT_FLAGS_PLANAR,
- 84 .description = "YUV 4:2:2 planar, Y/Cb/Cr",
- 85 .pixelformat = V4L2_PIX_FMT_YUV422P,
- 86 }, {
- 87 .index = 7,
- 88 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 89 .flags = FORMAT_FLAGS_PLANAR,
- 90 .description = "YUV 4:2:0 planar, Y/CbCr",
- 91 .pixelformat = V4L2_PIX_FMT_NV12,
- 92 }, {
- 93 .index = 8,
- 94 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 95 .flags = FORMAT_FLAGS_PLANAR,
- 96 .description = "YUV 4:2:0 planar, Y/CbCr, Tiled",
- 97 .pixelformat = V4L2_PIX_FMT_NV12T,
- 98 }, {
- 99 .index = 9,
- 100 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 101 .flags = FORMAT_FLAGS_PLANAR,
- 102 .description = "YUV 4:2:0 planar, Y/CrCb",
- 103 .pixelformat = V4L2_PIX_FMT_NV21,
- 104 }, {
- 105 .index = 10,
- 106 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 107 .flags = FORMAT_FLAGS_PLANAR,
- 108 .description = "YUV 4:2:2 planar, Y/CbCr",
- 109 .pixelformat = V4L2_PIX_FMT_NV16,
- 110 }, {
- 111 .index = 11,
- 112 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 113 .flags = FORMAT_FLAGS_PLANAR,
- 114 .description = "YUV 4:2:2 planar, Y/CrCb",
- 115 .pixelformat = V4L2_PIX_FMT_NV61,
- 116 }, {
- 117 .index = 12,
- 118 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 119 .flags = FORMAT_FLAGS_PLANAR,
- 120 .description = "YUV 4:2:0 planar, Y/Cb/Cr",
- 121 .pixelformat = V4L2_PIX_FMT_YUV420,
- 122 }, {
- 123 .index = 13,
- 124 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- 125 .flags = FORMAT_FLAGS_ENCODED,
- 126 .description = "Encoded JPEG bitstream",
- 127 .pixelformat = V4L2_PIX_FMT_JPEG,
- 128 },
- 129 };
43 static const struct v4l2_fmtdesc capture_fmts[] = {
44 {
45 .index = 0,
46 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
47 .flags = FORMAT_FLAGS_PACKED,
48 .description = "RGB-5-6-5",
49 .pixelformat = V4L2_PIX_FMT_RGB565,
50 }, {
51 .index = 1,
52 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
53 .flags = FORMAT_FLAGS_PACKED,
54 .description = "RGB-8-8-8, unpacked 24 bpp",
55 .pixelformat = V4L2_PIX_FMT_RGB32,
56 }, {
57 .index = 2,
58 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
59 .flags = FORMAT_FLAGS_PACKED,
60 .description = "YUV 4:2:2 packed, YCbYCr",
61 .pixelformat = V4L2_PIX_FMT_YUYV,
62 }, {
63 .index = 3,
64 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
65 .flags = FORMAT_FLAGS_PACKED,
66 .description = "YUV 4:2:2 packed, CbYCrY",
67 .pixelformat = V4L2_PIX_FMT_UYVY,
68 }, {
69 .index = 4,
70 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
71 .flags = FORMAT_FLAGS_PACKED,
72 .description = "YUV 4:2:2 packed, CrYCbY",
73 .pixelformat = V4L2_PIX_FMT_VYUY,
74 }, {
75 .index = 5,
76 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
77 .flags = FORMAT_FLAGS_PACKED,
78 .description = "YUV 4:2:2 packed, YCrYCb",
79 .pixelformat = V4L2_PIX_FMT_YVYU,
80 }, {
81 .index = 6,
82 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
83 .flags = FORMAT_FLAGS_PLANAR,
84 .description = "YUV 4:2:2 planar, Y/Cb/Cr",
85 .pixelformat = V4L2_PIX_FMT_YUV422P,
86 }, {
87 .index = 7,
88 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
89 .flags = FORMAT_FLAGS_PLANAR,
90 .description = "YUV 4:2:0 planar, Y/CbCr",
91 .pixelformat = V4L2_PIX_FMT_NV12,
92 }, {
93 .index = 8,
94 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
95 .flags = FORMAT_FLAGS_PLANAR,
96 .description = "YUV 4:2:0 planar, Y/CbCr, Tiled",
97 .pixelformat = V4L2_PIX_FMT_NV12T,
98 }, {
99 .index = 9,
100 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
101 .flags = FORMAT_FLAGS_PLANAR,
102 .description = "YUV 4:2:0 planar, Y/CrCb",
103 .pixelformat = V4L2_PIX_FMT_NV21,
104 }, {
105 .index = 10,
106 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
107 .flags = FORMAT_FLAGS_PLANAR,
108 .description = "YUV 4:2:2 planar, Y/CbCr",
109 .pixelformat = V4L2_PIX_FMT_NV16,
110 }, {
111 .index = 11,
112 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
113 .flags = FORMAT_FLAGS_PLANAR,
114 .description = "YUV 4:2:2 planar, Y/CrCb",
115 .pixelformat = V4L2_PIX_FMT_NV61,
116 }, {
117 .index = 12,
118 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
119 .flags = FORMAT_FLAGS_PLANAR,
120 .description = "YUV 4:2:0 planar, Y/Cb/Cr",
121 .pixelformat = V4L2_PIX_FMT_YUV420,
122 }, {
123 .index = 13,
124 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
125 .flags = FORMAT_FLAGS_ENCODED,
126 .description = "Encoded JPEG bitstream",
127 .pixelformat = V4L2_PIX_FMT_JPEG,
128 },
129 };
這個列表列出了FIMC支持的capture格式,app可以通過vidioc_s_fmt設置capture的輸出格式,capture的輸出格式必須在上面的列表中
這裏的flags標誌位並不符合V4L2標準,V4L2只支持一種標誌:V4L2_FMT_FLAG_COMPRESSED。
samsung擴展了flags標誌:
FORMAT_FLAGS_PACKED: 圖片的像素點分量放在一同一個buffer中
FORMAT_FLAGS_PLANAR:圖片像素的分量放在不同的buffer中
FORMAT_FLAGS_ENCODED:圖片數據編碼存儲,如jpeg格式
- static int fimc_camera_init(struct fimc_control *ctrl)
- 202 {
- 203 int ret;
- 204
- 205 fimc_dbg("%s\n", __func__);
- 206
- 207 /* do nothing if already initialized */
- 208 if (ctrl->cam->initialized)
- 209 return 0;
- 210
- 211 /* enable camera power if needed */
- 212 if (ctrl->cam->cam_power)
- 213 ctrl->cam->cam_power(1);
- 214
- 215 /* subdev call for init */
- 216 ret = subdev_call(ctrl, core, init, 0);
- 217 if (ret == -ENOIOCTLCMD) {
- 218 fimc_err("%s: init subdev api not supported\n",
- 219 __func__);
- 220 return ret;
- 221 }
- 222
- 223 if (ctrl->cam->type == CAM_TYPE_MIPI) {
- 224 /* subdev call for sleep/wakeup:
- 225 * no error although no s_stream api support
- 226 */
- 227 u32 pixelformat;
- 228 if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)
- 229 pixelformat = V4L2_PIX_FMT_JPEG;
- 230 else
- 231 pixelformat = ctrl->cam->pixelformat;
- 232
- 233 subdev_call(ctrl, video, s_stream, 0);
- 234 s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle, \
- 235 ctrl->cam->mipi_align, ctrl->cam->width, \
- 236 ctrl->cam->height, pixelformat);
- 237 subdev_call(ctrl, video, s_stream, 1);
- 238 }
- 239
- 240 ctrl->cam->initialized = 1;
- 241
- 242 return 0;
- 243 }
201 static int fimc_camera_init(struct fimc_control *ctrl)
202 {
203 int ret;
204
205 fimc_dbg("%s\n", __func__);
206
207 /* do nothing if already initialized */
208 if (ctrl->cam->initialized)
209 return 0;
210
211 /* enable camera power if needed */
212 if (ctrl->cam->cam_power)
213 ctrl->cam->cam_power(1);
214
215 /* subdev call for init */
216 ret = subdev_call(ctrl, core, init, 0);
217 if (ret == -ENOIOCTLCMD) {
218 fimc_err("%s: init subdev api not supported\n",
219 __func__);
220 return ret;
221 }
222
223 if (ctrl->cam->type == CAM_TYPE_MIPI) {
224 /* subdev call for sleep/wakeup:
225 * no error although no s_stream api support
226 */
227 u32 pixelformat;
228 if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)
229 pixelformat = V4L2_PIX_FMT_JPEG;
230 else
231 pixelformat = ctrl->cam->pixelformat;
232
233 subdev_call(ctrl, video, s_stream, 0);
234 s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle, \
235 ctrl->cam->mipi_align, ctrl->cam->width, \
236 ctrl->cam->height, pixelformat);
237 subdev_call(ctrl, video, s_stream, 1);
238 }
239
240 ctrl->cam->initialized = 1;
241
242 return 0;
243 }
這個函數主要對camera的sensor進行上電,初始化,這個函數最早的調用位置是streamon。
但是有一個問題,假定外圍電路是一個video AD轉換芯片託多個cvbs s-video或者YPbPr輸入,那麼在執行streamon之前,要首先執行s_input操作選擇哪個video AD芯片的輸入。選擇video AD 的input輸入是要操作AD芯片I2C寄存器的,因此這個上電位置是有問題的。
- 368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)
- 369 {
- 370 struct fimc_capinfo *cap = ctrl->cap;
- 371
- 372 struct fimc_buf_set *buf;
- 373
- 374 if (i >= cap->nr_bufs)
- 375 return -EINVAL;
- 376
- 377 list_for_each_entry(buf, &cap->inq, list) {
- 378 if (buf->id == i) {
- 379 fimc_dbg("%s: buffer %d already in inqueue.\n", \
- 380 __func__, i);
- 381 return -EINVAL;
- 382 }
- 383 }
- 384
- 385 list_add_tail(&cap->bufs[i].list, &cap->inq);
- 386
- 387 return 0;
- 388 }
368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)
369 {
370 struct fimc_capinfo *cap = ctrl->cap;
371
372 struct fimc_buf_set *buf;
373
374 if (i >= cap->nr_bufs)
375 return -EINVAL;
376
377 list_for_each_entry(buf, &cap->inq, list) {
378 if (buf->id == i) {
379 fimc_dbg("%s: buffer %d already in inqueue.\n", \
380 __func__, i);
381 return -EINVAL;
382 }
383 }
384
385 list_add_tail(&cap->bufs[i].list, &cap->inq);
386
387 return 0;
388 }
這個函數被qbuf調用,把@i指定的buffer加到cap->inq鏈表中
cap->inq是可用buffer鏈表,當FIMC更新out DMA address時,就設置爲cap->inq中的一個buffer
- 390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)
- 391 {
- 392 struct fimc_capinfo *cap = ctrl->cap;
- 393 struct fimc_buf_set *buf;
- 394
- 395 unsigned int mask = 0x2;
- 396
- 397 /* PINGPONG_2ADDR_MODE Only */
- 398 /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */
- 399
- 400 int pair_buf_index = (i^mask);
- 401
- 402 /* FIMC have 4 h/w registers */
- 403 if (i < 0 || i >= FIMC_PHYBUFS) {
- 404 fimc_err("%s: invalid queue index : %d\n", __func__, i);
- 405 return -ENOENT;
- 406 }
- 407
- 408 if (list_empty(&cap->inq))
- 409 return -ENOENT;
- 410
- 411 buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);
- 412
- 413 /* pair index buffer should be allocated first */
- 414 cap->outq[pair_buf_index] = buf->id;
- 415 fimc_hwset_output_address(ctrl, buf, pair_buf_index);
- 416
- 417 cap->outq[i] = buf->id;
- 418 fimc_hwset_output_address(ctrl, buf, i);
- 419
- 420 if (cap->nr_bufs != 1)
- 421 list_del(&buf->list);
- 422
- 423 return 0;
- 424 }
390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)
391 {
392 struct fimc_capinfo *cap = ctrl->cap;
393 struct fimc_buf_set *buf;
394
395 unsigned int mask = 0x2;
396
397 /* PINGPONG_2ADDR_MODE Only */
398 /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */
399
400 int pair_buf_index = (i^mask);
401
402 /* FIMC have 4 h/w registers */
403 if (i < 0 || i >= FIMC_PHYBUFS) {
404 fimc_err("%s: invalid queue index : %d\n", __func__, i);
405 return -ENOENT;
406 }
407
408 if (list_empty(&cap->inq))
409 return -ENOENT;
410
411 buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);
412
413 /* pair index buffer should be allocated first */
414 cap->outq[pair_buf_index] = buf->id;
415 fimc_hwset_output_address(ctrl, buf, pair_buf_index);
416
417 cap->outq[i] = buf->id;
418 fimc_hwset_output_address(ctrl, buf, i);
419
420 if (cap->nr_bufs != 1)
421 list_del(&buf->list);
422
423 return 0;
424 }
411 在cap->inq buffer鏈表中取得第一個可用buffer
413 ~ 418 一直沒明白爲什麼這裏把buf設置到兩個輸出out DMA address寄存器中,華清遠見有篇文檔http://www.embedu.org/Column/Column457.htm對這個代碼的解釋是說最多可以把四個out DMA address都配置上,可以增加畫面的流暢度。
我原來也是同意華清講師的說法的,四個output DMA address把幀數分成四個部分,第一個DMA address存儲 1, 5, 9, 13... 幀, 第二個DMA address存儲2, 6, 10, 14...幀, 第三個存儲3, 7, 11, 15...幀, 第四個存儲4, 8, 12, 16...幀,如果僅使用一個output DMA address,那麼僅能得到1/4的幀率。
但是測試後發現,刪除414~415後重新編譯的內核沒發現有幀率的變化,對幀率沒有任何影響。
420 ~ 421 從cap->inq 鏈表中刪除這個buf
- 516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
- 517 {
- 518 struct fimc_global *fimc = get_fimc_dev();
- 519 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 520
- 521 fimc_dbg("%s: index %d\n", __func__, inp->index);
- 522
- 523 if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {
- 524 fimc_err("%s: invalid input index, received = %d\n", \
- 525 __func__, inp->index);
- 526 return -EINVAL;
- 527 }
- 528
- 529 if (!fimc->camera_isvalid[inp->index])
- 530 return -EINVAL;
- 531
- 532 strcpy(inp->name, fimc->camera[inp->index].info->type);
- 533 inp->type = V4L2_INPUT_TYPE_CAMERA;
- 534
- 535 return 0;
- 536 }
516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
517 {
518 struct fimc_global *fimc = get_fimc_dev();
519 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
520
521 fimc_dbg("%s: index %d\n", __func__, inp->index);
522
523 if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {
524 fimc_err("%s: invalid input index, received = %d\n", \
525 __func__, inp->index);
526 return -EINVAL;
527 }
528
529 if (!fimc->camera_isvalid[inp->index])
530 return -EINVAL;
531
532 strcpy(inp->name, fimc->camera[inp->index].info->type);
533 inp->type = V4L2_INPUT_TYPE_CAMERA;
534
535 return 0;
536 }
我覺得fimc應該把ENUMINPUT ioctl調用傳遞給sensor驅動實現,畢竟std, status甚至name,是隸屬於sensor的特性,fimc不該管理這些信息,管理就破壞了fimc驅動的通用性。
- 538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)
- 539 {
- 540 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 541 struct fimc_global *fimc = get_fimc_dev();
- 542
- 543 /* In case of isueing g_input before s_input */
- 544 if (!ctrl->cam) {
- 545 fimc_err("no camera device selected yet!" \
- 546 "do VIDIOC_S_INPUT first\n");
- 547 return -ENODEV;
- 548 }
- 549
- 550 *i = (unsigned int) fimc->active_camera;
- 551
- 552 fimc_dbg("%s: index %d\n", __func__, *i);
- 553
- 554 return 0;
- 555 }
538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)
539 {
540 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
541 struct fimc_global *fimc = get_fimc_dev();
542
543 /* In case of isueing g_input before s_input */
544 if (!ctrl->cam) {
545 fimc_err("no camera device selected yet!" \
546 "do VIDIOC_S_INPUT first\n");
547 return -ENODEV;
548 }
549
550 *i = (unsigned int) fimc->active_camera;
551
552 fimc_dbg("%s: index %d\n", __func__, *i);
553
554 return 0;
555 }
與fimc_enum_input不同,fimc_g_input可以完全由fimc驅動實現,畢竟這個函數僅僅返回current input的編號,這個編號應該算是隸屬於video設備@file的一個特性。
- 637 int fimc_s_input(struct file *file, void *fh, unsigned int i)
- 638 {
- 639 struct fimc_global *fimc = get_fimc_dev();
- 640 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 641 int ret = 0;
- 642
- 643 fimc_dbg("%s: index %d\n", __func__, i);
- 644
- 645 if (i < 0 || i >= FIMC_MAXCAMS) {
- 646 fimc_err("%s: invalid input index\n", __func__);
- 647 return -EINVAL;
- 648 }
- 649
- 650 if (!fimc->camera_isvalid[i])
- 651 return -EINVAL;
- 652
- 653 if (fimc->camera[i].sd && ctrl->id != 2) {
- 654 fimc_err("%s: Camera already in use.\n", __func__);
- 655 return -EBUSY;
- 656 }
- 657
- 658 mutex_lock(&ctrl->v4l2_lock);
- 659 /* If ctrl->cam is not NULL, there is one subdev already registered.
- 660 * We need to unregister that subdev first.
- 661 */
- 662 if (i != fimc->active_camera) {
- 663 fimc_release_subdev(ctrl);
- 664 ctrl->cam = &fimc->camera[i];
- 665 ret = fimc_configure_subdev(ctrl);
- 666 if (ret < 0) {
- 667 mutex_unlock(&ctrl->v4l2_lock);
- 668 fimc_err("%s: Could not register camera sensor "
- 669 "with V4L2.\n", __func__);
- 670 return -ENODEV;
- 671 }
- 672 fimc->active_camera = i;
- 673 }
- 674
- 675 if (ctrl->id == 2) {
- 676 if (i == fimc->active_camera) {
- 677 ctrl->cam = &fimc->camera[i];
- 678 } else {
- 679 mutex_unlock(&ctrl->v4l2_lock);
- 680 return -EINVAL;
- 681 }
- 682 }
- 683
- 684 mutex_unlock(&ctrl->v4l2_lock);
- 685
- 686 return 0;
- 687 }
637 int fimc_s_input(struct file *file, void *fh, unsigned int i)
638 {
639 struct fimc_global *fimc = get_fimc_dev();
640 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
641 int ret = 0;
642
643 fimc_dbg("%s: index %d\n", __func__, i);
644
645 if (i < 0 || i >= FIMC_MAXCAMS) {
646 fimc_err("%s: invalid input index\n", __func__);
647 return -EINVAL;
648 }
649
650 if (!fimc->camera_isvalid[i])
651 return -EINVAL;
652
653 if (fimc->camera[i].sd && ctrl->id != 2) {
654 fimc_err("%s: Camera already in use.\n", __func__);
655 return -EBUSY;
656 }
657
658 mutex_lock(&ctrl->v4l2_lock);
659 /* If ctrl->cam is not NULL, there is one subdev already registered.
660 * We need to unregister that subdev first.
661 */
662 if (i != fimc->active_camera) {
663 fimc_release_subdev(ctrl);
664 ctrl->cam = &fimc->camera[i];
665 ret = fimc_configure_subdev(ctrl);
666 if (ret < 0) {
667 mutex_unlock(&ctrl->v4l2_lock);
668 fimc_err("%s: Could not register camera sensor "
669 "with V4L2.\n", __func__);
670 return -ENODEV;
671 }
672 fimc->active_camera = i;
673 }
674
675 if (ctrl->id == 2) {
676 if (i == fimc->active_camera) {
677 ctrl->cam = &fimc->camera[i];
678 } else {
679 mutex_unlock(&ctrl->v4l2_lock);
680 return -EINVAL;
681 }
682 }
683
684 mutex_unlock(&ctrl->v4l2_lock);
685
686 return 0;
687 }
這個函數選擇@file指定的video設備的input路徑,我的理解是s_input必須要有sensor驅動參與,這裏的實現並沒有調用sensor的接口
- 897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)
- 898 {
- 899 struct fimc_capinfo *cap = ctrl->cap;
- 900 int i, plane;
- 901
- 902 for (i = 0; i < cap->nr_bufs; i++) {
- 903 for (plane = 0; plane < 4; plane++) {
- 904 cap->bufs[i].length[plane] = size[plane];
- 905 if (!cap->bufs[i].length[plane])
- 906 continue;
- 907
- 908 fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);
- 909
- 910 if (!cap->bufs[i].base[plane])
- 911 goto err_alloc;
- 912 }
- 913
- 914 cap->bufs[i].state = VIDEOBUF_PREPARED;
- 915 cap->bufs[i].id = i;
- 916 }
- 917
- 918 return 0;
- 919
- 920 err_alloc:
- 921 for (i = 0; i < cap->nr_bufs; i++) {
- 922 if (cap->bufs[i].base[plane])
- 923 fimc_dma_free(ctrl, &cap->bufs[i], plane);
- 924
- 925 memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
- 926 }
- 927
- 928 return -ENOMEM;
- 929 }
897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)
898 {
899 struct fimc_capinfo *cap = ctrl->cap;
900 int i, plane;
901
902 for (i = 0; i < cap->nr_bufs; i++) {
903 for (plane = 0; plane < 4; plane++) {
904 cap->bufs[i].length[plane] = size[plane];
905 if (!cap->bufs[i].length[plane])
906 continue;
907
908 fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);
909
910 if (!cap->bufs[i].base[plane])
911 goto err_alloc;
912 }
913
914 cap->bufs[i].state = VIDEOBUF_PREPARED;
915 cap->bufs[i].id = i;
916 }
917
918 return 0;
919
920 err_alloc:
921 for (i = 0; i < cap->nr_bufs; i++) {
922 if (cap->bufs[i].base[plane])
923 fimc_dma_free(ctrl, &cap->bufs[i], plane);
924
925 memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
926 }
927
928 return -ENOMEM;
929 }
分配queue buffer
@align:queue buffer是DMA buffer,所以會有alignment要求
@size:不同的format,每幀需要的子buffers數目不同,這個函數的plane就代表需要的子buffers數目,size[]是一個數組,表示queue buffers的每個子buffer需求的尺寸
902 cap->nr_bufs,是capture總的queue buffers數量。
- 950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)
- 951 {
- 952 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 953 struct fimc_capinfo *cap = ctrl->cap;
- 954 int ret = 0, i;
- 955 int size[4] = { 0, 0, 0, 0};
- 956 int align = SZ_4K;
- 957
- 958 if (b->memory != V4L2_MEMORY_MMAP) {
- 959 fimc_err("%s: invalid memory type\n", __func__);
- 960 return -EINVAL;
- 961 }
- 962
- 963 if (!cap) {
- 964 fimc_err("%s: no capture device info\n", __func__);
- 965 return -ENODEV;
- 966 }
- 967
- 968 if (!ctrl->cam || !ctrl->cam->sd) {
- 969 fimc_err("%s: No capture device.\n", __func__);
- 970 return -ENODEV;
- 971 }
- 972
- 973 mutex_lock(&ctrl->v4l2_lock);
- 974
- 975 if (b->count < 1 || b->count > FIMC_CAPBUFS)
- 976 return -EINVAL;
- 977
- 978 /* It causes flickering as buf_0 and buf_3 refer to same hardware
- 979 * address.
- 980 */
- 981 if (b->count == 3)
- 982 b->count = 4;
- 983
- 984 cap->nr_bufs = b->count;
- 985
- 986 fimc_dbg("%s: requested %d buffers\n", __func__, b->count);
- 987
- 988 INIT_LIST_HEAD(&cap->inq);
- 989
- 990 fimc_free_buffers(ctrl);
- 991
- 992 switch (cap->fmt.pixelformat) {
- 993 case V4L2_PIX_FMT_RGB32: /* fall through */
- 994 case V4L2_PIX_FMT_RGB565: /* fall through */
- 995 case V4L2_PIX_FMT_YUYV: /* fall through */
- 996 case V4L2_PIX_FMT_UYVY: /* fall through */
- 997 case V4L2_PIX_FMT_VYUY: /* fall through */
- 998 case V4L2_PIX_FMT_YVYU: /* fall through */
- 999 case V4L2_PIX_FMT_YUV422P: /* fall through */
- 1000 size[0] = cap->fmt.sizeimage;
- 1001 break;
- 1002
- 1003 case V4L2_PIX_FMT_NV16: /* fall through */
- 1004 case V4L2_PIX_FMT_NV61:
- 1005 size[0] = cap->fmt.width * cap->fmt.height;
- 1006 size[1] = cap->fmt.width * cap->fmt.height;
- 1007 size[3] = 16; /* Padding buffer */
- 1008 break;
- 1009 case V4L2_PIX_FMT_NV12:
- 1010 size[0] = cap->fmt.width * cap->fmt.height;
- 1011 size[1] = cap->fmt.width * cap->fmt.height/2;
- 1012 break;
- 1013 case V4L2_PIX_FMT_NV21:
- 1014 size[0] = cap->fmt.width * cap->fmt.height;
- 1015 size[1] = cap->fmt.width * cap->fmt.height/2;
- 1016 size[3] = 16; /* Padding buffer */
- 1017 break;
- 1018 case V4L2_PIX_FMT_NV12T:
- 1019 /* Tiled frame size calculations as per 4x2 tiles
- 1020 * - Width: Has to be aligned to 2 times the tile width
- 1021 * - Height: Has to be aligned to the tile height
- 1022 * - Alignment: Has to be aligned to the size of the
- 1023 * macrotile (size of 4 tiles)
- 1024 *
- 1025 * NOTE: In case of rotation, we need modified calculation as
- 1026 * width and height are aligned to different values.
- 1027 */
- 1028 if (cap->rotate == 90 || cap->rotate == 270) {
- 1029 size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *
- 1030 ALIGN(cap->fmt.width, 32),
- 1031 SZ_8K);
- 1032 size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *
- 1033 ALIGN(cap->fmt.width/2, 32),
- 1034 SZ_8K);
- 1035 } else {
- 1036 size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *
- 1037 ALIGN(cap->fmt.height, 32),
- 1038 SZ_8K);
- 1039 size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *
- 1040 ALIGN(cap->fmt.height/2, 32),
- 1041 SZ_8K);
- 1042 }
- 1043 align = SZ_8K;
- 1044 break;
- 1045
- 1046 case V4L2_PIX_FMT_YUV420:
- 1047 size[0] = cap->fmt.width * cap->fmt.height;
- 1048 size[1] = cap->fmt.width * cap->fmt.height >> 2;
- 1049 size[2] = cap->fmt.width * cap->fmt.height >> 2;
- 1050 size[3] = 16; /* Padding buffer */
- 1051 break;
- 1052
- 1053 case V4L2_PIX_FMT_JPEG:
- 1054 size[0] = fimc_camera_get_jpeg_memsize(ctrl);
- 1055 default:
- 1056 break;
- 1057 }
- 1058
- 1059 ret = fimc_alloc_buffers(ctrl, size, align);
- 1060 if (ret) {
- 1061 fimc_err("%s: no memory for "
- 1062 "capture buffer\n", __func__);
- 1063 mutex_unlock(&ctrl->v4l2_lock);
- 1064 return -ENOMEM;
- 1065 }
- 1066
- 1067 for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {
- 1068 memcpy(&cap->bufs[i], \
- 1069 &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));
- 1070 }
- 1071
- 1072 mutex_unlock(&ctrl->v4l2_lock);
- 1073
- 1074 return 0;
- 1075 }
950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)
951 {
952 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
953 struct fimc_capinfo *cap = ctrl->cap;
954 int ret = 0, i;
955 int size[4] = { 0, 0, 0, 0};
956 int align = SZ_4K;
957
958 if (b->memory != V4L2_MEMORY_MMAP) {
959 fimc_err("%s: invalid memory type\n", __func__);
960 return -EINVAL;
961 }
962
963 if (!cap) {
964 fimc_err("%s: no capture device info\n", __func__);
965 return -ENODEV;
966 }
967
968 if (!ctrl->cam || !ctrl->cam->sd) {
969 fimc_err("%s: No capture device.\n", __func__);
970 return -ENODEV;
971 }
972
973 mutex_lock(&ctrl->v4l2_lock);
974
975 if (b->count < 1 || b->count > FIMC_CAPBUFS)
976 return -EINVAL;
977
978 /* It causes flickering as buf_0 and buf_3 refer to same hardware
979 * address.
980 */
981 if (b->count == 3)
982 b->count = 4;
983
984 cap->nr_bufs = b->count;
985
986 fimc_dbg("%s: requested %d buffers\n", __func__, b->count);
987
988 INIT_LIST_HEAD(&cap->inq);
989
990 fimc_free_buffers(ctrl);
991
992 switch (cap->fmt.pixelformat) {
993 case V4L2_PIX_FMT_RGB32: /* fall through */
994 case V4L2_PIX_FMT_RGB565: /* fall through */
995 case V4L2_PIX_FMT_YUYV: /* fall through */
996 case V4L2_PIX_FMT_UYVY: /* fall through */
997 case V4L2_PIX_FMT_VYUY: /* fall through */
998 case V4L2_PIX_FMT_YVYU: /* fall through */
999 case V4L2_PIX_FMT_YUV422P: /* fall through */
1000 size[0] = cap->fmt.sizeimage;
1001 break;
1002
1003 case V4L2_PIX_FMT_NV16: /* fall through */
1004 case V4L2_PIX_FMT_NV61:
1005 size[0] = cap->fmt.width * cap->fmt.height;
1006 size[1] = cap->fmt.width * cap->fmt.height;
1007 size[3] = 16; /* Padding buffer */
1008 break;
1009 case V4L2_PIX_FMT_NV12:
1010 size[0] = cap->fmt.width * cap->fmt.height;
1011 size[1] = cap->fmt.width * cap->fmt.height/2;
1012 break;
1013 case V4L2_PIX_FMT_NV21:
1014 size[0] = cap->fmt.width * cap->fmt.height;
1015 size[1] = cap->fmt.width * cap->fmt.height/2;
1016 size[3] = 16; /* Padding buffer */
1017 break;
1018 case V4L2_PIX_FMT_NV12T:
1019 /* Tiled frame size calculations as per 4x2 tiles
1020 * - Width: Has to be aligned to 2 times the tile width
1021 * - Height: Has to be aligned to the tile height
1022 * - Alignment: Has to be aligned to the size of the
1023 * macrotile (size of 4 tiles)
1024 *
1025 * NOTE: In case of rotation, we need modified calculation as
1026 * width and height are aligned to different values.
1027 */
1028 if (cap->rotate == 90 || cap->rotate == 270) {
1029 size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *
1030 ALIGN(cap->fmt.width, 32),
1031 SZ_8K);
1032 size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *
1033 ALIGN(cap->fmt.width/2, 32),
1034 SZ_8K);
1035 } else {
1036 size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *
1037 ALIGN(cap->fmt.height, 32),
1038 SZ_8K);
1039 size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *
1040 ALIGN(cap->fmt.height/2, 32),
1041 SZ_8K);
1042 }
1043 align = SZ_8K;
1044 break;
1045
1046 case V4L2_PIX_FMT_YUV420:
1047 size[0] = cap->fmt.width * cap->fmt.height;
1048 size[1] = cap->fmt.width * cap->fmt.height >> 2;
1049 size[2] = cap->fmt.width * cap->fmt.height >> 2;
1050 size[3] = 16; /* Padding buffer */
1051 break;
1052
1053 case V4L2_PIX_FMT_JPEG:
1054 size[0] = fimc_camera_get_jpeg_memsize(ctrl);
1055 default:
1056 break;
1057 }
1058
1059 ret = fimc_alloc_buffers(ctrl, size, align);
1060 if (ret) {
1061 fimc_err("%s: no memory for "
1062 "capture buffer\n", __func__);
1063 mutex_unlock(&ctrl->v4l2_lock);
1064 return -ENOMEM;
1065 }
1066
1067 for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {
1068 memcpy(&cap->bufs[i], \
1069 &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));
1070 }
1071
1072 mutex_unlock(&ctrl->v4l2_lock);
1073
1074 return 0;
1075 }
975 ~978 FIMC_CAPBUFS是fimc支持的最大queue buffers數量,可以根據最大capture buffers數目,以及幀buffer所需空間大小(所有子buffers空間總和),加上alignment所帶來的空間損失,大致算出fimc capture設備需要預留的物理空間
992 ~ 1057 根據pixelformat和width/height計算每個幀子buffers的尺寸。
- 1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)
- 1078 {
- 1079 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 1080
- 1081 if (!ctrl->cap || !ctrl->cap->bufs) {
- 1082 fimc_err("%s: no capture device info\n", __func__);
- 1083 return -ENODEV;
- 1084 }
- 1085
- 1086 if (ctrl->status != FIMC_STREAMOFF) {
- 1087 fimc_err("fimc is running\n");
- 1088 return -EBUSY;
- 1089 }
- 1090
- 1091 mutex_lock(&ctrl->v4l2_lock);
- 1092
- 1093 b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]
- 1094 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]
- 1095 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];
- 1096
- 1097 b->m.offset = b->index * PAGE_SIZE;
- 1098
- 1099 ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;
- 1100
- 1101 mutex_unlock(&ctrl->v4l2_lock);
- 1102
- 1103 fimc_dbg("%s: %d bytes at index: %d\n", __func__, b->length, b->index);
- 1104
- 1105 return 0;
- 1106 }
1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)
1078 {
1079 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1080
1081 if (!ctrl->cap || !ctrl->cap->bufs) {
1082 fimc_err("%s: no capture device info\n", __func__);
1083 return -ENODEV;
1084 }
1085
1086 if (ctrl->status != FIMC_STREAMOFF) {
1087 fimc_err("fimc is running\n");
1088 return -EBUSY;
1089 }
1090
1091 mutex_lock(&ctrl->v4l2_lock);
1092
1093 b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]
1094 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]
1095 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];
1096
1097 b->m.offset = b->index * PAGE_SIZE;
1098
1099 ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;
1100
1101 mutex_unlock(&ctrl->v4l2_lock);
1102
1103 fimc_dbg("%s: %d bytes at index: %d\n", __func__, b->length, b->index);
1104
1105 return 0;
1106 }
1093 ~ 1095 buffer的length由三個分量buffer總長度決定
1097 這個需要結合fimc_mmap_cap來看,b->m.offset可以用來表示buffer的索引值
- 1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)
- 1256 {
- 1257 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 1258 struct fimc_capinfo *cap = ctrl->cap;
- 1259
- 1260 fimc_dbg("%s\n", __func__);
- 1261
- 1262 if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {
- 1263 fimc_err("%s: No capture device.\n", __func__);
- 1264 return -ENODEV;
- 1265 }
- 1266
- 1267 mutex_lock(&ctrl->v4l2_lock);
- 1268
- 1269 /* crop limitations */
- 1270 cap->cropcap.bounds.left = 0;
- 1271 cap->cropcap.bounds.top = 0;
- 1272 cap->cropcap.bounds.width = ctrl->cam->width;
- 1273 cap->cropcap.bounds.height = ctrl->cam->height;
- 1274
- 1275 /* crop default values */
- 1276 cap->cropcap.defrect.left = 0;
- 1277 cap->cropcap.defrect.top = 0;
- 1278 cap->cropcap.defrect.width = ctrl->cam->width;
- 1279 cap->cropcap.defrect.height = ctrl->cam->height;
- 1280
- 1281 a->bounds = cap->cropcap.bounds;
- 1282 a->defrect = cap->cropcap.defrect;
- 1283
- 1284 mutex_unlock(&ctrl->v4l2_lock);
- 1285
- 1286 return 0;
- 1287 }
1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)
1256 {
1257 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1258 struct fimc_capinfo *cap = ctrl->cap;
1259
1260 fimc_dbg("%s\n", __func__);
1261
1262 if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {
1263 fimc_err("%s: No capture device.\n", __func__);
1264 return -ENODEV;
1265 }
1266
1267 mutex_lock(&ctrl->v4l2_lock);
1268
1269 /* crop limitations */
1270 cap->cropcap.bounds.left = 0;
1271 cap->cropcap.bounds.top = 0;
1272 cap->cropcap.bounds.width = ctrl->cam->width;
1273 cap->cropcap.bounds.height = ctrl->cam->height;
1274
1275 /* crop default values */
1276 cap->cropcap.defrect.left = 0;
1277 cap->cropcap.defrect.top = 0;
1278 cap->cropcap.defrect.width = ctrl->cam->width;
1279 cap->cropcap.defrect.height = ctrl->cam->height;
1280
1281 a->bounds = cap->cropcap.bounds;
1282 a->defrect = cap->cropcap.defrect;
1283
1284 mutex_unlock(&ctrl->v4l2_lock);
1285
1286 return 0;
1287 }
fimc_cropcap_capture:fimc的VIDIOC_CROPCAP的實現
cropcap.bounds 是capture window 最大邊界,capture.defrect是capture window的默認方框
cropcap.defrect一定不會超出cropcap.bounds的範圍,他們的關係如下圖
cropcap.pixelaspect =垂直像素數 / 水平像素數
- 1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)
- 1290 {
- 1291 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 1292
- 1293 fimc_dbg("%s\n", __func__);
- 1294
- 1295 if (!ctrl->cap) {
- 1296 fimc_err("%s: No capture device.\n", __func__);
- 1297 return -ENODEV;
- 1298 }
- 1299
- 1300 mutex_lock(&ctrl->v4l2_lock);
- 1301 a->c = ctrl->cap->crop;
- 1302 mutex_unlock(&ctrl->v4l2_lock);
- 1303
- 1304 return 0;
- 1305 }
- 1306
1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)
1290 {
1291 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1292
1293 fimc_dbg("%s\n", __func__);
1294
1295 if (!ctrl->cap) {
1296 fimc_err("%s: No capture device.\n", __func__);
1297 return -ENODEV;
1298 }
1299
1300 mutex_lock(&ctrl->v4l2_lock);
1301 a->c = ctrl->cap->crop;
1302 mutex_unlock(&ctrl->v4l2_lock);
1303
1304 return 0;
1305 }
1306
fimc_g_crop_capture 是capture設備的VIDIOC_G_CROP實現,返回當前的crop
- <PRE class=cpp name="code">1307 static int fimc_capture_crop_size_check(struct fimc_control *ctrl)
- 1308 {
- 1309 struct fimc_capinfo *cap = ctrl->cap;
- 1310 int win_hor_offset = 0, win_hor_offset2 = 0;
- 1311 int win_ver_offset = 0, win_ver_offset2 = 0;
- 1312 int crop_width = 0, crop_height = 0;
- 1313
- 1314 /* check win_hor_offset, win_hor_offset2 */
- 1315 win_hor_offset = ctrl->cam->window.left;
- 1316 win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left -
- 1317 ctrl->cam->window.width;
- 1318
- 1319 win_ver_offset = ctrl->cam->window.top;
- 1320 win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top -
- 1321 ctrl->cam->window.height;
- 1322
- 1323 if (win_hor_offset < 0 || win_hor_offset2 < 0) {
- 1324 fimc_err("%s: Offset (left-side(%d) or right-side(%d) "
- 1325 "is negative.\n", __func__, \
- 1326 win_hor_offset, win_hor_offset2);
- 1327 return -1;
- 1328 }
- 1329
- 1330 if (win_ver_offset < 0 || win_ver_offset2 < 0) {
- 1331 fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) "
- 1332 "is negative.\n", __func__, \
- 1333 win_ver_offset, win_ver_offset2);
- 1334 return -1;
- 1335 }
- 1336
- 1337 if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) {
- 1338 fimc_err("%s: win_hor_offset must be multiple of 2\n", \
- 1339 __func__);
- 1340 return -1;
- 1341 }
- 1342
- 1343 /* check crop_width, crop_height */
- 1344 crop_width = ctrl->cam->window.width;
- 1345 crop_height = ctrl->cam->window.height;
- 1346
- 1347 if (crop_width % 16) {
- 1348 fimc_err("%s: crop_width must be multiple of 16\n", __func__);
- 1349 return -1;
- 1350 }
- 1351
- 1352 switch (cap->fmt.pixelformat) {
- 1353 case V4L2_PIX_FMT_YUV420: /* fall through */
- 1354 case V4L2_PIX_FMT_NV12: /* fall through */
- 1355 case V4L2_PIX_FMT_NV21: /* fall through */
- 1356 case V4L2_PIX_FMT_NV12T: /* fall through */
- 1357 if ((crop_height % 2) || (crop_height < 8)) {
- 1358 fimc_err("%s: crop_height error!\n", __func__);
- 1359 return -1;
- 1360 }
- 1361 break;
- 1362 default:
- 1363 break;
- 1364 }
- 1365
- 1366 return 0;
- 1367 }
- </PRE><P></P>
- <PRE></PRE>
- <BR>
- cam->cam->window是crop設置後的取景框,這個函數就是檢測這個取景框是否符合規範
- <P></P>
- <P><BR>
- </P>
- <P><PRE class=cpp name="code">1377 static void fimc_capture_update_crop_window(struct fimc_control *ctrl)
- 1378 {
- 1379 unsigned int zoom_hor = 0;
- 1380 unsigned int zoom_ver = 0;
- 1381 unsigned int multiplier = 1024;
- 1382
- 1383 if (!ctrl->cam->width || !ctrl->cam->height)
- 1384 return;
- 1385
- 1386 zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width;
- 1387 zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height;
- 1388
- 1389 if (!zoom_hor || !zoom_ver)
- 1390 return;
- 1391
- 1392 /* Width */
- 1393 ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor;
- 1394 if (ctrl->cam->window.width > ctrl->cam->width)
- 1395 ctrl->cam->window.width = ctrl->cam->width;
- 1396 if (ctrl->cam->window.width % 16)
- 1397 ctrl->cam->window.width =
- 1398 (ctrl->cam->window.width + 0xF) & ~0xF;
- 1399
- 1400 /* Left offset */
- 1401 ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor;
- 1402 if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width)
- 1403 ctrl->cam->window.left =
- 1404 (ctrl->cam->width - ctrl->cam->window.width)/2;
- 1405 if (ctrl->cam->window.left % 2)
- 1406 ctrl->cam->window.left--;
- 1407
- 1408 /* Height */
- 1409 ctrl->cam->window.height =
- 1410 (ctrl->cap->crop.height * multiplier) / zoom_ver;
- 1411 if (ctrl->cam->window.top > ctrl->cam->height)
- 1412 ctrl->cam->window.height = ctrl->cam->height;
- 1413 if (ctrl->cam->window.height % 2)
- 1414 ctrl->cam->window.height--;
- 1415
- 1416 /* Top offset */
- 1417 ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver;
- 1418 if (ctrl->cam->window.height + ctrl->cam->window.top >
- 1419 ctrl->cam->height)
- 1420 ctrl->cam->window.top =
- 1421 (ctrl->cam->height - ctrl->cam->window.height)/2;
- 1422 if (ctrl->cam->window.top % 2)
- 1423 ctrl->cam->window.top--;
- 1424
- 1425 fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d)\n", \
- 1426 ctrl->cam->width, ctrl->cam->height, \
- 1427 ctrl->cap->crop.left, ctrl->cap->crop.top, \
- 1428 ctrl->cap->crop.width, ctrl->cap->crop.height, \
- 1429 ctrl->cam->window.left, ctrl->cam->window.top, \
- 1430 ctrl->cam->window.width, ctrl->cam->window.height);
- 1431
- 1432 }
- </PRE><BR>
- 根據s_crop設置的curr_crop設置capture 的取景框<BR>
- <P></P>
- <P><BR>
- </P>
- <P><PRE class=cpp name="code">1434 int fimc_s_crop_capture(void *fh, struct v4l2_crop *a)
- 1435 {
- 1436 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- 1437 int ret = 0;
- 1438
- 1439 fimc_dbg("%s\n", __func__);
- 1440
- 1441 if (!ctrl->cap) {
- 1442 fimc_err("%s: No capture device.\n", __func__);
- 1443 return -ENODEV;
- 1444 }
- 1445
- 1446 mutex_lock(&ctrl->v4l2_lock);
- 1447 ctrl->cap->crop = a->c;
- 1448
- 1449 fimc_capture_update_crop_window(ctrl);
- 1450
- 1451 ret = fimc_capture_crop_size_check(ctrl);
- 1452 if (ret < 0) {
- 1453 mutex_unlock(&ctrl->v4l2_lock);
- 1454 fimc_err("%s: Invalid crop parameters.\n", __func__);
- 1455 return -EINVAL;
- 1456 }
- 1457
- 1458 if (ctrl->status == FIMC_STREAMON &&
- 1459 ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) {
- 1460 fimc_hwset_shadow_disable(ctrl);
- 1461 fimc_hwset_camera_offset(ctrl);
- 1462 fimc_capture_scaler_info(ctrl);
- 1463 fimc_hwset_prescaler(ctrl, &ctrl->sc);
- 1464 fimc_hwset_scaler(ctrl, &ctrl->sc);
- 1465 fimc_hwset_shadow_enable(ctrl);
- 1466 }
- 1467
- 1468 mutex_unlock(&ctrl->v4l2_lock);
- 1469
- 1470 return 0;
- 1471 }
- </PRE>fimc_s_crop_capture是capture設備的VIDIOC_S_CROP ioctl實現<P></P>
- <P>1449 用@a更新capture window</P>
- <P>1451 檢測新生成的capture window參數合法性</P>
- <P>1458 ~ 1466 FIMC支持streamon正在進行時,修改capture取景框<BR