感激涕零造句/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.no_dynamic_id = 1,
};
前段时间写了篇<qualcomm usb modem驱动小结>的文章, 描述了自己如何为高通的一个usb modem设备写驱动的过程, 最近发现实际上可以使用linux自带的一个叫usbserial的模块作为这个modem的驱动并能良好的工作, 所以写了这片文章来详细的分析下usbserial模块的源码(2.6.16.3).
应该来说, 对于那些仅仅是用USB来通信, 在上层可看作tty设备, 不属于任何USB设备类型, 没有什么流控等的普通USB设备来说都可以使用这个驱动来作为设备驱动程序.下面就来对这样一种通用的驱动程序来进行详细的分析. 不对之处敬请指正!
为了能让usbserail模块支持我的设备, 我必须在命令行上输入如下命令:
sudo modprobe usbserial vendor=0x12d1 product=0x1003
该命令用特权用户来加载usbserial模块,并把该模块依赖的模块一并加载进系统, 同时它还设置了usbserial的两个参数: vendor, product, 很显然这两个参数是厂商ID和设备ID, 而作用就是用于匹配设备.
首先, 当然是要知道usbserial模块由哪些文件编译而成, 这样才能有目的性的去分析其代码. 而要知道其组成当然是去其目录下看Makefile了, 它位于内核源码目录下的./drivers/usb/serial/下原谅张玉华歌词
./drivers/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.o
usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o
usbserial-objs := usb-serial.o generic.o bus.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().
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_driver)
return -ENOMEM;
/* Initialize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {等不到天黑
serial_table[i] = NULL; //该模块共支持SERIAL_TTY_MINORS个该类型设备.
}
result = bus_register(&usb_serial_bus_type); //注册这条serial bus.
if (result) {
err("%s - registering bus driver failed", __FUNCTION__);
goto exit_bus;
}
//初始化tty_driver对象
usb_serial_tty_driver->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_serial_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_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驱动
if (result) {
err("%s - tty_register_driver failed", __FUNCTION__);
goto exit_reg_driver;
}
/* register the USB driver */
result = usb_register(&usb_serial_driver); //注册一个usb驱动
if (result < 0) {
err("%s - usb_register failed", __FUNCTION__);
goto exit_tty;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论