通用USB设备驱动源码分析Word文档格式.docx
- 文档编号:21385908
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:40
- 大小:38.65KB
通用USB设备驱动源码分析Word文档格式.docx
《通用USB设备驱动源码分析Word文档格式.docx》由会员分享,可在线阅读,更多相关《通用USB设备驱动源码分析Word文档格式.docx(40页珍藏版)》请在冰豆网上搜索。
obj-$(CONFIG_USB_SERIAL)
+=usbserial.o
#编译内核时如何编译该模块
usbserial-obj-$(CONFIG_USB_SERIAL_CONSOLE)
+=console.o
usbserial-obj-$(CONFIG_USB_EZUSB)
+=ezusb.o
usbserial-objs
:
=usb-serial.ogeneric.obus.o$(usbserial-obj-y)
#OK,
就是usbserial模块的组成了.
obj-$(CONFIG_USB_SERIAL_AIRPRIME)
+=airprime.o
obj-$(CONFIG_USB_SERIAL_ANYDATA)
+=anydata.o
.......
我们重点看的是usb-serial.c,
generic.c,bus.c
在看源码之前我们先说说该模块的原理及整体结构:
很简单跟应用层交互的是一个tty设备,
也就是说该模块把USB设备映射成一个tty设备(即在/dev/目录下为该USB设备创建一个tty设备文件),
然后用于可以用minicom之类的串口工具来打开这个设备,
并同设备端的设备通信.
对于发送过程:
tty设备文件在获取了用户要求发送的数据之后传递到下层usbserial模块的核心层,而该核心层就是将数据打包成USB格式的数据并由USB通信发送到设备端去,
对于接收过程:
usbserial模块会在该设备打开时就启动一个urb在那等待设备端发数据过来,
收到数据后就push到上层tty设备的缓冲中去,
而tty设备在收到数据后就会给用户,或直接显示在minicom之类的工具上.
usb-serial.c
就是usbserial模块的核心,
它主要用来接收设备端发来的数据并传送到上层,
同时也接收来自上层应用的数据,并组装成urb包发送给设备.
generic.c
对特定设备单独的操作,相当于是设备自己的驱动程序,
由于很多设备具有通用性,
所以对于没有特殊要求的设备都可以使用这个驱动来作为自己设备的驱动程序.
它有两个参数vendor和product,上面提过了.
bus.c
每个usb驱动和设备都必须要归入某一条总线上,
即都是归属于某条总线的,只有这样系统才能从特定一条总线开始找到每个驱动和设备并为他们匹配.
这个文件就是用来模拟一条总线,
而usbserial的每个驱动和设备都会注册到这条总线上来.
好了,是时候分析usbserial模块了.
我们知道当把一个模块加载进系统时会调用这个模块里的一个由module_init()声明的一个初始化函数.usbserial当然也不另外,
usb-serial.c:
module_init(usb_serial_init);
module_exit(usb_serial_exit);
没错加载时调用的就是:
usb_serial_init().
structtty_driver*usb_serial_tty_driver;
staticint__initusb_serial_init(void)
{
inti;
intresult;
//创建一个tty_driver对象,
对应的就是tty设备的驱动.
usb_serial_tty_driver=alloc_tty_driver(SERIAL_TTY_MINORS);
if(!
usb_serial_tty_driver)
return-ENOMEM;
/*Initializeourglobaldata*/
for(i=0;
i<
SERIAL_TTY_MINORS;
++i){
serial_table[i]=NULL;
//该模块共支持SERIAL_TTY_MINORS个该类型设备.
}
result=bus_register(&
usb_serial_bus_type);
//注册这条serialbus.
if(result){
err("
%s-registeringbusdriverfailed"
__FUNCTION__);
gotoexit_bus;
//初始化tty_driver对象
usb_serial_tty_driver->
owner=THIS_MODULE;
driver_name="
usbserial"
;
devfs_name="
usb/tts/"
name=
"
ttyUSB"
//tty设备文件名以这个开头,后加0,1,2,3,....
major=SERIAL_TTY_MAJOR;
//主设备号
minor_start=0;
type=TTY_DRIVER_TYPE_SERIAL;
//设备类型
subtype=SERIAL_TYPE_NORMAL;
flags=TTY_DRIVER_REAL_RAW|TTY_DRIVER_NO_DEVFS;
init_termios=tty_std_termios;
init_termios.c_cflag=B9600|CS8|CREAD|HUPCL|CLOCAL;
//赋值tty设备的操作集合,即应用层调用open时最终会调到serial_ops->
open里面
tty_set_operations(usb_serial_tty_driver,&
serial_ops);
result=tty_register_driver(usb_serial_tty_driver);
//注册这个tty驱动
%s-tty_register_driverfailed"
gotoexit_reg_driver;
/*registertheUSBdriver*/
result=usb_register(&
usb_serial_driver);
//注册一个usb驱动
if(result<
0){
%s-usb_registerfailed"
gotoexit_tty;
/*registerthegenericdriver,ifweshould*/
result=usb_serial_generic_register(debug);
//注册generic驱动程序
%s-registeringgenericdriverfailed"
gotoexit_generic;
info(DRIVER_DESC);
returnresult;
//失败时候的一些反向操作
exit_generic:
usb_deregister(&
exit_tty:
tty_unregister_driver(usb_serial_tty_driver);
exit_reg_driver:
bus_unregister(&
exit_bus:
err("
%s-returningwitherror%d"
__FUNCTION__,result);
put_tty_driver(usb_serial_tty_driver);
该函数先创建并初始化好了一个tty_driver的对象,
并把该对象注册进系统,
该对象就是tty设备的驱动程序,
后面我们会看到他是如何于具体tty设备绑定在一起的.
usb_serial.c:
staticstructtty_operationsserial_ops={
.open=
serial_open,
.close=
serial_close,
.write=
serial_write,
.write_room=
serial_write_room,
.ioctl=
serial_ioctl,
.set_termios=
serial_set_termios,
.throttle=
serial_throttle,
.unthrottle=
serial_unthrottle,
.break_ctl=
serial_break,
.chars_in_buffer=
serial_chars_in_buffer,
.read_proc=
serial_read_proc,
.tiocmget=
serial_tiocmget,
.tiocmset=
serial_tiocmset,
};
这个就是tty设备文件对应的操作方法集合,
例如,
应用层调用open函数来打开该设备文件时将最终会走到serial_open里面.
usb_serial_init()
还注册了一条总线:
usb_serial_bus_type,
这样当有设备连上系统时,
该总线上的驱动就有机会去匹配这个设备.
后面我们会看到generic的驱动就是注册在该总线上的.
bus.c:
structbus_typeusb_serial_bus_type={
.name=
usb-serial"
.match=
usb_serial_device_match,
//在设备匹配时会调用
.probe=
usb_serial_device_probe,
.remove=
usb_serial_device_remove,
关于设备匹配过程(probe)可以参考我的另一篇文章.
在最后usb_serial_generic_register(debug)来注册generic驱动.
generic.c:
intusb_serial_generic_register(int_debug)
intretval=0;
debug=_debug;
#ifdefCONFIG_USB_SERIAL_GENERIC
generic_device_ids[0].idVendor=vendor;
//保存厂商ID
generic_device_ids[0].idProduct=product;
//保存产品ID
generic_device_ids[0].match_flags=USB_DEVICE_ID_MATCH_VENDOR|USB_DEVICE_ID_MATCH_PRODUCT;
//匹配类型
/*registerourgenericdriverwithourselves*/
retval=usb_serial_register(&
usb_serial_generic_device);
//注册驱动
if(retval)
gotoexit;
retval=usb_register(&
generic_driver);
usb_serial_deregister(&
exit:
#endif
returnretval;
该函数首先保存了命令通过命令行设备的vendor,product
用于以后设备匹配,
由此我们知道该驱动可以动态支持设备匹配.
接着该函数注册了usb_serial_generic_device驱动.
structusb_serial_driverusb_serial_generic_device={
.driver={
.owner=
THIS_MODULE,
generic"
},
.id_table=
generic_device_ids,
//匹配用的设备列表,
支持动态匹配
.num_interrupt_in=
NUM_DONT_CARE,
.num_bulk_in=
.num_bulk_out=
.num_ports=
1,
.shutdown=
usb_serial_generic_shutdown,
Usb-serial.c:
intusb_serial_register(structusb_serial_driver*driver)
intretval;
fixup_generic(driver);
//为driver赋上默认的操作函数
driver->
description)
description=driver->
driver.name;
/*Addthisdevicetoourlistofdevices*/
list_add(&
driver_list,&
usb_serial_driver_list);
//加入驱动列表
retval=usb_serial_bus_register(driver);
//把该驱动注册进usbserialbus下
if(retval){
problem%dwhenregisteringdriver%s"
retval,driver->
description);
list_del(&
driver_list);
else
info("
USBSerialsupportregisteredfor%s"
driver->
其中的fixup_generic()函数仅仅是为driver赋上默认的操作函数.
#defineset_to_generic_if_null(type,function)
\
do{
type->
function){
function=usb_serial_generic_##function;
dbg("
Hadtooverridethe"
#function
usbserialoperationwiththegenericone."
);
}
}while(0)
staticvoidfixup_generic(structusb_serial_driver*device)
set_to_generic_if_null(device,open);
set_to_generic_if_null(device,write);
set_to_generic_if_null(device,close);
set_to_generic_if_null(device,write_room);
set_to_generic_if_null(device,chars_in_buffer);
set_to_generic_if_null(device,read_bulk_callback);
set_to_generic_if_null(device,write_bulk_callback);
set_to_generic_if_null(device,shutdown);
即通过上面的usb_serial_register()函数后usb_serial_generic_device的函数集为:
usb_serial_generic_device.open=usb_serial_generic_open;
usb_serial_generic_device.close=usb_serial_generic_close
......
驱动usb_serial_generic_device将是以后操作tty设备的主要函数.我们会在后面分析.
intusb_serial_bus_register(structusb_serial_driver*driver)
driver.bus=&
usb_serial_bus_type;
//注册到该bus下
retval=driver_register(&
driver);
最后usb_serial_generic_register()函数注册了一个generic_driver驱动.
staticstructusb_drivergeneric_driver={
usbserial_generic"
generic_probe,
//匹配函数
.disconnect=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 通用 USB 设备 驱动 源码 分析