研究生期间由于导师研究的项目需要,对xilinx的IP核Video-DMA内核中驱动进行学习。(此处的为DMA 通道驱动,而非DMA engines)

首先,查看设备结构体:

struct xvip_dma {struct list_head list;struct video_device video;struct media_pad pad;struct xvip_composite_device *xdev;struct xvip_pipeline pipe;unsigned int port;struct mutex lock;struct v4l2_pix_format format;const struct xvip_video_format *fmtinfo;struct vb2_queue queue;void *alloc_ctx;unsigned int sequence;struct list_head queued_bufs;spinlock_t queued_lock;struct dma_chan *dma;unsigned int align;struct dma_interleaved_template xt;struct data_chunk sgl[1];int input;int vptype;
};

可以看到,VDMA设备被定义成了video_device。

注意,xilinx-dma并不是作为单独一个设备进行注册(它没有probe函数),它需要依附xvip_composite_device设备进行初始化,同时在设备树中设备中的一些参数是放在xvip_composite_device设备中的。查看xilinx-vipp.c文件中的probe函数,调用关系如下:

xvip_composite_probe

->xvip_graph_init

->xvip_graph_dma_init

->xvip_graph_dma_init_one

->xvip_dma_init

至此,vipp和vdma挂上钩。

来分析xvip_dma_init函数:

int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,enum v4l2_buf_type type, unsigned int port)
{char name[14];int ret;dma->xdev = xdev;dma->port = port;mutex_init(&dma->lock);mutex_init(&dma->pipe.lock);INIT_LIST_HEAD(&dma->queued_bufs);spin_lock_init(&dma->queued_lock);dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);dma->format.pixelformat = dma->fmtinfo->fourcc;dma->format.colorspace = V4L2_COLORSPACE_SRGB;dma->format.field = V4L2_FIELD_NONE;dma->format.width = XVIP_DMA_DEF_WIDTH;dma->format.height = XVIP_DMA_DEF_HEIGHT;dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp;dma->format.sizeimage = dma->format.bytesperline * dma->format.height;/* Initialize the media entity... */dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0);if (ret < 0)goto error;/* ... and the video node... */dma->video.fops = &xvip_dma_fops;dma->video.v4l2_dev = &xdev->v4l2_dev;dma->video.queue = &dma->queue;snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u",xdev->dev->of_node->name,type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",port);dma->video.vfl_type = VFL_TYPE_GRABBER;dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE? VFL_DIR_RX : VFL_DIR_TX;dma->video.release = video_device_release_empty;dma->video.ioctl_ops = &xvip_dma_ioctl_ops;dma->video.lock = &dma->lock;video_set_drvdata(&dma->video, dma);/* ... and the buffers queue... */dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev);if (IS_ERR(dma->alloc_ctx)) {ret = PTR_ERR(dma->alloc_ctx);goto error;}/* Don't enable VB2_READ and VB2_WRITE, as using the read() and write()* V4L2 APIs would be inefficient. Testing on the command line with a* 'cat /dev/video?' thus won't be possible, but given that the driver* anyway requires a test tool to setup the pipeline before any video* stream can be started, requiring a specific V4L2 test tool as well* instead of 'cat' isn't really a drawback.*/dma->queue.type = type;dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;dma->queue.lock = &dma->lock;dma->queue.drv_priv = dma;dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer);dma->queue.ops = &xvip_dma_queue_qops;dma->queue.mem_ops = &vb2_dma_contig_memops;dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC| V4L2_BUF_FLAG_TSTAMP_SRC_EOF;ret = vb2_queue_init(&dma->queue);if (ret < 0) {dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n");goto error;}/* ... and the DMA channel. */sprintf(name, "port%u", port);dma->dma = dma_request_slave_channel(dma->xdev->dev, name);if (dma->dma == NULL) {dev_err(dma->xdev->dev, "no VDMA channel found\n");ret = -ENODEV;goto error;}dma->align = 1 << dma->dma->device->copy_align;ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1);if (ret < 0) {dev_err(dma->xdev->dev, "failed to register video device\n");goto error;}return 0;error:xvip_dma_cleanup(dma);return ret;
}

在xvip_dma_init中可以到vdma作为video_device设备在/dev目录下生成video节点,作为应用层操作的核心。

作为video_device设备,需要设置v4l2_file_operations和v4l2_ioctl_ops来实现在应用层进行相关操作。从上面的代码看到v4l2_file_operations被设置成xvip_dma_fops:

static const struct v4l2_file_operations xvip_dma_fops = {.owner        = THIS_MODULE,.unlocked_ioctl  = video_ioctl2,.open       = v4l2_fh_open,.release    = vb2_fop_release,.poll        = vb2_fop_poll,.mmap       = vb2_fop_mmap,
};

4l2_ioctl_ops为:

