Linux 下 USB摄像头驱动的实现

时间:2022-05-17 06:04:49

Linux 下 USB摄像头驱动的实现

摘要:介绍了Linux体系下USB摄像头驱动的体系结构。首先介绍了作为Linux视频部分标准的Video4Linux,这是USB摄像头开发的关键部分;然后描述了Linux体系下USB设备驱动的层次结构以及涉及到的几个重要数据结构;最后给出了中星微的ZC0301P摄像头驱动的具体实现。

关键词:USB摄像头;Linux;video4Linux;驱动程序

中图分类号:TP301文献标识码:A文章编号:16727800(2012)009001803

0引言

USB摄像头由于价格低廉、使用方便、通用性强,被广泛应用于个人电脑、视频监控、图像采集等设备中。目前 ,摄像头驱动程序大部分都是基于Windows平台下,而嵌入式系统大都采用Linux系统,因此需要开发在嵌入式Linux平台下的基于Linux驱动框架的摄像头驱动程序。

摄像头主要由主控芯片和传感芯片两部分组成,景物通过镜头生成的光学图像投射到图像传感器上,然后转为电信号,经过A/D转换后变为数字图像信号,然后送到DSP中处理。主控芯片负责图像采集、压缩以及和主机的通信。本文中摄像头芯片采用的是中星微公司的ZC0301P芯片,这是目前应用比较广泛的一款产品。

1Linux下的视频标准Video4Linux

目前的Linux内核已经添加了对音视频设备的支持,这部分的标准是Video4Linux(简称V4L)。V4L是一些视频系统、视频软件、音频软件的基础,目前主要应用在图像采集、视频采集等多媒体设备中,比如可视电话、视频监控、Webcam,是嵌入式Linux开发人员经常使用的系统调用接口。Linux内核通过V4L为用户空间提供了标准的操作接口,各种音频和视频设备相应的驱动程序加载进内核后,V4L就可以通过内核提供的API像对普通文件一样来操作视频和音频设备,从这里可以看出V4L大体分为两层,上层为系统提供的API,底层为音视频设备在内核中的驱动。这个标准提供了一套标准接口,应用程序、内核、驱动以这个接口进行互相访问。同时,该标准对USB摄像头也提供非常好的支持。

V4L为Linux音视频设备驱动程序提供了以下几个重要数据结构:①struct video_capabilitycap;/ 包含了摄像头设备的基本信息;②struct video_picturepic;/包含了摄像头设备采集的图像的各种属性;③struct video_mmapbuf;/用于实现内存映射;④struct video_mbufvm;/利用video_mmap进行内存映射得到帧的信息。

2Linux下USB驱动体系

USB是英文Universal Serial BUS(通用串行总线)的缩写,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯,主要有以下特点:使用简单、支持热插拔、传输速度快、方便扩展,大大简化了不同类型外设与计算机间的连接。USB是一种分层总线结构,并且由一个主机控制器来控制,USB主机控制器负责询问每一个USB设备是否有数据需要发送,USB不支持设备的直接通信。

如图1所示,在Linux驱动中,USB驱动处于最底层的是USB主机控制器硬件,在其之上运行的是USB主机控制器驱动,主机控制器之上为USB核心层,再上层为USB设备驱动层(插入主机上的U盘、鼠标、USB转串口等设备驱动)。因此,在主机侧的层次结构中,要实现的USB驱动包括两类:USB主机控制器驱动和USB设备驱动,前者控制插入其中的USB设备,后者控制USB设备如何与主机通信。Linux内核USB核心负责USB驱动管理和协议处理的主要工作。主机控制器驱动和设备驱动之间的USB核心非常重要,其功能包括:通过定义一些数据结构、宏和功能函数,向上为设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口;通过全局变量维护整个系统的USB设备信息;完成设备热拔插控制、总线数据传输控制等。

3本文涉及的几个主要数据结构

本文中主要有如下几个数据结构,分别是:

(1)USB设备数据结构usb_device,它保存了一个USB设备的信息,包括设备地址、设备描述符、配置描述符等。

