N0.5
Oct..2OO8
微 处 理 机
MICROPROCESSORS
第5期
2oo8年10月
Linux2.6内核的 USB鼠标驱动开发
杨春霞,王 自强
(南京大学电子
工程
路基工程安全技术交底工程项目施工成本控制工程量增项单年度零星工程技术标正投影法基本原理
系,南京 21OO93)
摘 要: .6内核较先前版本有很大程度的修改。首先介绍2.6内核的设备模型以及驱动编
写上的变化,然后介绍 uSB设备,以鼠标为例重点说明uSB驱动程序的实现。
关键词:Linux系统;内核 2.6;USB(通用串行总线);设备驱动
中图分类号:TP316 文献标识码:A 文章编号:1002—2279(2008)O5一O094—03
The USB MOuse D riVer Pr0gramming based On Kernel一2.6 in Linux
YANG Chun—xia, ANG Zi—qiang
(D t. E c加n c&Eng e ,Ⅳ口 , 210o93, na)
Abstract:The Linux kemel Version 2.6 has modi6ed a lot. 11his p印 er fisrt introduces the Linux
device module and the changes of.driver p ogr舢 ming based on kemel一2.6, then intmduces USB
devices.We will emphasis on exp1aining the implementation of the USB driVer th the examp1e 0f USB
m 0USe.
Ke】 wOrds:Linux;Kemel versio玎2.6;USB;DeVice DdVer
1 前 言
uSB(通用串行总线)是一种应用广泛的接口技
术,它具备诸如支持热插拔,传输速度快且稳定,低
耗能等优点。usB现在可以支持几乎所有可以连接
到Pc上的设备。目前已成为微机与外围设备通信
的首选接口。
Linux系统自发布以来,因其安全,高效,灵活,
经济等特点受到越来越广泛的关注,目前稳定的内
核版本是2.6。2.6内核和以前的内核版本相比进
行了很大程度的修改,这意味着内核的内部编程接
口可能会发生变化,因此 2.6内核的驱动开发也和
较早版本有所区别。
下面主要讨论基于 2.6内核的 uSB设备驱动
开发,并以鼠标为例来实现。
2 2.6内核的系统模型概述
以前的内核中没有用来让内核获得系统整体配
合信息的数据结构,而随着拓扑结构越来越复杂,需
要有一个对系统结构的一般性抽象描述,2.6版内
核的设备模型提供了这样的抽象描述。LinuX设备
模型是个复杂的数据结构,图一是系统模型的一个
小片段,与usB鼠标相关联的设备模型的一部分。
设备树
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
明了鼠标是如何连接到系统的,总线树跟
踪了连接到每个总线的设备,类树表明设备提供的
功能。对大部分模型,Linux设备模型代码会很好的
处理这些关系,而不会强加给驱动程序的编写者。
图1 与usB鼠标相关联的设备模型片断
基于2。6版本的内核构造模块也和较早的版本
有所区别,在早期版本中构造内核模块只需要一套内
核头文件,而2.6内核模块要和内核源代码树种的
目标文件连接,所以必须在自己的系统中配置并构
造好内核树。这样可以得到更加健壮的模块装载。
作者简介:杨春霞(1981一),女,沈阳人,硕士研究生,主研方向:嵌入式系统
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
。
收稿 日期:2oo6一o4—24
5期 杨春霞等:Linu)(2.6内核的usB鼠标驱动开发 ·95·
3 USB系统介绍及通信
usB采用四线电缆,其中两根是用来传送数据
的串行通道,另两根为设备提供电源。最新的 usB
规范修订增加了高达48OMbps的高速连接。
usB系统采用级联星型拓扑,该拓扑由三个基
本部分组成:主机(H0st),集线器 (Hub)和功能设
备。usB主控制器负责询问每个 usB设备是否有
数据需要发送。
每一个 usB设备的结构(如图2)会有~个或
者多个逻辑连接点,称为端口。每个端 口有 4种数
据传送方式:控制方式;等时方式 ;中断方式和大量
方式。端口O用来传送配置和控制信息。
雌 画
设备 I
图 2 USB设备结构
在主机和设备端口之间的连接叫作管道,与端
口0连接的一般称作缺省管道。一组端口的组合叫
做接口,如果一个设备包含不止一个的接 口就可以
称之为复合设备。接口的组合称之为配置。每次只
能有一个配置是可用的,而一旦该配置激活,里面的
接口和端口就都同时可以使用。主机从设备发过来
的描述符中来判断用的是哪个配置,哪个接口,这些
描述字通常是在端口O中传送的。
usB和核心的通信是通过 uSB Request Bl0ck
即urb进行的。Linux的 uSB子系统只使用这么一
种数据结构来进行 usB通信,urb包含了建立任何
usB传输所需的所有信息,并贯穿于 usB协议栈对
数据处理的整个过程。urb由usB设备驱动程序创
建,并分配给一个特定的usB设备端口,由usB设
备驱动程序递交到uSB核心,再由uSB核心递交到
特定设备的usB主控器驱动程序,并由usB主控器
驱动程序处理,它和从设备进行 usB传送。当urb
结束后,usB主控制器驱动程序通知uSB设备驱动
程序。使用stⅢct urb结构体来描述。该结构主要
字段如下所示:
stI1lct urb{
sⅡuct usb-device dev;/ 相应的UsB设备指针
unsi 坨d int pipe;/ 端口信息%/
int status;/ 返回的状态信息,Ic/
void 缸彻sfe u ;/ 指向相关数据缓冲区:}:/
int fler_-1)u艉rJengt}l;/ 数据缓冲区大小 /
int actualjength;/ 返回的实际数据大小 /
int imen ;/ 被轮询的时间间隔$/
v0id c0ntext;/ 在结束例程中使用的数据块 /
usb_coⅡlpIetej complete;/ 结束例程函数指针 /
};
在urb被提交前,以上字段及相关字段要被正
确初始化,在第四部分的驱动程序编写中将作进一
步介绍。
4 编写USB鼠标驱动程序
4.1 注册和注销 USB驱动程序
向usB核心子系统注册和注销 usB驱动程序
时使用函数usb_register和 usD—dere百ster,其中注册
驱动程序必须在初始化时进行。具体用法如下:int
usb
— register(stI1Jct usD一 ver dnr);其功能是把
stm ct usD
— driver注册到 USB核心,若注册成功则返
回O,若失败则返回错误值。相关代码如下:
static int
— jnit usbJmousejnit(void)
· {
int result=O:
result=usb-j ster(&mouse—ddver);
if(result)
eH(”usD—re西steT failed.EⅡ0r叫mber%d’.,
result);
printk(”re ster OK\n”);
retum result;
}
其中struct usD一 ver是所有驱动程序必须创
建的结构体,由usB驱动程序填写。主要的相关字
段填写及代码如下:
static stmct usb— ddver mouse— driver={
. owner=THIS
— MODuLE,//指向驱动程序的模
块所有者的指针
. name=”mymouse”,//指向驱动程序名字的指
针
. id_tab1e=m0use
一 le,//指向一个 stⅢct usD—
device—id表,该表包含程序可以支持的所有不同类
型的USB设备
.probe=mouse_probe,//指向uSB驱动程序中探
测函数的指针
. disconnect=mouse
— disconnect,//指向usB驱动
程序中断开函数的指针
· 96· 微 处 理 机 2o08年
};
当usB被卸载时调用 usD—deregister来完成
struct usD
— driver从内核注销的工作。
usb
— deregister(&mouse—driVer);
4.2 探测和断开
在 stmct usD一 ver结构体中有两个重要的字
段,即上面提到的 pmbe和 disconnect,分别指定了
usB核心要调用的探测和断开函数。当 uSB核心
认为一个被安装的设备应该使用该驱动程序处理
时,调用探测函数,检查设备信息,确定驱动程序是
否适合该设备;当驱动程序不再控制设备时,调用断
开函数来做一些清理工作。
探测和断开函数的原型:
int(术pr0be) (stmct usb—inted.aee 米intf,const
truct usb
—
device
— id $id)
如果usB驱动程序确认传递指针,则应恰当的
初始化设备然后返回O,否则返回错误值。
void(冰disconnect)(struct usb—interface木intf)
usB驱动程序应该在探测回调函数中初始化可
能用于控制 usB设备的局部结构体。通常需要探
测设备的端口地址和缓冲区大小,因为需要它们才
能和设备通信。对于鼠标驱动程序来说,首先要访
问端口,查看端口的方向,类型,这是通过查看 stmct
usb_endp0int_descript0r的bEndpointAddress和 bmAt—
t utes的值是否匹配来完成的。相关代码如下:
dev一 >udev = usb
— get—dev(inteIface—t0一usbdev
(inte如ce));
dev一 >inteIface = inttj—-ace:
iflace_desc = inted.ace一 >cur--altsetting;
if(iface—desc一>desc.bNumEndpoints! =1)
retum —ENOMEM:
endpoint= &iflace
— desc一>endp0int[O].desc;
if(!(endpoint一>bEndpointAddress&0x80))
retum —ENOMEM:
if((endpoint一>blnAttdbutes&3)! =3)
retum —ENOMEM :
pipe :usb_.rcvintpipe(dev一>udeV,endpoint一>
bEndp0intAddI.ess);
maxp = usb
— maxpacket(deV一>udeV,pipe,usb—
pipe0ut(pipe));
if(ma)【p>8)maxp=8;
dev一 >maxp = maxp;
在断开函数中设置stmct usD_interface结构体中
的数据指针为 NULL。
usD
—
seI
— intfdata(inter£ace,NU【JL);
4.3 使用 urb通信
1)urb的创建和初始化
stmct urb使用 usn—alloc—urb函数来分配。该
函数有两个参数,第一个参数在不创建同步urb时
设置为O。第二个参数用于从内核分配内存,可以
使用GFP—KERNEL等标志。
鼠标使用中断端 口,用 usD—fiU—im—urb函数初
始化。这与在以前版本中的初始化方法不同。该函
数的原形如下,参数对应于 urb的相关字段,这在第
三部分的usB通信中作过介绍。
usb
— _fiU_int—urb(stmct urb urb,stI1lct usD—de—
vice 术dev,unsigned int pipe,void 串transfler
—
buflfer,
int buflfer
—
Ieng山,usb
—
compIete
—
t complete,void 水
context,int interva1)
complete为结束当前 urb后调用的处理函数指
针,在本文的鼠标驱动中回调函数为mouse—irq,保
存context指向的数据块以便在结束例程中进行查
找。
相关代码如下:
urb = usb
—
aUoc
— urb(O,GFP—KERNEL);
usb
—
fiU
—
int
— urb(urb,dev一>udev,pipe,dev一>
data,maxp,mouse-irq,
dev,endpoint一>bIntenra1);
2)提交和结束
使用usD—submit—urb函数将 urb提交到 usB核
心,以传输到设备。
if(usb—submit—llrb(urb,GFP—KERNEL))
{
kfree(dev);
g0t0 eHDr;
}
成功后 usB核心调用urb回调函数啪use-irq,
回调函数要检查 urb的状态,以确定传输是否真的
成功。如果状态值为0,即成功,最后,使用内核输
人函数报告鼠标状态。
5 总 结
Linux的发展非常迅速,本文通过一个 usB鼠
标来说明基于2.6内核的uSB设备驱动程序的写
法和应用,并使用 ntk函数进行调试,使用gpm命
令配置 鼠标和测试程序。本文的编写希望对
linuX2.6内核其他相关 uSB设备的开发有所启示。
参考文献:
[1] AlessarIdm Rub .Linu)【Device Drivers[M].北京:中
国电力出版社,20o5.
[2] Don Anders0n,Dave Dz 【ko.usB体系结构[M],北京:
中国电力出版社,20o3.