S5PV210開發板 攝像頭ov3640 fimc驅動分析 :fimc_capture.c 分析

fimc_capture.c在FIMC系統中的位置,網上偷來的一幅圖片



  1. 43 static const struct v4l2_fmtdesc capture_fmts[] = {
  2. 44 {
  3. 45 .index = 0,
  4. 46 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  5. 47 .flags = FORMAT_FLAGS_PACKED,
  6. 48 .description = "RGB-5-6-5",
  7. 49 .pixelformat = V4L2_PIX_FMT_RGB565,
  8. 50 }, {
  9. 51 .index = 1,
  10. 52 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  11. 53 .flags = FORMAT_FLAGS_PACKED,
  12. 54 .description = "RGB-8-8-8, unpacked 24 bpp",
  13. 55 .pixelformat = V4L2_PIX_FMT_RGB32,
  14. 56 }, {
  15. 57 .index = 2,
  16. 58 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  17. 59 .flags = FORMAT_FLAGS_PACKED,
  18. 60 .description = "YUV 4:2:2 packed, YCbYCr",
  19. 61 .pixelformat = V4L2_PIX_FMT_YUYV,
  20. 62 }, {
  21. 63 .index = 3,
  22. 64 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  23. 65 .flags = FORMAT_FLAGS_PACKED,
  24. 66 .description = "YUV 4:2:2 packed, CbYCrY",
  25. 67 .pixelformat = V4L2_PIX_FMT_UYVY,
  26. 68 }, {
  27. 69 .index = 4,
  28. 70 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  29. 71 .flags = FORMAT_FLAGS_PACKED,
  30. 72 .description = "YUV 4:2:2 packed, CrYCbY",
  31. 73 .pixelformat = V4L2_PIX_FMT_VYUY,
  32. 74 }, {
  33. 75 .index = 5,
  34. 76 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  35. 77 .flags = FORMAT_FLAGS_PACKED,
  36. 78 .description = "YUV 4:2:2 packed, YCrYCb",
  37. 79 .pixelformat = V4L2_PIX_FMT_YVYU,
  38. 80 }, {
  39. 81 .index = 6,
  40. 82 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  41. 83 .flags = FORMAT_FLAGS_PLANAR,
  42. 84 .description = "YUV 4:2:2 planar, Y/Cb/Cr",
  43. 85 .pixelformat = V4L2_PIX_FMT_YUV422P,
  44. 86 }, {
  45. 87 .index = 7,
  46. 88 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  47. 89 .flags = FORMAT_FLAGS_PLANAR,
  48. 90 .description = "YUV 4:2:0 planar, Y/CbCr",
  49. 91 .pixelformat = V4L2_PIX_FMT_NV12,
  50. 92 }, {
  51. 93 .index = 8,
  52. 94 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  53. 95 .flags = FORMAT_FLAGS_PLANAR,
  54. 96 .description = "YUV 4:2:0 planar, Y/CbCr, Tiled",
  55. 97 .pixelformat = V4L2_PIX_FMT_NV12T,
  56. 98 }, {
  57. 99 .index = 9,
  58. 100 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  59. 101 .flags = FORMAT_FLAGS_PLANAR,
  60. 102 .description = "YUV 4:2:0 planar, Y/CrCb",
  61. 103 .pixelformat = V4L2_PIX_FMT_NV21,
  62. 104 }, {
  63. 105 .index = 10,
  64. 106 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  65. 107 .flags = FORMAT_FLAGS_PLANAR,
  66. 108 .description = "YUV 4:2:2 planar, Y/CbCr",
  67. 109 .pixelformat = V4L2_PIX_FMT_NV16,
  68. 110 }, {
  69. 111 .index = 11,
  70. 112 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  71. 113 .flags = FORMAT_FLAGS_PLANAR,
  72. 114 .description = "YUV 4:2:2 planar, Y/CrCb",
  73. 115 .pixelformat = V4L2_PIX_FMT_NV61,
  74. 116 }, {
  75. 117 .index = 12,
  76. 118 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  77. 119 .flags = FORMAT_FLAGS_PLANAR,
  78. 120 .description = "YUV 4:2:0 planar, Y/Cb/Cr",
  79. 121 .pixelformat = V4L2_PIX_FMT_YUV420,
  80. 122 }, {
  81. 123 .index = 13,
  82. 124 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  83. 125 .flags = FORMAT_FLAGS_ENCODED,
  84. 126 .description = "Encoded JPEG bitstream",
  85. 127 .pixelformat = V4L2_PIX_FMT_JPEG,
  86. 128 },
  87. 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格式


  1. static int fimc_camera_init(struct fimc_control *ctrl)
  2. 202 {
  3. 203 int ret;
  4. 204
  5. 205 fimc_dbg("%s\n", __func__);
  6. 206
  7. 207 /* do nothing if already initialized */
  8. 208 if (ctrl->cam->initialized)
  9. 209 return 0;
  10. 210
  11. 211 /* enable camera power if needed */
  12. 212 if (ctrl->cam->cam_power)
  13. 213 ctrl->cam->cam_power(1);
  14. 214
  15. 215 /* subdev call for init */
  16. 216 ret = subdev_call(ctrl, core, init, 0);
  17. 217 if (ret == -ENOIOCTLCMD) {
  18. 218 fimc_err("%s: init subdev api not supported\n",
  19. 219 __func__);
  20. 220 return ret;
  21. 221 }
  22. 222
  23. 223 if (ctrl->cam->type == CAM_TYPE_MIPI) {
  24. 224 /* subdev call for sleep/wakeup:
  25. 225 * no error although no s_stream api support
  26. 226 */
  27. 227 u32 pixelformat;
  28. 228 if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)
  29. 229 pixelformat = V4L2_PIX_FMT_JPEG;
  30. 230 else
  31. 231 pixelformat = ctrl->cam->pixelformat;
  32. 232
  33. 233 subdev_call(ctrl, video, s_stream, 0);
  34. 234 s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle, \
  35. 235 ctrl->cam->mipi_align, ctrl->cam->width, \
  36. 236 ctrl->cam->height, pixelformat);
  37. 237 subdev_call(ctrl, video, s_stream, 1);
  38. 238 }
  39. 239
  40. 240 ctrl->cam->initialized = 1;
  41. 241
  42. 242 return 0;
  43. 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寄存器的,因此這個上電位置是有問題的。


  1. 368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)
  2. 369 {
  3. 370 struct fimc_capinfo *cap = ctrl->cap;
  4. 371
  5. 372 struct fimc_buf_set *buf;
  6. 373
  7. 374 if (i >= cap->nr_bufs)
  8. 375 return -EINVAL;
  9. 376
  10. 377 list_for_each_entry(buf, &cap->inq, list) {
  11. 378 if (buf->id == i) {
  12. 379 fimc_dbg("%s: buffer %d already in inqueue.\n", \
  13. 380 __func__, i);
  14. 381 return -EINVAL;
  15. 382 }
  16. 383 }
  17. 384
  18. 385 list_add_tail(&cap->bufs[i].list, &cap->inq);
  19. 386
  20. 387 return 0;
  21. 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


  1. 390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)
  2. 391 {
  3. 392 struct fimc_capinfo *cap = ctrl->cap;
  4. 393 struct fimc_buf_set *buf;
  5. 394
  6. 395 unsigned int mask = 0x2;
  7. 396
  8. 397 /* PINGPONG_2ADDR_MODE Only */
  9. 398 /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */
  10. 399
  11. 400 int pair_buf_index = (i^mask);
  12. 401
  13. 402 /* FIMC have 4 h/w registers */
  14. 403 if (i < 0 || i >= FIMC_PHYBUFS) {
  15. 404 fimc_err("%s: invalid queue index : %d\n", __func__, i);
  16. 405 return -ENOENT;
  17. 406 }
  18. 407
  19. 408 if (list_empty(&cap->inq))
  20. 409 return -ENOENT;
  21. 410
  22. 411 buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);
  23. 412
  24. 413 /* pair index buffer should be allocated first */
  25. 414 cap->outq[pair_buf_index] = buf->id;
  26. 415 fimc_hwset_output_address(ctrl, buf, pair_buf_index);
  27. 416
  28. 417 cap->outq[i] = buf->id;
  29. 418 fimc_hwset_output_address(ctrl, buf, i);
  30. 419
  31. 420 if (cap->nr_bufs != 1)
  32. 421 list_del(&buf->list);
  33. 422
  34. 423 return 0;
  35. 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


  1. 516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
  2. 517 {
  3. 518 struct fimc_global *fimc = get_fimc_dev();
  4. 519 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  5. 520
  6. 521 fimc_dbg("%s: index %d\n", __func__, inp->index);
  7. 522
  8. 523 if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {
  9. 524 fimc_err("%s: invalid input index, received = %d\n", \
  10. 525 __func__, inp->index);
  11. 526 return -EINVAL;
  12. 527 }
  13. 528
  14. 529 if (!fimc->camera_isvalid[inp->index])
  15. 530 return -EINVAL;
  16. 531
  17. 532 strcpy(inp->name, fimc->camera[inp->index].info->type);
  18. 533 inp->type = V4L2_INPUT_TYPE_CAMERA;
  19. 534
  20. 535 return 0;
  21. 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驅動的通用性。


  1. 538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)
  2. 539 {
  3. 540 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  4. 541 struct fimc_global *fimc = get_fimc_dev();
  5. 542
  6. 543 /* In case of isueing g_input before s_input */
  7. 544 if (!ctrl->cam) {
  8. 545 fimc_err("no camera device selected yet!" \
  9. 546 "do VIDIOC_S_INPUT first\n");
  10. 547 return -ENODEV;
  11. 548 }
  12. 549
  13. 550 *i = (unsigned int) fimc->active_camera;
  14. 551
  15. 552 fimc_dbg("%s: index %d\n", __func__, *i);
  16. 553
  17. 554 return 0;
  18. 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的一個特性。


  1. 637 int fimc_s_input(struct file *file, void *fh, unsigned int i)
  2. 638 {
  3. 639 struct fimc_global *fimc = get_fimc_dev();
  4. 640 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  5. 641 int ret = 0;
  6. 642
  7. 643 fimc_dbg("%s: index %d\n", __func__, i);
  8. 644
  9. 645 if (i < 0 || i >= FIMC_MAXCAMS) {
  10. 646 fimc_err("%s: invalid input index\n", __func__);
  11. 647 return -EINVAL;
  12. 648 }
  13. 649
  14. 650 if (!fimc->camera_isvalid[i])
  15. 651 return -EINVAL;
  16. 652
  17. 653 if (fimc->camera[i].sd && ctrl->id != 2) {
  18. 654 fimc_err("%s: Camera already in use.\n", __func__);
  19. 655 return -EBUSY;
  20. 656 }
  21. 657
  22. 658 mutex_lock(&ctrl->v4l2_lock);
  23. 659 /* If ctrl->cam is not NULL, there is one subdev already registered.
  24. 660 * We need to unregister that subdev first.
  25. 661 */
  26. 662 if (i != fimc->active_camera) {
  27. 663 fimc_release_subdev(ctrl);
  28. 664 ctrl->cam = &fimc->camera[i];
  29. 665 ret = fimc_configure_subdev(ctrl);
  30. 666 if (ret < 0) {
  31. 667 mutex_unlock(&ctrl->v4l2_lock);
  32. 668 fimc_err("%s: Could not register camera sensor "
  33. 669 "with V4L2.\n", __func__);
  34. 670 return -ENODEV;
  35. 671 }
  36. 672 fimc->active_camera = i;
  37. 673 }
  38. 674
  39. 675 if (ctrl->id == 2) {
  40. 676 if (i == fimc->active_camera) {
  41. 677 ctrl->cam = &fimc->camera[i];
  42. 678 } else {
  43. 679 mutex_unlock(&ctrl->v4l2_lock);
  44. 680 return -EINVAL;
  45. 681 }
  46. 682 }
  47. 683
  48. 684 mutex_unlock(&ctrl->v4l2_lock);
  49. 685
  50. 686 return 0;
  51. 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的接口


  1. 897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)
  2. 898 {
  3. 899 struct fimc_capinfo *cap = ctrl->cap;
  4. 900 int i, plane;
  5. 901
  6. 902 for (i = 0; i < cap->nr_bufs; i++) {
  7. 903 for (plane = 0; plane < 4; plane++) {
  8. 904 cap->bufs[i].length[plane] = size[plane];
  9. 905 if (!cap->bufs[i].length[plane])
  10. 906 continue;
  11. 907
  12. 908 fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);
  13. 909
  14. 910 if (!cap->bufs[i].base[plane])
  15. 911 goto err_alloc;
  16. 912 }
  17. 913
  18. 914 cap->bufs[i].state = VIDEOBUF_PREPARED;
  19. 915 cap->bufs[i].id = i;
  20. 916 }
  21. 917
  22. 918 return 0;
  23. 919
  24. 920 err_alloc:
  25. 921 for (i = 0; i < cap->nr_bufs; i++) {
  26. 922 if (cap->bufs[i].base[plane])
  27. 923 fimc_dma_free(ctrl, &cap->bufs[i], plane);
  28. 924
  29. 925 memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
  30. 926 }
  31. 927
  32. 928 return -ENOMEM;
  33. 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數量。


  1. 950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)
  2. 951 {
  3. 952 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  4. 953 struct fimc_capinfo *cap = ctrl->cap;
  5. 954 int ret = 0, i;
  6. 955 int size[4] = { 0, 0, 0, 0};
  7. 956 int align = SZ_4K;
  8. 957
  9. 958 if (b->memory != V4L2_MEMORY_MMAP) {
  10. 959 fimc_err("%s: invalid memory type\n", __func__);
  11. 960 return -EINVAL;
  12. 961 }
  13. 962
  14. 963 if (!cap) {
  15. 964 fimc_err("%s: no capture device info\n", __func__);
  16. 965 return -ENODEV;
  17. 966 }
  18. 967
  19. 968 if (!ctrl->cam || !ctrl->cam->sd) {
  20. 969 fimc_err("%s: No capture device.\n", __func__);
  21. 970 return -ENODEV;
  22. 971 }
  23. 972
  24. 973 mutex_lock(&ctrl->v4l2_lock);
  25. 974
  26. 975 if (b->count < 1 || b->count > FIMC_CAPBUFS)
  27. 976 return -EINVAL;
  28. 977
  29. 978 /* It causes flickering as buf_0 and buf_3 refer to same hardware
  30. 979 * address.
  31. 980 */
  32. 981 if (b->count == 3)
  33. 982 b->count = 4;
  34. 983
  35. 984 cap->nr_bufs = b->count;
  36. 985
  37. 986 fimc_dbg("%s: requested %d buffers\n", __func__, b->count);
  38. 987
  39. 988 INIT_LIST_HEAD(&cap->inq);
  40. 989
  41. 990 fimc_free_buffers(ctrl);
  42. 991
  43. 992 switch (cap->fmt.pixelformat) {
  44. 993 case V4L2_PIX_FMT_RGB32: /* fall through */
  45. 994 case V4L2_PIX_FMT_RGB565: /* fall through */
  46. 995 case V4L2_PIX_FMT_YUYV: /* fall through */
  47. 996 case V4L2_PIX_FMT_UYVY: /* fall through */
  48. 997 case V4L2_PIX_FMT_VYUY: /* fall through */
  49. 998 case V4L2_PIX_FMT_YVYU: /* fall through */
  50. 999 case V4L2_PIX_FMT_YUV422P: /* fall through */
  51. 1000 size[0] = cap->fmt.sizeimage;
  52. 1001 break;
  53. 1002
  54. 1003 case V4L2_PIX_FMT_NV16: /* fall through */
  55. 1004 case V4L2_PIX_FMT_NV61:
  56. 1005 size[0] = cap->fmt.width * cap->fmt.height;
  57. 1006 size[1] = cap->fmt.width * cap->fmt.height;
  58. 1007 size[3] = 16; /* Padding buffer */
  59. 1008 break;
  60. 1009 case V4L2_PIX_FMT_NV12:
  61. 1010 size[0] = cap->fmt.width * cap->fmt.height;
  62. 1011 size[1] = cap->fmt.width * cap->fmt.height/2;
  63. 1012 break;
  64. 1013 case V4L2_PIX_FMT_NV21:
  65. 1014 size[0] = cap->fmt.width * cap->fmt.height;
  66. 1015 size[1] = cap->fmt.width * cap->fmt.height/2;
  67. 1016 size[3] = 16; /* Padding buffer */
  68. 1017 break;
  69. 1018 case V4L2_PIX_FMT_NV12T:
  70. 1019 /* Tiled frame size calculations as per 4x2 tiles
  71. 1020 * - Width: Has to be aligned to 2 times the tile width
  72. 1021 * - Height: Has to be aligned to the tile height
  73. 1022 * - Alignment: Has to be aligned to the size of the
  74. 1023 * macrotile (size of 4 tiles)
  75. 1024 *
  76. 1025 * NOTE: In case of rotation, we need modified calculation as
  77. 1026 * width and height are aligned to different values.
  78. 1027 */
  79. 1028 if (cap->rotate == 90 || cap->rotate == 270) {
  80. 1029 size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *
  81. 1030 ALIGN(cap->fmt.width, 32),
  82. 1031 SZ_8K);
  83. 1032 size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *
  84. 1033 ALIGN(cap->fmt.width/2, 32),
  85. 1034 SZ_8K);
  86. 1035 } else {
  87. 1036 size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *
  88. 1037 ALIGN(cap->fmt.height, 32),
  89. 1038 SZ_8K);
  90. 1039 size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *
  91. 1040 ALIGN(cap->fmt.height/2, 32),
  92. 1041 SZ_8K);
  93. 1042 }
  94. 1043 align = SZ_8K;
  95. 1044 break;
  96. 1045
  97. 1046 case V4L2_PIX_FMT_YUV420:
  98. 1047 size[0] = cap->fmt.width * cap->fmt.height;
  99. 1048 size[1] = cap->fmt.width * cap->fmt.height >> 2;
  100. 1049 size[2] = cap->fmt.width * cap->fmt.height >> 2;
  101. 1050 size[3] = 16; /* Padding buffer */
  102. 1051 break;
  103. 1052
  104. 1053 case V4L2_PIX_FMT_JPEG:
  105. 1054 size[0] = fimc_camera_get_jpeg_memsize(ctrl);
  106. 1055 default:
  107. 1056 break;
  108. 1057 }
  109. 1058
  110. 1059 ret = fimc_alloc_buffers(ctrl, size, align);
  111. 1060 if (ret) {
  112. 1061 fimc_err("%s: no memory for "
  113. 1062 "capture buffer\n", __func__);
  114. 1063 mutex_unlock(&ctrl->v4l2_lock);
  115. 1064 return -ENOMEM;
  116. 1065 }
  117. 1066
  118. 1067 for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {
  119. 1068 memcpy(&cap->bufs[i], \
  120. 1069 &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));
  121. 1070 }
  122. 1071
  123. 1072 mutex_unlock(&ctrl->v4l2_lock);
  124. 1073
  125. 1074 return 0;
  126. 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的尺寸。


  1. 1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)
  2. 1078 {
  3. 1079 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  4. 1080
  5. 1081 if (!ctrl->cap || !ctrl->cap->bufs) {
  6. 1082 fimc_err("%s: no capture device info\n", __func__);
  7. 1083 return -ENODEV;
  8. 1084 }
  9. 1085
  10. 1086 if (ctrl->status != FIMC_STREAMOFF) {
  11. 1087 fimc_err("fimc is running\n");
  12. 1088 return -EBUSY;
  13. 1089 }
  14. 1090
  15. 1091 mutex_lock(&ctrl->v4l2_lock);
  16. 1092
  17. 1093 b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]
  18. 1094 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]
  19. 1095 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];
  20. 1096
  21. 1097 b->m.offset = b->index * PAGE_SIZE;
  22. 1098
  23. 1099 ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;
  24. 1100
  25. 1101 mutex_unlock(&ctrl->v4l2_lock);
  26. 1102
  27. 1103 fimc_dbg("%s: %d bytes at index: %d\n", __func__, b->length, b->index);
  28. 1104
  29. 1105 return 0;
  30. 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的索引值


  1. 1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)
  2. 1256 {
  3. 1257 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  4. 1258 struct fimc_capinfo *cap = ctrl->cap;
  5. 1259
  6. 1260 fimc_dbg("%s\n", __func__);
  7. 1261
  8. 1262 if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {
  9. 1263 fimc_err("%s: No capture device.\n", __func__);
  10. 1264 return -ENODEV;
  11. 1265 }
  12. 1266
  13. 1267 mutex_lock(&ctrl->v4l2_lock);
  14. 1268
  15. 1269 /* crop limitations */
  16. 1270 cap->cropcap.bounds.left = 0;
  17. 1271 cap->cropcap.bounds.top = 0;
  18. 1272 cap->cropcap.bounds.width = ctrl->cam->width;
  19. 1273 cap->cropcap.bounds.height = ctrl->cam->height;
  20. 1274
  21. 1275 /* crop default values */
  22. 1276 cap->cropcap.defrect.left = 0;
  23. 1277 cap->cropcap.defrect.top = 0;
  24. 1278 cap->cropcap.defrect.width = ctrl->cam->width;
  25. 1279 cap->cropcap.defrect.height = ctrl->cam->height;
  26. 1280
  27. 1281 a->bounds = cap->cropcap.bounds;
  28. 1282 a->defrect = cap->cropcap.defrect;
  29. 1283
  30. 1284 mutex_unlock(&ctrl->v4l2_lock);
  31. 1285
  32. 1286 return 0;
  33. 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 =垂直像素數 / 水平像素數

  1. 1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)
  2. 1290 {
  3. 1291 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  4. 1292
  5. 1293 fimc_dbg("%s\n", __func__);
  6. 1294
  7. 1295 if (!ctrl->cap) {
  8. 1296 fimc_err("%s: No capture device.\n", __func__);
  9. 1297 return -ENODEV;
  10. 1298 }
  11. 1299
  12. 1300 mutex_lock(&ctrl->v4l2_lock);
  13. 1301 a->c = ctrl->cap->crop;
  14. 1302 mutex_unlock(&ctrl->v4l2_lock);
  15. 1303
  16. 1304 return 0;
  17. 1305 }
  18. 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


  1. <PRE class=cpp name="code">1307 static int fimc_capture_crop_size_check(struct fimc_control *ctrl)
  2. 1308 {
  3. 1309 struct fimc_capinfo *cap = ctrl->cap;
  4. 1310 int win_hor_offset = 0, win_hor_offset2 = 0;
  5. 1311 int win_ver_offset = 0, win_ver_offset2 = 0;
  6. 1312 int crop_width = 0, crop_height = 0;
  7. 1313
  8. 1314 /* check win_hor_offset, win_hor_offset2 */
  9. 1315 win_hor_offset = ctrl->cam->window.left;
  10. 1316 win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left -
  11. 1317 ctrl->cam->window.width;
  12. 1318
  13. 1319 win_ver_offset = ctrl->cam->window.top;
  14. 1320 win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top -
  15. 1321 ctrl->cam->window.height;
  16. 1322
  17. 1323 if (win_hor_offset < 0 || win_hor_offset2 < 0) {
  18. 1324 fimc_err("%s: Offset (left-side(%d) or right-side(%d) "
  19. 1325 "is negative.\n", __func__, \
  20. 1326 win_hor_offset, win_hor_offset2);
  21. 1327 return -1;
  22. 1328 }
  23. 1329
  24. 1330 if (win_ver_offset < 0 || win_ver_offset2 < 0) {
  25. 1331 fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) "
  26. 1332 "is negative.\n", __func__, \
  27. 1333 win_ver_offset, win_ver_offset2);
  28. 1334 return -1;
  29. 1335 }
  30. 1336
  31. 1337 if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) {
  32. 1338 fimc_err("%s: win_hor_offset must be multiple of 2\n", \
  33. 1339 __func__);
  34. 1340 return -1;
  35. 1341 }
  36. 1342
  37. 1343 /* check crop_width, crop_height */
  38. 1344 crop_width = ctrl->cam->window.width;
  39. 1345 crop_height = ctrl->cam->window.height;
  40. 1346
  41. 1347 if (crop_width % 16) {
  42. 1348 fimc_err("%s: crop_width must be multiple of 16\n", __func__);
  43. 1349 return -1;
  44. 1350 }
  45. 1351
  46. 1352 switch (cap->fmt.pixelformat) {
  47. 1353 case V4L2_PIX_FMT_YUV420: /* fall through */
  48. 1354 case V4L2_PIX_FMT_NV12: /* fall through */
  49. 1355 case V4L2_PIX_FMT_NV21: /* fall through */
  50. 1356 case V4L2_PIX_FMT_NV12T: /* fall through */
  51. 1357 if ((crop_height % 2) || (crop_height < 8)) {
  52. 1358 fimc_err("%s: crop_height error!\n", __func__);
  53. 1359 return -1;
  54. 1360 }
  55. 1361 break;
  56. 1362 default:
  57. 1363 break;
  58. 1364 }
  59. 1365
  60. 1366 return 0;
  61. 1367 }
  62. </PRE><P></P>
  63. <PRE></PRE>
  64. <BR>
  65. cam->cam->window是crop設置後的取景框,這個函數就是檢測這個取景框是否符合規範
  66. <P></P>
  67. <P><BR>
  68. </P>
  69. <P><PRE class=cpp name="code">1377 static void fimc_capture_update_crop_window(struct fimc_control *ctrl)
  70. 1378 {
  71. 1379 unsigned int zoom_hor = 0;
  72. 1380 unsigned int zoom_ver = 0;
  73. 1381 unsigned int multiplier = 1024;
  74. 1382
  75. 1383 if (!ctrl->cam->width || !ctrl->cam->height)
  76. 1384 return;
  77. 1385
  78. 1386 zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width;
  79. 1387 zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height;
  80. 1388
  81. 1389 if (!zoom_hor || !zoom_ver)
  82. 1390 return;
  83. 1391
  84. 1392 /* Width */
  85. 1393 ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor;
  86. 1394 if (ctrl->cam->window.width > ctrl->cam->width)
  87. 1395 ctrl->cam->window.width = ctrl->cam->width;
  88. 1396 if (ctrl->cam->window.width % 16)
  89. 1397 ctrl->cam->window.width =
  90. 1398 (ctrl->cam->window.width + 0xF) & ~0xF;
  91. 1399
  92. 1400 /* Left offset */
  93. 1401 ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor;
  94. 1402 if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width)
  95. 1403 ctrl->cam->window.left =
  96. 1404 (ctrl->cam->width - ctrl->cam->window.width)/2;
  97. 1405 if (ctrl->cam->window.left % 2)
  98. 1406 ctrl->cam->window.left--;
  99. 1407
  100. 1408 /* Height */
  101. 1409 ctrl->cam->window.height =
  102. 1410 (ctrl->cap->crop.height * multiplier) / zoom_ver;
  103. 1411 if (ctrl->cam->window.top > ctrl->cam->height)
  104. 1412 ctrl->cam->window.height = ctrl->cam->height;
  105. 1413 if (ctrl->cam->window.height % 2)
  106. 1414 ctrl->cam->window.height--;
  107. 1415
  108. 1416 /* Top offset */
  109. 1417 ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver;
  110. 1418 if (ctrl->cam->window.height + ctrl->cam->window.top >
  111. 1419 ctrl->cam->height)
  112. 1420 ctrl->cam->window.top =
  113. 1421 (ctrl->cam->height - ctrl->cam->window.height)/2;
  114. 1422 if (ctrl->cam->window.top % 2)
  115. 1423 ctrl->cam->window.top--;
  116. 1424
  117. 1425 fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d)\n", \
  118. 1426 ctrl->cam->width, ctrl->cam->height, \
  119. 1427 ctrl->cap->crop.left, ctrl->cap->crop.top, \
  120. 1428 ctrl->cap->crop.width, ctrl->cap->crop.height, \
  121. 1429 ctrl->cam->window.left, ctrl->cam->window.top, \
  122. 1430 ctrl->cam->window.width, ctrl->cam->window.height);
  123. 1431
  124. 1432 }
  125. </PRE><BR>
  126. 根據s_crop設置的curr_crop設置capture 的取景框<BR>
  127. <P></P>
  128. <P><BR>
  129. </P>
  130. <P><PRE class=cpp name="code">1434 int fimc_s_crop_capture(void *fh, struct v4l2_crop *a)
  131. 1435 {
  132. 1436 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
  133. 1437 int ret = 0;
  134. 1438
  135. 1439 fimc_dbg("%s\n", __func__);
  136. 1440
  137. 1441 if (!ctrl->cap) {
  138. 1442 fimc_err("%s: No capture device.\n", __func__);
  139. 1443 return -ENODEV;
  140. 1444 }
  141. 1445
  142. 1446 mutex_lock(&ctrl->v4l2_lock);
  143. 1447 ctrl->cap->crop = a->c;
  144. 1448
  145. 1449 fimc_capture_update_crop_window(ctrl);
  146. 1450
  147. 1451 ret = fimc_capture_crop_size_check(ctrl);
  148. 1452 if (ret < 0) {
  149. 1453 mutex_unlock(&ctrl->v4l2_lock);
  150. 1454 fimc_err("%s: Invalid crop parameters.\n", __func__);
  151. 1455 return -EINVAL;
  152. 1456 }
  153. 1457
  154. 1458 if (ctrl->status == FIMC_STREAMON &&
  155. 1459 ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) {
  156. 1460 fimc_hwset_shadow_disable(ctrl);
  157. 1461 fimc_hwset_camera_offset(ctrl);
  158. 1462 fimc_capture_scaler_info(ctrl);
  159. 1463 fimc_hwset_prescaler(ctrl, &ctrl->sc);
  160. 1464 fimc_hwset_scaler(ctrl, &ctrl->sc);
  161. 1465 fimc_hwset_shadow_enable(ctrl);
  162. 1466 }
  163. 1467
  164. 1468 mutex_unlock(&ctrl->v4l2_lock);
  165. 1469
  166. 1470 return 0;
  167. 1471 }
  168. </PRE>fimc_s_crop_capture是capture設備的VIDIOC_S_CROP ioctl實現<P></P>
  169. <P>1449 用@a更新capture window</P>
  170. <P>1451 檢測新生成的capture window參數合法性</P>
  171. <P>1458 ~ 1466 FIMC支持streamon正在進行時,修改capture取景框<BR

發佈了40 篇原創文章 · 獲贊 20 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章