Android S5PV210 fimc驱动分析 - fimc_capture.c
fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片
http://blog.csdn.net/kickxxx/article/details/7733482
- 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格式
- 131 static const struct v4l2_queryctrl fimc_controls[] = {
- 132 {
- 133 .id = V4L2_CID_ROTATION,
- 134 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 135 .name = "Roataion",
- 136 .minimum = 0,
- 137 .maximum = 270,
- 138 .step = 90,
- 139 .default_value = 0,
- 140 }, {
- 141 .id = V4L2_CID_HFLIP,
- 142 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 143 .name = "Horizontal Flip",
- 144 .minimum = 0,
- 145 .maximum = 1,
- 146 .step = 1,
- 147 .default_value = 0,
- 148 }, {
- 149 .id = V4L2_CID_VFLIP,
- 150 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 151 .name = "Vertical Flip",
- 152 .minimum = 0,
- 153 .maximum = 1,
- 154 .step = 1,
- 155 .default_value = 0,
- 156 }, {
- 157 .id = V4L2_CID_PADDR_Y,
- 158 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 159 .name = "Physical address Y",
- 160 .minimum = 0,
- 161 .maximum = 1,
- 162 .step = 1,
- 163 .default_value = 0,
- 164 .flags = V4L2_CTRL_FLAG_READ_ONLY,
- 165 }, {
- 166 .id = V4L2_CID_PADDR_CB,
- 167 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 168 .name = "Physical address Cb",
- 169 .minimum = 0,
- 170 .maximum = 1,
- 171 .step = 1,
- 172 .default_value = 0,
- 173 .flags = V4L2_CTRL_FLAG_READ_ONLY,
- 174 }, {
- 175 .id = V4L2_CID_PADDR_CR,
- 176 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 177 .name = "Physical address Cr",
- 178 .minimum = 0,
- 179 .maximum = 1,
- 180 .step = 1,
- 181 .default_value = 0,
- 182 .flags = V4L2_CTRL_FLAG_READ_ONLY,
- 183 }, {
- 184 .id = V4L2_CID_PADDR_CBCR,
- 185 .type = V4L2_CTRL_TYPE_BOOLEAN,
- 186 .name = "Physical address CbCr",
- 187 .minimum = 0,
- 188 .maximum = 1,
- 189 .step = 1,
- 190 .default_value = 0,
- 191 .flags = V4L2_CTRL_FLAG_READ_ONLY,
- 192 },
- 193 };
定义了FIMC支持的ctrl,后面四个ctrl: V4L2_CID_PADDR_Y, V4L2_CID_PADDR_CB, V4L2_CID_PADDR_CR, V4L2_CID_PADDR_CBCR 是samsung fimc私有的ctrl id, 用来获取分量的物理起始地址。
- 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 }
这个函数被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 }
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 }
我觉得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 }
与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 }
这个函数选择@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 }
分配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 }
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 }
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 }
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
fimc_g_crop_capture 是capture设备的VIDIOC_G_CROP实现,返回当前的crop
- <pre name="code" class="cpp">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></p><pre name="code" class="cpp">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></p><pre name="code" class="cpp">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>
- </p>
- <p><br>
- </p>
- <p><br>
- </p>
- <p><br>
- <br>
- </p>
Android S5PV210 fimc驱动分析 - fimc_capture.c的更多相关文章
- 高通 android平台LCD驱动分析
目前手机芯片厂家提供的源码里包含整个LCD驱动框架,一般厂家会定义一个xxx_fb.c的源文件,注册一个平台设备和平台驱动,在驱动的probe函数中来调用register_framebuffer(), ...
- 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇
关键词:android 电池 电量计 PL2301任务初始化宏 power_supply 中断线程化 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 ...
- 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇
关键词:android 电池 电量计 MAX17040 任务初始化宏 power_supply 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台: ...
- android电池(四):电池 电量计(MAX17040)驱动分析篇【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/8969369 电池电量计,库仑计,用max17040这颗电量IC去计量电池电量,这种方法 ...
- s5k4ba摄像头驱动分析
注释: 本驱动是基于S5PV310的,但是全天下的摄像头驱动都是采用V4L2,因此驱动框架流程基本差不多.其中fimc_init_camera()函数会回调.init函数,该函数主要就是通过IIC总线 ...
- ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程
对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...
- [置顶] Android开发之serviceManager分析
Android 开发之serviceManager分析 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binde ...
- 《Android系统源代码情景分析》连载回忆录:灵感之源
上个月,在花了一年半时间之后,写了55篇文章,分析完成了Chromium在Android上的实现,以及Android基于Chromium实现的WebView.学到了很多东西,不过也挺累的,平均不到两个 ...
- Android Hal层简要分析
Android Hal层简要分析 Android Hal层(即 Hardware Abstraction Layer)是Google开发的Android系统里上层应用对底层硬件操作屏蔽的一个软件层次, ...
随机推荐
- CentOS 笔记(三) 目录结构
理解CentOS 目录结构 首次登录进入,应该是进入了,run文件夹 通过 cd ../ 进入了,最根节点 通过 ls 显示全部文件夹 通过 pwd 查看当前目录 参考: https://www ...
- 汇编-理解call,ret
; 有意思的东西,主函数调用子函数用汇编来理解 assume cs:codeseg codeseg segment start: main: call sub1 ; 调用子函数1, push IP1 ...
- Tensorflow读取文件到队列文件
TensorFlow读取二进制文件数据到队列 2016-11-03 09:30:00 0个评论 来源:diligent_321的博客 收藏 我要投稿 TensorFlow是一种 ...
- Appium遇到问题:
问题一:问题org.openqa.selenium.remote.UnreachableBrowserException: Could not start a new session. Possibl ...
- Oracle中Cursor介绍和使用
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/MyDreamNeverstop/article/details/78604033 一 概念 游标 ...
- BA-siemens-insight-event builder使用
event builder功能主要是用来给report使用的,作为一个独立的对象,这个对象的功能就是收集点位的信息,如果再使用report功能就可以显示或输出点位的信息.
- 洛谷—— P1803 凌乱的yyy
https://www.luogu.org/problem/show?pid=1803 题目背景 快noip了,yyy很紧张! 题目描述 现在各大oj上有n个比赛,每个比赛的开始.结束的时间点是知道的 ...
- cogs 1143. [石门中学2009] 切割树
1143. [石门中学2009] 切割树 ★ 输入文件:treecut.in 输出文件:treecut.out 简单对比时间限制:1 s 内存限制:128 MB treecut 题目描 ...
- An internal error occurred during: "Building workspace". java.lang.StackOverflowError
1 错误描写叙述 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveW91MjNoYWk0NQ==/font/5a6L5L2T/fontsize/400/fi ...
- SVN文件恢复
SVN删除文件 一.本地删除 SVN删除文件里的本地删除,指的是在clientdelete了一个文件,但还没有commit.使用revert来撤销删除. 二.server删除 1.通过本地删除后提交s ...