摄像头驱动属于字符驱动。
应用程序:open/read/write
驱动程序:drv_open/drv_read/drv_write
怎么去写驱动:
①构造file_operations:
.open=drv_open
.read=drv_read
...
②告诉内核:register_chardev(主设备号,次设备号, file_operations,name);
//注册字符驱动程序就是把file_operations发到内核中的某个chardev数组中,根据主设备号和次设备号确定放入数组中的位置。
1.分配cdev结构体
2.设置cdev结构体,设置时,cdev结构体中的某一项=file_operations
3.cdev_add
③谁来调用register_chardev,一般是入口函数来调用。
④有注册驱动就有对应的卸载驱动,一般利用出口函数进行卸载。在出口函数中调用unregistered_chardev
对于复杂的字符驱动:
分层
上层:
fbmem.c:
①file_operations
open/read/write
②register_chardev
③入口/出口
硬件相关:
①分配fb_info
②设置fb_info
③注册
④硬件相关
如何编写分层驱动程序?
①分配某结构体(LCD驱动是fb_info结构体)
②设置
③注册
④硬件相关操作
V4L2框架
APP:open/read/write
核心层
v4l2_dev.c
①file_operations
②注册
cdev_alloc:分配fop结构体
cdev_ops=v4l2_fops,其中包含open/read/write
cdev_add
硬件相关
uvc_driver.c
v4l2_device_register
video_device_alloc
video_register_device
①分配video_device
②
③注册video_device
虚拟视频驱动vivi.c分析:
1.分配video_device
2.设置
3.注册:video_register_device
vivi_init
vivi_create_instance
v4l2_device_register // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数
video_device_alloc
// 设置
1. vfd:
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
2.
vfd->v4l2_dev = &dev->v4l2_dev;
3. 设置"ctrl属性"(用于APP的ioctl):
v4l2_ctrl_handler_init(hdl, 11);
dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 16);
video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)//根据类型创建不同的名字,对于不同的类型次设备号也是不一样的
__video_register_device
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
cdev_add
video_device[vdev->minor] = vdev;//根据次设备号将vdev放入数组
if (vdev->ctrl_handler == NULL)
vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
分析vivi.c的open,read,write,ioctl过程
1. open
app: open("/dev/video0",....)
---------------------------------------------------
drv: v4l2_fops.v4l2_open
vdev = video_devdata(filp); // 根据次设备号从数组中得到video_device
ret = vdev->fops->open(filp);
vivi_ioctl_ops.open
v4l2_fh_open
2. read
app: read ....
---------------------------------------------------
drv: v4l2_fops.v4l2_read
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->read(filp, buf, sz, off);
3. ioctl
app: ioctl
----------------------------------------------------
drv: v4l2_fops.unlocked_ioctl
v4l2_ioctl
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
video_ioctl2
video_usercopy(file, cmd, arg, __video_do_ioctl);
__video_do_ioctl
struct video_device *vfd = video_devdata(file);
根据APP传入的cmd来获得、设置"某些属性"
怎么写V4L2的驱动?
①分配/设置/注册 v4l2_device:v4l2_device_register得到v4l2_device(辅助作用,提供自旋锁和计数量)。
②分配videv_device:video_device_alloc
③设置vfd(videv_device):a.vfd->v4l2_dev指向v4l2_device.
b.vfd:
.fops=...中的open/read/write 被上层的v4l2_fops调用
.ioctl_ops=
c.APP可以通过ioctl来设置获得亮度等信息。
驱动程序里,谁来接收/存储/设置到硬件/提供这些信息
属性:
v4l2_ctrl
管理:
v4l2_ctrl_handler
①v4l2_ctrl_handler_init(初始化)
②创建以下v4l2_ctrl,放入v4l2_ctrl_handler链表
v4l2_ctrl_new_std
v4l2_ctrl_new_custom
③跟vdev关联
v4l2_dev.ctrl_handler = hal
video_dev->v4l2_dev= v4l2_dev
本文章源于百问网韦东山嵌入式