USB转串口驱动分析(一)

之前追踪代码用的grep命令效率太低了,所以这次下载C代码阅读跳转利器ctags、cscope用于分析代码

因为用的是Centos6.7所以需要用到yum install安装软件

[wuyujun@wuyujunlocalhost ~]$ sudo yum install ctags cscope

[wuyujun@wuyujunlocalhost ~]$ vim ~/.bashrc

#在最后加上两行,做命令的别名,建立索引文件只需输入tag即可

alias tag='cscope -Rbq && ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R .'

alias tagclean='rm -f cscope.* tags'

[wuyujun@wuyujunlocalhost ~]$ source ~/.bashrc

[wuyujun@wuyujunlocalhost linux-3.0]$ tag

[wuyujun@wuyujunlocalhost linux-3.0]$ ls tags cscope*

cscope.in.out  cscope.out  cscope.po.out  tags

这样tag索引文件就建立好了

用法:

ctags主要是用来创建Vim可以使用的tag索引文件,使用ctags -R 即可对当前目录下的代码递归建立索引文件,文件保存在当前目录下,默认文件名为tags,文件大小和你要索引的代码量有关。

Vim在运行过程中需要知道tag的索引文件位置,如果不指定的话,Vim会在当前目录下寻找名为tags的文件作为tag索引文件。如果想使用某个目录下的索引文件,在该目录下启动Vim即可。也可以在启动后通过如下命令设置或改变索引文件的位置:set tags=索引文件路径

  1. F4 左侧分屏列出该C文件中所有的变量,函数列表;再按一下取消左侧小窗口;
  2. Ctrl+WW 左右两侧之间切换,左侧函数列表窗口在某个函数上按回车就会回到右侧该函数的定义处;
  3. Ctrl+] 光标放在某个宏,变量,函数上,按这两个键可以查看他们的定义
  4. CTRL+T 返回刚才的查找
  5. CTRL+\然后迅速按S 光标放在某个宏,变量,函数上,快速按这三个组合键可以查看它们所有出现的地方

USB转串口驱动分析

USB驱动存在于不同的子系统,块设备(U盘)、字符设备层(键盘)、TTY层(USB转串口)...

在这里要分析的是USB转串口的驱动,首先,要知道usbserial模块由哪些文件编译而成,这样才能有目的性的去分析其代码. 而要知道其组成当然是去其目录下看Makefile了,它位于内核源码目录下的./drivers/usb/serial/

1 #

2 # Makefile for the USB serial device drivers.

3 #

4

5 # Object file lists.

6

7 obj-$(CONFIG_USB_SERIAL)            += usbserial.o  #编译内核时如何编译该模块

8

9 usbserial-y := usb-serial.o generic.o bus.o #usbserial模块的组成

10

11 usbserial-$(CONFIG_USB_SERIAL_CONSOLE)  += console.o

12 usbserial-$(CONFIG_USB_EZUSB)       += ezusb.o

13

14 obj-$(CONFIG_USB_SERIAL_AIRCABLE)       += aircable.o

15 obj-$(CONFIG_USB_SERIAL_ARK3116)        += ark3116.o

16 obj-$(CONFIG_USB_SERIAL_BELKIN)         += belkin_sa.o

 .......

重点需要看的是usb-serial.c,  generic.c, bus.c

1、usb-serial.c 就是usbserial模块的核心, 它主要用来接收设备端发来的数据并传送到上层, 同时也接收来自上层应用的数据,并组装成urb包发送给设备.

 

2、generic.c 对特定设备单独的操作,相当于是设备自己的驱动程序, 由于很多设备具有通用性, 所以对于没有特殊要求的设备都可以使用这个驱动来作为自己设备的驱动程序. 它有两个参数vendor和product,厂商ID和设备ID, 用于匹配设备.

 

3、bus.c  每个usb驱动和设备都必须要归入某一条总线上, 即都是归属于某条总线的,只有这样系统才能从特定一条总线开始找到每个驱动和设备并为他们匹配. 这个文件就是用来模拟一条总线, 而usbserial的每个驱动和设备都会注册到这条总线上来.

 