static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = {.vidioc_querycap       = xvip_dma_querycap,.vidioc_enum_fmt_vid_cap   = xvip_dma_enum_format,.vidioc_g_fmt_vid_cap       = xvip_dma_get_format,.vidioc_g_fmt_vid_out        = xvip_dma_get_format,.vidioc_s_fmt_vid_cap        = xvip_dma_set_format,.vidioc_s_fmt_vid_out        = xvip_dma_set_format,.vidioc_try_fmt_vid_cap      = xvip_dma_try_format,.vidioc_try_fmt_vid_out      = xvip_dma_try_format,.vidioc_reqbufs          = vb2_ioctl_reqbufs,.vidioc_querybuf       = vb2_ioctl_querybuf,.vidioc_qbuf          = vb2_ioctl_qbuf,.vidioc_dqbuf         = vb2_ioctl_dqbuf,.vidioc_create_bufs      = vb2_ioctl_create_bufs,.vidioc_expbuf         = vb2_ioctl_expbuf,.vidioc_streamon        = vb2_ioctl_streamon,.vidioc_streamoff     = vb2_ioctl_streamoff,.vidioc_g_input          = vidioc_g_input,.vidioc_s_input       = vidioc_s_input,.vidioc_enum_input        = vidioc_enum_input,.vidioc_queryctrl      = vidioc_queryctrl,.vidioc_g_ctrl          = vidioc_getctrl,                   //add by ray.vidioc_s_ctrl          = vidioc_setctrl                    //add by ray
};
static struct vb2_ops xvip_dma_queue_qops = {.queue_setup = xvip_dma_queue_setup,.buf_prepare = xvip_dma_buffer_prepare,.buf_queue = xvip_dma_buffer_queue,.wait_prepare = vb2_ops_wait_prepare,.wait_finish = vb2_ops_wait_finish,.start_streaming = xvip_dma_start_streaming,.stop_streaming = xvip_dma_stop_streaming,
};

除了必须的11个ioctrl函数,还添加了更多的函数。这些ioctrl才是驱动的核心。

xilinx的VDMA驱动分析相关推荐

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  2. 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0  ...

  3. Android10.0 Binder通信原理(五)-Binder驱动分析

    摘要:本节主要来讲解Android10.0 Binder的驱动层分析 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计 ...

  4. linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析

    uart tty serial 驱动分析 内核版本3.14.23 以atmel为例: 起点: static int __init atmel_serial_init(void) { int ret; ...

  5. linux 网卡驱动分析,LINUX_网卡驱动分析

    LINUX_网卡驱动分析 (36页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 Linux DM9000网卡驱动程序完全分析说明仁 本文分 ...

  6. Linux PCI网卡驱动分析

    http://www.uplinux.com/shizi/wenxian/4429.html Linux网卡驱动分析 学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难 ...

  7. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  8. wince串口驱动分析(转)

    wince串口驱动分析 串行通讯接口主要是指UART(通用串行)和IRDA两种.通常的串行连接电气连接上有3wire和9wire两种.3wire的接线方式下定义了发送.接收和地三根连接.其用途就如名称 ...

  9. framebuffer驱动详解4——framebuffer驱动分析2(probe函数讲解)

    以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 主要在填充fbdev这个结构体. 二.framebuffer驱动分析2 1.probe函数分析 (1)struct s ...

最新文章

  1. Gridview][UpdateCommand的写法要点]
  2. OpenStack(Kilo版本)基础架构学习笔记
  3. EditText的另类用法
  4. Python pandas模块输出每行中间省略号问题
  5. 17年三月计算机二级,2017年3月计算机二级考试攻略
  6. linux tempfile指令学习
  7. java json float_java – Json解析问题(值自动更改为float)
  8. php替换局部大小写字母,php替换字符串中的一些字符(区分大小写)的函数str_replace()...
  9. 在linux系统中下载thchs30,aishell数据处理为thchs30格式
  10. css使两个盒子并列_前端学习CSS
  11. Java SE 基础:List 集合列表
  12. 计算机专业考研复试经验【最终版本】(来自一位上岸又退学的二战dog)
  13. 百度html的json解析,百度调用API返回json数据解析
  14. canvas画圆形进度条
  15. Git commit --amend 修改提交信息
  16. php 美颜,怀念以前无滤镜美颜的影视剧
  17. Android 更换皮肤
  18. 微信小程序php签到功能,小程序签到功能的作用
  19. 使用 Swift 语言编程的优缺点
  20. 图扑 TopLink 边缘组态

热门文章

  1. ALOGV,ALOGD,ALOGI,ALOGW,ALOGE区别
  2. HTML行内元素、块状元素、行内块状元素介绍
  3. 潘娟:从女工程师转变成开源商业化Infra公司创始人,痛并快乐着
  4. IMU/GNSS组合导航经典论文论文合集IMU校准ahrs滤波算法
  5. 2023基于微信小程序的游戏账号在线交易买卖平台(SSM+mysql)-JAVA.VUE(论文+开题报告+运行)
  6. Idea git local changes were not restore
  7. 【IDEA checkout分支冲突,点rollback后,之前add但未commit的代码找回】
  8. 服务器证书 sll证书的理解
  9. UE4小地图制作 (使用蓝图制作小地图)
  10. 上美集团吕义雄:跨界营销新玩法