?一、前言
對于一個usb攝像頭,它的內核驅動源碼位于/drivers/media/usb/uvc/
核心層:V4L2_dev.c文件
硬件相關層: uvc_driver.c文件
本篇記錄基于對6.8.8.8內核下vivid-core.c文件(虛擬視頻驅動程序)的分析,梳理Linux系統中vedio視頻設備的驅動框架。
二、源碼分析
1、入口函數
module_init(vivid_init);vivid_init//注冊vivid設備和驅動platform_device_register(&vivid_pdev);platform_driver_register(&vivid_pdrv);
通過入口函數將平臺設備和平臺驅動結構體注冊到內核中,關于具體的設備和驅動注冊先關內容可以看Linux--平臺設備、平臺驅動的注冊源碼分析-CSDN博客這篇。
在代碼中,vivid_pdrv
平臺驅動沒有 of_match_table
字段,因為該驅動程序不依賴設備樹進行匹配和初始化。如果是真實的硬件驅動程序需要支持設備樹匹配,則需要定義 of_match_table
字段,并提供一個設備樹兼容字符串數組,也就是compatible屬性值。
2、probe()函數
在vivid_init()
里分別注冊了vivid_pdev
和vivid_pdrv
,注冊后,當他們匹配時,內核會自動則會調用該驅動程序probe()初始化該設備
。在probe()
里面主要進行初始化、注冊等相關流程。
vivid_probe1) vivid_create_instance /* 創建實例 */dev = kzalloc(sizeof(*vivid_dev), GFP_KERNEL);/* 分配video_devicede */v4l2_device_register /* 初始化v4l2_device */2) static int vivid_create_devnodes(struct platform_device *pdev,struct vivid_dev *dev, int inst,unsigned int cec_tx_bus_cnt,v4l2_std_id tvnorms_cap,v4l2_std_id tvnorms_out,unsigned in_type_counter[4],unsigned out_type_counter[4])
{/* 設置video_device */1.vfd->fops = &vivid_fops; /*也就是在probe里的這一步實現設備操作和驅動操作的綁定*/vfd->ioctl_ops = &vivid_ioctl_ops;vfd->release = video_device_release_empty;2.vfd->v4l2_dev = &dev->v4l2_dev;3.設置"ctrl屬性"(用于APP的ioctl)v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);.../*注冊vedio_device*/ /*分配主次設備號*/video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)__video_register_devicevdev->cdev = cdev_alloc();vdev->cdev->ops = &v4l2_fops;video_devices[vdev->minor] = vdev;//將video_device放入全局數組中ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);if (vdev->ctrl_handler == NULL)vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
關鍵點:
1、分配video_device結構體內存? ? ? ? ??video_device_alloc()
或kzalloc()
;
2、設置video_device? ? ? ?.fops
、.ioctl_ops
、dev
;、
也就是在probe里的這一步實現設備操作和驅動操作的綁定
3、注冊video_device結構體? ? ??video_register_device()
;
3、操作函數(open、read、wirite等)
1、open
app: open("/dev/video0",....)---------------------------------------------------
drv: v4l2_fops.v4l2_openvdev = video_devdata(filp); // 根據次設備號從數組中得到video_deviceret = vdev->fops->open(filp);vivi_ioctl_ops.openv4l2_fh_open
當應用層發生系統調用時,會先調用到v4l2_fops中的v4l2_open,v4l2_open會找到對應設備video_device的file opr中的open,而設備中的open是在驅動注冊后調用probe函數與驅動函數定義的open綁定的,這樣就實現了video設備用戶空間open調用驅動open的過程。
2、ioctl
app: read ....-----------------------------------------------drv: v4l2_fops.v4l2_readstruct video_device *vdev = video_devdata(filp);ret = vdev->fops->read(filp, buf, sz, off);
核心層v4l2_ctrl_handler會找到video_device的fops 。過程如下(在上文中通過v4l2_ctrl_handler_setup設置了某些屬性的ioctl處理函數)
__video_do_ioctlstruct video_device *vfd = video_devdata(file);v4l2_is_known_ioctl(cmd)info = &v4l2_ioctls[_IOC_NR(cmd)]; /* v4l2_ioctls數組存有全部IOCTL_INFO,含有 ioctl函數指針 */ret = info->func(ops, file, fh, arg); /* 調用對應的ioctl函數 */
三、UVC(USB Video Class)
UVC全稱為USB Video Class,即:USB視頻類,是一種為USB視頻捕獲設備定義的協議標準。是Microsoft與另外幾家設備廠商聯合推出的為USB視頻捕獲設備定義的協議標準,已成為USB org標準之一。
最新的UVC版本為UVC 1.5,由USB Implementers Forum定義包括基本協議及負載格式。? ? ? ? ? ? ?
USB攝像頭示例如下:
對于框架具體細節可以看這篇UVC 1.5 Class Specification 簡解_uvc1.5-CSDN博客
UVC驅動的重點在于:
? ?描述符的分析
? ?屬性的控制: 通過VideoControl Interface來設置
? ?格式的選擇:通過VideoStreaming Interface來設置
? ?數據的獲得:通過VideoStreaming Interface的URB來獲得
參考文章:
??????【Linux驅動】Linux--虛擬攝像頭vivid驅動分析(基于5.4內核)-CSDN博客
【轉載】linux攝像頭驅動_linux 攝像頭驅動-CSDN博客? ? ? ? ? ? ? ? ?