按照惯例,看驱动代码都是先从module_init开始看,虽说安装了ctags阅读代码利器,但是一开始也需要先找到对应的c代码才能进行结构体、变量、函数的跳转追踪,还是熟悉的grep

[wuyujun@wuyujunlocalhost linux-3.0]$ grep -n usb_serial_init -r ./

./tags:1682029:usb_serial_init  drivers/usb/serial/usb-serial.c /^module_init(usb_serial_init);$/;"     v

./tags:1682030:usb_serial_init  drivers/usb/serial/usb-serial.c /^static int __init usb_serial_init(void)$/;"   f       file:

匹配到二进制文件 ./.tmp_vmlinux1

匹配到二进制文件 ./vmlinux

匹配到二进制文件 ./arch/arm/boot/Image

./.tmp_System.map:518:c0018a2c t usb_serial_init

./.tmp_System.map:974:c001ec40 t __initcall_usb_serial_init6

./System.map:518:c0018a2c t usb_serial_init

./System.map:974:c001ec40 t __initcall_usb_serial_init6

匹配到二进制文件 ./vmlinux.o

匹配到二进制文件 ./drivers/usb/serial/usbserial.o

匹配到二进制文件 ./drivers/usb/serial/built-in.o

./drivers/usb/serial/usb-serial.c:1218:static int __init usb_serial_init(void)

./drivers/usb/serial/usb-serial.c:1310:module_init(usb_serial_init);

./drivers/usb/serial/ftdi_sio.c:1808:   /* Termios defaults are set by usb_serial_init. We don't change

匹配到二进制文件 ./drivers/usb/serial/usb-serial.o

匹配到二进制文件 ./drivers/usb/built-in.o

匹配到二进制文件 ./drivers/built-in.o

匹配到二进制文件 ./.tmp_vmlinux2

module_init(usb_serial_init);在./drivers/usb/serial/usb-serial.c

struct tty_driver *usb_serial_tty_driver; //usb_serial_tty_driver是tty_driver结构体类型的指针, 对应的tty设备的驱动.

 

static int __init usb_serial_init(void)

{

    int i;

    int result;

 

    usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS)//创建tty结构函数

    if (!usb_serial_tty_driver)

        return -ENOMEM;

 

    /* Initialize our global data */

    for (i = 0; i < SERIAL_TTY_MINORS; ++i) //该模块共支持SERIAL_TTY_MINORS个该类型设备.

        serial_table[i] = NULL;

 

    result = bus_register(&usb_serial_bus_type);//注册usb_serial_bus_type类型的总线

    if (result) {

        printk(KERN_ERR "usb-serial: %s - registering bus driver "

               "failed\n", __func__);

        goto exit_bus;

    }    

 

    usb_serial_tty_driver->owner = THIS_MODULE; //驱动模块拥有者

    usb_serial_tty_driver->driver_name = "usbserial"; //用来在/proc/tty/drivers文件中向用户描述驱动程序的状态,并且在sysfs的tty类目录中显示当前被加载的tty驱动程序

    usb_serial_tty_driver->name =   "ttyUSB"; //分配给单独tty结点的名字,通过在该名字末尾添加tty设备序号来创建tty设备

    usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; //设置主设备号

    usb_serial_tty_driver->minor_start = 0; //次设备号开始的序号

    usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; //设置tty驱动类型,可分控制台、串口和pty,这里是串口驱动

usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;//描述向tty核心注册的是何种tty驱动,SERIAL_TYPE_NORMAL可以被串行类设备使用

    usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |

                        TTY_DRIVER_DYNAMIC_DEV; //表明驱动状态和类型

    usb_serial_tty_driver->init_termios = tty_std_termios; //termios提供一系列串口的设置值    usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD

                            | HUPCL | CLOCAL; //设置串口默认配置

    usb_serial_tty_driver->init_termios.c_ispeed = 9600; //串口输入波特率

    usb_serial_tty_driver->init_termios.c_ospeed = 9600; //串口输出波特率

    tty_set_operations(usb_serial_tty_driver, &serial_ops); //赋值tty设备的操作集合,操作函数在serial_ops中定义

    result = tty_register_driver(usb_serial_tty_driver); //串口驱动注册,在之前的博客串口驱动分析说到过

    if (result) {

        printk(KERN_ERR "usb-serial: %s

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值