1、通用USB设备驱动源码分析通用USB设备驱动源码分析Author:aaron前段时间写了篇的文章,描述了自己如何为高通的一个usb modem设备写驱动的过程,最近发现实际上可以使用linux自带的一个叫usbserial的模块作为这个modem的驱动并能良好的工作,所以写了这片文章来详细的分析下usbserial模块的源码(2.6.16.3).应该来说,对于那些仅仅是用USB来通信,在上层可看作tty设备,不属于任何USB设备类型,没有什么流控等的普通USB设备来说都可以使用这个驱动来作为设备驱动程序.下面就来对这样一种通用的驱动程序来进行详细的分析.不对之处敬请指正!为了能让usbsera
2、il模块支持我的设备,我必须在命令行上输入如下命令:sudo modprobe usbserial vendor=0x12d1 product=0x1003该命令用特权用户来加载usbserial模块,并把该模块依赖的模块一并加载进系统,同时它还设置了usbserial的两个参数: vendor, product,很显然这两个参数是厂商ID和设备ID,而作用就是用于匹配设备.首先,当然是要知道usbserial模块由哪些文件编译而成,这样才能有目的性的去分析其代码.而要知道其组成当然是去其目录下看Makefile了,它位于内核源码目录下的./drivers/usb/serial/下./driv
3、ers/usb/serial/Makefile:# Makefile for the USB serial device drivers.# Object file lists.obj-$(CONFIG_USB_SERIAL)+= usbserial.o#编译内核时如何编译该模块usbserial-obj-$(CONFIG_USB_SERIAL_CONSOLE)+= console.ousbserial-obj-$(CONFIG_USB_EZUSB)+= ezusb.ousbserial-objs:= usb-serial.o generic.o bus.o $(usbserial-obj-y
4、)#OK,就是usbserial模块的组成了.obj-$(CONFIG_USB_SERIAL_AIRPRIME)+= airprime.oobj-$(CONFIG_USB_SERIAL_ANYDATA)+= anydata.o.我们重点看的是usb-serial.c,generic.c, bus.c在看源码之前我们先说说该模块的原理及整体结构:很简单跟应用层交互的是一个tty设备,也就是说该模块把USB设备映射成一个tty设备(即在/dev/目录下为该USB设备创建一个tty设备文件),然后用于可以用minicom之类的串口工具来打开这个设备,并同设备端的设备通信.对于发送过程: tty设备文
5、件在获取了用户要求发送的数据之后传递到下层usbserial模块的核心层,而该核心层就是将数据打包成USB格式的数据并由USB通信发送到设备端去,对于接收过程: usbserial模块会在该设备打开时就启动一个urb在那等待设备端发数据过来,收到数据后就push到上层tty设备的缓冲中去,而tty设备在收到数据后就会给用户,或直接显示在minicom之类的工具上.usb-serial.c就是usbserial模块的核心,它主要用来接收设备端发来的数据并传送到上层,同时也接收来自上层应用的数据,并组装成urb包发送给设备.generic.c对特定设备单独的操作,相当于是设备自己的驱动程序,由于很
6、多设备具有通用性,所以对于没有特殊要求的设备都可以使用这个驱动来作为自己设备的驱动程序.它有两个参数vendor和product,上面提过了.bus.c每个usb驱动和设备都必须要归入某一条总线上,即都是归属于某条总线的,只有这样系统才能从特定一条总线开始找到每个驱动和设备并为他们匹配.这个文件就是用来模拟一条总线,而usbserial的每个驱动和设备都会注册到这条总线上来.好了,是时候分析usbserial模块了.我们知道当把一个模块加载进系统时会调用这个模块里的一个由module_init()声明的一个初始化函数. usbserial当然也不另外,usb-serial.c:module_i
7、nit(usb_serial_init);module_exit(usb_serial_exit);没错加载时调用的就是:usb_serial_init().usb-serial.c:struct tty_driver *usb_serial_tty_driver;static int _init usb_serial_init(void)int i;int result;/创建一个tty_driver对象,对应的就是tty设备的驱动.usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);if (!usb_serial_tty_
8、driver)return -ENOMEM;/* Initialize our global data */for (i = 0; i owner = THIS_MODULE;usb_serial_tty_driver-driver_name = usbserial;usb_serial_tty_driver-devfs_name = usb/tts/;usb_serial_tty_driver-name =ttyUSB;/tty设备文件名以这个开头,后加0,1,2,3,.usb_serial_tty_driver-major = SERIAL_TTY_MAJOR;/主设备号usb_seria
9、l_tty_driver-minor_start = 0;usb_serial_tty_driver-type = TTY_DRIVER_TYPE_SERIAL;/设备类型usb_serial_tty_driver-subtype = SERIAL_TYPE_NORMAL;usb_serial_tty_driver-flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;usb_serial_tty_driver-init_termios = tty_std_termios;usb_serial_tty_driver-init_termios.c_c
10、flag = 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驱动if (result) err(%s - tty_register_driver failed, _FUNCTION_);goto exit_reg_driver;/* registe
11、r the USB driver */result = usb_register(&usb_serial_driver);/注册一个usb驱动if (result 0) err(%s - usb_register failed, _FUNCTION_);goto exit_tty;/* register the generic driver, if we should */result = usb_serial_generic_register(debug);/注册generic驱动程序if (result description)driver-description = driver-dri
12、ver.name;/* Add this device to our list of devices */list_add(&driver-driver_list, &usb_serial_driver_list);/加入驱动列表retval = usb_serial_bus_register(driver);/把该驱动注册进usb serial bus下if (retval) err(problem %d when registering driver %s, retval, driver-description);list_del(&driver-driver_list);elseinfo
13、(USB Serial support registered for %s, driver-description);return retval;其中的fixup_generic()函数仅仅是为driver赋上默认的操作函数.Usb-serial.c:#define set_to_generic_if_null(type, function)do if (!type-function) type-function = usb_serial_generic_#function;dbg(Had to override the #function usb serial operation with
14、the generic one.); while (0)static void fixup_generic(struct usb_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_ge
15、neric_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_ge
16、neric_close.驱动usb_serial_generic_device将是以后操作tty设备的主要函数.我们会在后面分析.bus.c:int usb_serial_bus_register(struct usb_serial_driver *driver)int retval;driver-driver.bus = &usb_serial_bus_type;/注册到该bus下retval = driver_register(&driver-driver);return retval;最后usb_serial_generic_register()函数注册了一个generic_driver驱动.generic.c:static struct usb_driver generic_driver = .name =usbserial_generic,.probe =generic_probe,/匹配函数.disconnect =
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1