(2) struct usb_driver 是对USB设备的最高层次的抽象,这个结构用于向USBD层注册USB设备驱动程序。该结构体中有两个重要函数分别是probe和disconnect,当内核中有某设备的驱动程序,而且当该设备连接上时,系统会自动调用probe函数探测。当拔出该设备时disconnect函数会被调用,移除该设备。所以这两个函数支持了热拔插操作。

(3)文件系统数据结构。File_opertions是Linux设备驱动中的一个重要数据结构。在Linux系统中设备驱动被当做文件,所以,对设备的操作就是对设备文件的操作。File_opertions定义了文件操作如open()、read()、write()、chose()等。当这些函数被调用时,实际与它们关联的函数(数据结构中定义的函数)将会被调用。

4摄像头驱动程序各模块的实现

本文的USB摄像头驱动程序是以模块的形式编译进Linux的内核,所以必须先定义模块操作的函数。模块初始化函数zc0301_module_init(void)调用函数usb_register(&zc0301_usb_driver)向USB核心子系统注册USB设备驱动,若注册成功则返回0。部分代码如下:

模块卸载函数zc0301_module_exit(void)调用usb_deregister(&zc0301_usb_driver)向USB核心子系统注销USB设备驱动。部分代码如下:

zc0301_usb_probe()和zc0301_usb_disconnect()函数是USB设备驱动中重要、必须的部分,分别用来实现设备的探测和设备断开连接,实现USB设备的热拔插技术。

在函数zc0301_usb_probe中,调用interface_to_usbdev(intf) 来获取USB接口对应的USB设备,主要完成如下两项工作:根据USB_interface指针intf获取usb_device的地址。获取USB接口对于的USB设备,USB接口对应的USB设备是该接口的父设备。然后调用kzalloc(sizeof(struct zc0301_device)函数为设备分配内存。调用mutex_init(&cam->dev_mutex)初始化一个互斥量实现设备的互斥访问。调用zc0301_init(cam)初始化摄像头芯片。最后调用video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,video_nr[dev_nr])函数注册一个视频设备,部分代码如下:

4.3MMAP内存映射机制

Linux中文件的传统访问方式是:首先用open()系统调用打开文件,然后使用read()、write()以及lseek()等调用进行顺序或者随机的I/O访问。这种方式是非常低效的,每一次I/O操作都需要一次系统调用。另外,如果若干个进程访问同一个文件,每个进程都要在自己的地址空间维护一个副本,浪费了内存空间,如图2所示。对大量的图像数据来说,这种频繁拷贝会增加系统开销,特别对资源相对较少的嵌入式系统来说更加明显。

图2Read系统调用

内存映射机制提供了一种很好的解决问题的方法:它是将页面映射到进程的地址空间中,也就是说首先通过简单产生的某些内存管理数据结构完成映射的创建。当进

程访问页面时产生一个缺页中断,内核将页面读入内存并且更新页表指向该页面。本文的MMAP映射函数的部分代码如下:

5结语

Linux是当前最受欢迎的操作系统之一。它具有内核小、效率高、源码开放的优点,所以也被广泛应用于嵌入式系统中。与嵌入式平台相应的驱动程序的发展也日新月异,具有广阔的前景。本文介绍的在LinuxV4L标准下的USB摄像头驱动程序有很高的实用价值,对于其它设备驱动的开发具有一定的参考价值。

参考文献:

[1]王鑫.嵌入式Linux下USB通用摄像头驱动程序研究与设计[D].沈阳:东北大学,2006.

[2]宋宝华.Linux设备驱动开发详解:第2版[M].北京:人民邮电出版社,2010.

[3]刘飞,张曦煌.基于嵌入式平台的USB摄像头驱动程序的实现[J].计算机工程与设计,2008(4).

[4]宋丽华,高珂.嵌入式Linux下USB摄像头驱动实现[J].计算机工程,2010(5).

上一篇:云计算:基于Xen平台下OCFS2的性能研究 下一篇:任务驱动的计算机教学模式设计