xilinx的VDMA驱动分析
研究生期间由于导师研究的项目需要,对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驱动分析相关推荐
- linux串口驱动分析
linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...
- 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇
关键词:android 电池 电量计 MAX17040 任务初始化宏 power_supply 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0 ...
- Android10.0 Binder通信原理(五)-Binder驱动分析
摘要:本节主要来讲解Android10.0 Binder的驱动层分析 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计 ...
- linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析
uart tty serial 驱动分析 内核版本3.14.23 以atmel为例: 起点: static int __init atmel_serial_init(void) { int ret; ...
- linux 网卡驱动分析,LINUX_网卡驱动分析
LINUX_网卡驱动分析 (36页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 Linux DM9000网卡驱动程序完全分析说明仁 本文分 ...
- Linux PCI网卡驱动分析
http://www.uplinux.com/shizi/wenxian/4429.html Linux网卡驱动分析 学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难 ...
- Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇
Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...
- wince串口驱动分析(转)
wince串口驱动分析 串行通讯接口主要是指UART(通用串行)和IRDA两种.通常的串行连接电气连接上有3wire和9wire两种.3wire的接线方式下定义了发送.接收和地三根连接.其用途就如名称 ...
- framebuffer驱动详解4——framebuffer驱动分析2(probe函数讲解)
以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 主要在填充fbdev这个结构体. 二.framebuffer驱动分析2 1.probe函数分析 (1)struct s ...
最新文章
- Gridview][UpdateCommand的写法要点]
- OpenStack(Kilo版本)基础架构学习笔记
- EditText的另类用法
- Python pandas模块输出每行中间省略号问题
- 17年三月计算机二级,2017年3月计算机二级考试攻略
- linux tempfile指令学习
- java json float_java – Json解析问题(值自动更改为float)
- php替换局部大小写字母,php替换字符串中的一些字符(区分大小写)的函数str_replace()...
- 在linux系统中下载thchs30,aishell数据处理为thchs30格式
- css使两个盒子并列_前端学习CSS
- Java SE 基础:List 集合列表
- 计算机专业考研复试经验【最终版本】(来自一位上岸又退学的二战dog)
- 百度html的json解析,百度调用API返回json数据解析
- canvas画圆形进度条
- Git commit --amend 修改提交信息
- php 美颜,怀念以前无滤镜美颜的影视剧
- Android 更换皮肤
- 微信小程序php签到功能,小程序签到功能的作用
- 使用 Swift 语言编程的优缺点
- 图扑 TopLink 边缘组态
热门文章
- ALOGV,ALOGD,ALOGI,ALOGW,ALOGE区别
- HTML行内元素、块状元素、行内块状元素介绍
- 潘娟:从女工程师转变成开源商业化Infra公司创始人,痛并快乐着
- IMU/GNSS组合导航经典论文论文合集IMU校准ahrs滤波算法
- 2023基于微信小程序的游戏账号在线交易买卖平台(SSM+mysql)-JAVA.VUE(论文+开题报告+运行)
- Idea git local changes were not restore
- 【IDEA checkout分支冲突,点rollback后,之前add但未commit的代码找回】
- 服务器证书 sll证书的理解
- UE4小地图制作 (使用蓝图制作小地图)
- 上美集团吕义雄:跨界营销新玩法