怎样写linux下的USB设备驱动程序加精Word下载.docx
- 文档编号:15895054
- 上传时间:2022-11-16
- 格式:DOCX
- 页数:11
- 大小:44.59KB
怎样写linux下的USB设备驱动程序加精Word下载.docx
《怎样写linux下的USB设备驱动程序加精Word下载.docx》由会员分享,可在线阅读,更多相关《怎样写linux下的USB设备驱动程序加精Word下载.docx(11页珍藏版)》请在冰豆网上搜索。
本文将详细介绍运行于PC机上的USB系统是如何运作的。
并同时用USB驱动程序的框架程序当例子作详细的说明,我们在此文中不讨论USB器件的驱动程序。
USB驱动程序基础
在动手写USB驱动程序这前,让我们先看看写的USB驱动程序在内核中的结构,如下图:
USB驱动程序存在于不同的内核子系统和USB硬件控制器之间,USB核心为USB驱动程序提供了一个用于访问和控制USB硬件的接口,而不必考虑系统当前存在的各种不同类型的USB硬件控制器。
USB是一个非常复杂的设备,linux内核为我们提供了一个称为USB的核心的子系统来处理大部分的复杂性,USB设备包括配置(configuration)、接口(interface)和端点(endpoint),USB设备绑定到接口上,而不是整个USB设备。
如下图所示:
USB通信最基本的形式是通过端点(USB端点分中断、批量、等时、控制四种,每种用途不同),USB端点只能往一个方向传送数据,从主机到设备或者从设备到主机,端点可以看作是单向的管道(pipe)。
所以我们可以这样认为:
设备通常具有一个或者更多的配置,配置经常具有一个或者更多的接口,接口通常具有一个或者更多的设置,接口没有或具有一个以上的端点。
驱动程序把驱动程序对象注册到USB子系统中,稍后再使用制造商和设备标识来判断是否已经安装了硬件。
USB核心使用一个列表(是一个包含制造商ID和设备号ID的一个结构体)来判断对于一个设备该使用哪一个驱动程序,热插拨脚本使用它来确定当一个特定的设备插入到系统时该自动装载哪一个驱动程序。
上面我们简要说明了驱动程序的基本理论,在写一个设备驱动程序之前,我们还要了解以下两个概念:
模块和设备文件。
模块:
是在内核空间运行的程序,实际上是一种目标对象文件,没有链接,不能独立运行,但是可以装载到系统中作为内核的一部分运行,从而可以动态扩充内核的功能。
模块最主要的用处就是用来实现设备驱动程序。
Linux下对于一个硬件的驱动,可以有两种方式:
直接加载到内核代码中,启动内核时就会驱动此硬件设备。
另一种就是以模块方式,编译生成一个.ko文件(在2.4以下内核中是用.o作模块文件,我们以2.6的内核为准,以下同)。
当应用程序需要时再加载到内核空间运行。
所以我们所说的一个硬件的驱动程序,通常指的就是一个驱动模块。
设备文件:
对于一个设备,它可以在/dev下面存在一个对应的逻辑设备节点,这个节点以文件的形式存在,但它不是普通意义上的文件,它是设备文件,更确切的说,它是设备节点。
这个节点是通过mknod命令建立的,其中指定了主设备号和次设备号。
主设备号表明了某一类设备,一般对应着确定的驱动程序;
次设备号一般是区分不同属性,例如不同的使用方法,不同的位置,不同的操作。
这个设备号是从/proc/devices文件中获得的,所以一般是先有驱动程序在内核中,才有设备节点在目录中。
这个设备号(特指主设备号)的主要作用,就是声明设备所使用的驱动程序。
驱动程序和设备号是一一对应的,当你打开一个设备文件时,操作系统就已经知道这个设备所对应的驱动程序。
对于一个硬件,Linux是这样来进行驱动的:
首先,我们必须提供一个.ko的驱动模块文件。
我们要使用这个驱动程序,首先要加载它,我们可以用insmodxxx.ko,这样驱动就会根据自己的类型(字符设备类型或块设备类型,例如鼠标就是字符设备而硬盘就是块设备)向系统注册,注册成功系统会反馈一个主设备号,这个主设备号就是系统对它的唯一标识。
驱动就是根据此主设备号来创建一个一般放置在/dev目录下的设备文件。
在我们要访问此硬件时,就可以对设备文件通过open、read、write、close等命令进行。
而驱动就会接收到相应的read、write操作而根据自己的模块中的相应函数进行操作了。
USB驱动程序实践
了解了上述理论后,我们就可以动手写驱动程序,如果你基本功好,而且写过linux下的硬件驱动,USB的硬件驱动和pci_driver很类似,那么写USB的驱动就比较简单了,如果你只是大体了解了linux的硬件驱动,那也不要紧,因为在linux的内核源码中有一个框架程序可以拿来借用一下,这个框架程序在/usr/src/~(你的内核版本,以下同)/drivers/usb下,文件名为usb-skeleton.c。
写一个USB的驱动程序最基本的要做四件事:
驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)(当然也可以不用urb来传输数据,下文我们会说到)。
驱动程序支持的设备:
有一个结构体structusb_device_id,这个结构体提供了一列不同类型的该驱动程序支持的USB设备,对于一个只控制一个特定的USB设备的驱动程序来说,structusb_device_id表被定义为:
/*驱动程序支持的设备列表*/
staticstructusb_device_idskel_table[]={
{USB_DEVICE(USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID)},
{}
/*终止入口*/
};
MODULE_DEVICE_TABLE(usb,skel_table);
对于PC驱动程序,MODULE_DEVICE_TABLE是必需的,而且usb必需为该宏的第一个值,而USB_SKEL_VENDOR_ID和USB_SKEL_PRODUCT_ID就是这个特殊设备的制造商和产品的ID了,我们在程序中把定义的值改为我们这款USB的,如:
/*定义制造商和产品的ID号*/
#defineUSB_SKEL_VENDOR_ID
0x1234
#defineUSB_SKEL_PRODUCT_ID
0x2345
这两个值可以通过命令lsusb,当然你得先把USB设备先插到主机上了。
或者查看厂商的USB设备的手册也能得到,在我机器上运行lsusb是这样的结果:
Bus004Device001:
ID0000:
0000
Bus003Device002:
ID1234:
2345
Abc
Corp.
Bus002Device001:
Bus001Device001:
0000
得到这两个值后把它定义到程序里就可以了。
注册USB驱动程序:
所有的USB驱动程序都必须创建的结构体是structusb_driver。
这个结构体必须由USB驱动程序来填写,包括许多回调函数和变量,它们向USB核心代码描述USB驱动程序。
创建一个有效的structusb_driver结构体,只须要初始化五个字段就可以了,在框架程序中是这样的:
staticstructusb_driverskel_driver={
.owner=
THIS_MODULE,
.name=
"
skeleton"
.probe=
skel_probe,
.disconnect=
skel_disconnect,
.id_table=
skel_table,
structmodule*owner:
指向该驱动程序的模块所有者的指针。
USB核心使用它来正确地对该USB驱动程序进行引用计数,使它不会在不合适的时刻被卸载掉,这个变量应该被设置为THIS_MODULE宏。
constchar*name:
指向驱动程序名字的指针,在内核的所有USB驱动程序中它必须是唯一的,通常被设置为和驱动程序模块名相同的名字。
int(*probe)(structusb_interface*intf,conststructusb_device_id*id):
这个是指向USB驱动程序中的探测函数的指针。
当USB核心认为它有一个接口(usb_interface)可以由该驱动程序处理时,这个函数被调用。
void(disconnect)(structusb_interface*intf):
指向USB驱动程序中的断开函数的指针,当一个USB接口(usb_interface)被从系统中移除或者驱动程序正在从USB核心中卸载时,USB核心将调用这个函数。
conststructusb_device_id*id_table:
指向ID设备表的指针,这个表包含了一列该驱动程序可以支持的USB设备,如果没有设置这个变量,USB驱动程序中的探测回调函数就不会被调用。
在这个结构体中还有其它的几个回调函数不是很常用,这里就不一一说明了。
以structusb_driver指针为参数的usb_register_driver函数调用把structusb_driver注册到USB核心。
一般是在USB驱动程序的模块初始化代码中完成这个工作的:
staticint__initusb_skel_init(void)
{
intresult;
/*驱动程序注册到USB子系统中*/
result=usb_register(&
skel_driver);
if(result)
err("
usb_registerfailed.Errornumber%d"
result);
returnresult;
}
当USB驱动程序将要被卸开时,需要把structusb_driver从内核中注销。
通过调用usb_deregister_driver来完成这个工作,当调用发生时,当前绑定到该驱动程序上的任何USB接口都被断开,断开函数将被调用:
staticvoid__exitusb_skel_exit(void)
/*从子系统注销驱动程序*/
usb_deregister(&
探测和断开:
当一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用,探测函数检查传递给它的设备信息,确定驱动程序是否真的适合该设备。
当驱动程序因为某种原因不应该控制设备时,断开函数被调用,它可以做一些清理工作。
探测回调函数中,USB驱动程序初始化任何可能用于控制USB设备的局部结构体,它还把所需的任何设备相关信息保存到一个局部结构体中,下面是探测函数的部分源码,我们加以分析
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 怎样 linux USB 设备 驱动程序