《Linux内核修炼之道》——分析内核源码如何入手?(上)

《Linux内核修炼之道》——分析内核源码如何入手?(上)

透过现象看本质,兽兽门无非就是一些人体艺术展示。同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的。

  既然要学习内核源码,就要经常对内核代码进行分析,而内核代码千千万,还前仆后继的不断往里加,这就让大部分人都有种雾里看花花不见的无助感。不过不要怕,孔老夫子早就留给我们了应对之策:敏于事而慎于言,就有道而正焉,可谓好学也已。这就是说,做事要踏实才是好学生好同志,要遵循严谨的态度,去理解每一段代码的实现,多问多想多记。如果抱着走马观花,得过且过的态度,结果极有可能就是一边看一边丢,没有多大的收获。

  假设全国房价上涨1.5%,假设80后局长是农民子弟,??,既然我们的人生充满了假设,那么我在这里假设你现在就迫不及待的希望研究内核中USB子系统的实现,应该没有意见吧?那好,下面就以USB子系统的实现分析为标本看看分析内核源码应该如何入手。

  分析README

  内核中USB子系统的代码位于目录drivers/usb,这个结论并不需要假设。于是我们进入到该目录,执行命令ls,结果显示如下:

  atm  class  core  gadget  host  image  misc  mon  serial  storage Kconfig 
Makefile  README usb-skeleton.c

  目录drivers/usb共包含有10个子目录和4个文件,usb-skeleton.c是一个简单的USB driver的框架,感兴趣的可以去看看,目前来说,它还吸引不了我们的眼球。那么首先应该关注什么?如果迎面走来一个ppmm,你会首先看脸、脚还是其它?当然答案依据每个人的癖好会有所不同。不过这里的问题应该只有一个答案,那就是Kconfig、Makefile、README。

  README里有关于这个目录下内容的一般性描述,它不是关键,只是帮助你了解。再说了,面对“read我吧read我吧”这么热情奔放的呼唤,善良的我们是不可能无动于衷的,所以先来看看里面都有些什么内容。

  23 Here is a list of what each subdirectory here is, and what is contained in
24 them.
25
26 core/        - This is for the core USB host code, including the
27             usbfs files and the hub class driver ("khubd").
28
29 host/        - This is for USB host controller drivers.  This
30             includes UHCI, OHCI, EHCI, and others that might
31             be used with more specialized "embedded" systems.
32
33 gadget/        - This is for USB peripheral controller drivers and
34             the various gadget drivers which talk to them.
35
36
37 Individual USB driver directories.  A new driver should be added to the
38 first subdirectory in the list below that it fits into.
39
40 image/        - This is for still image drivers, like scanners or
41             digital cameras.
42 input/        - This is for any driver that uses the input subsystem,
43             like keyboard, mice, touchscreens, tablets, etc.
44 media/        - This is for multimedia drivers, like video cameras,
45             radios, and any other drivers that talk to the v4l
46             subsystem.
47 net/        - This is for network drivers.
48 serial/        - This is for USB to serial drivers.
49 storage/    - This is for USB mass-storage drivers.
50 class/        - This is for all USB device drivers that do not fit
51             into any of the above categories, and work for a range
52             of USB Class specified devices.
53 misc/        - This is for all USB device drivers that do not fit
54             into any of the above categories.

  这个README文件描述了前边使用ls命令列出的那10个文件夹的用途。那么什么是USB Core?Linux内核开发者们,专门写了一些代码,负责实现一些核心的功能,为别的设备驱动程序提供服务,比如申请内存,比如实现一些所有的设备都会需要的公共的函数,并美其名曰USB Core。

  时代总在发展,当年胖杨贵妃照样迷死唐明皇,而如今人们欣赏的则是林志玲这样的魔鬼身材。同样,早期的Linux内核,其结构并不是如今天这般有层次感,远不像今天这般错落有致,那时候drivers/usb/这个目录下边放了很多很多文件,USB Core与其他各种设备的驱动程序的代码都堆砌在这里,后来,怎奈世间万千的变幻,总爱把有情的人分两端。于是在drivers/usb/目录下面出来了一个core目录,就专门放一些核心的代码,比如初始化整个USB系统,初始化Root Hub,初始化主机控制器的代码,再后来甚至把主机控制器相关的代码也单独建了一个目录,叫host目录,这是因为USB主机控制器随着时代的发展,也开始有了好几种,不再像刚开始那样只有一种,所以呢,设计者们把一些主机控制器公共的代码仍然留在core目录下,而一些各主机控制器单独的代码则移到host目录下面让负责各种主机控制器的人去维护。

  那么USB gadget那?gadget白了说就是配件的意思,主要就是一些内部运行Linux的嵌入式设备,比如PDA,设备本身有USB设备控制器(USB Device Controller),可以将PC,也就是我们的主机作为master端,将这样的设备作为slave端和主机通过USB进行通信。从主机的观点来看,主机系统的USB驱动程序控制插入其中的USB设备,而USB gadget的驱动程序控制外围设备如何作为一个USB设备和主机通信。比如,我们的嵌入式板子上支持SD卡,如果我们希望在将板子通过USB连接到PC之后,这个SD卡被模拟成U盘,那么就要通过USB gadget架构的驱动。

  剩下的几个目录分门别类的放了各种USB设备的驱动,比如U盘的驱动在storage目录下,触摸屏和USB键盘鼠标的驱动在input目录下,等等。

  我们响应了README的热情呼唤,它便给予了我们想要的,通过它我们了解了USB目录里的那些文件夹都有着什么样的角色。到现在为止,就只剩下内核的地图——Kconfig与Makefile两个文件了。有地图在手,对于在内核中游荡的我们来说,是件很愉悦的事情,不过,因为我们的目的是研究内核对USB子系统的实现,而不是特定设备或host controller的驱动,所以这里的定位很明显,USB Core就是我们需要关注的对象,那么接下来就是要对core目录中的内容进行定位了。

  分析Kconfig和Makefile

  进入到drivers/usb/core目录,执行命令ls,结果显示如下:

  Kconfig  Makefile  buffer.c  config.c  devices.c  devio.c  driver.c  
endpoint.c  file.c  generic.c  hcd-pci.c  hcd.c  hcd.h  hub.c  hub.h  
inode.c  message.c  notify.c  otg_whitelist.h  quirks.c  sysfs.c  urb.c  
usb.c  usb.h

  然后执行wc命令,如下所示。

  # wc –l ./*
   148 buffer.c
   607 config.c
   706 devices.c
  1677 devio.c
  1569 driver.c
   357 endpoint.c
   248 file.c
   238 generic.c
  1759 hcd.c
   458 hcd.h
   433 hcd-pci.c
  3046 hub.c
   195 hub.h
   758 inode.c
   144 Kconfig
    21 Makefile
  1732 message.c
    68 notify.c
   112 otg_whitelist.h
   161 quirks.c
   710 sysfs.c
   589 urb.c
   984 usb.c
   160 usb.h
16880 total

 drivers/usb/core目录共包括24个文件,16880行代码。core不愧是core,为大家默默的做这么多事。不过这么多文件里不一定都是我们所需要关注的,先拿咱们的地图来看看接下来该怎么走。先看看Kconfig文件,可以看到下面的选项。

  15 config USB_DEVICEFS
16         bool "USB device filesystem"
17         depends on USB
18         ---help---
19           If you say Y here (and to "/proc file system support" in the "File
20           systems" section, above), you will get a file /proc/bus/usb/devices
21           which lists the devices currently connected to your USB bus or
22           busses, and for every connected device a file named
23           "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the
24           device number; the latter files can be used by user space programs
25           to talk directly to the device. These files are "virtual", meaning
26           they are generated on the fly and not stored on the hard drive.
27
28           You may need to mount the usbfs file system to see the files, use
29           mount -t usbfs none /proc/bus/usb
30
31           For the format of the various /proc/bus/usb/ files, please read
32           <file:Documentation/usb/proc_usb_info.txt>.
33
34           Usbfs files can't handle Access Control Lists (ACL), which are the
35           default way to grant access to USB devices for untrusted users of a
36           desktop system. The usbfs functionality is replaced by real
37           device-nodes managed by udev. These nodes live in /dev/bus/usb and
38           are used by libusb.

  选项USB_DEVICEFS与usbfs文件系统有关。usbfs文件系统挂载在/proc/bus/usb目录,显示了当前连接的所有USB设备及总线的各种信息,每个连接的USB设备在其中都会有一个对应的文件进行描述。比如文件/proc/bus/usb/xxx/yyy,xxx表示总线的序号,yyy表示设备所在总线的地址。不过不能够依赖它们来稳定地访问设备,因为同一设备两次连接对应的描述文件可能会不同,比如,第一次连接一个设备时,它可能是002/027,一段时间后再次连接,它可能就已经改变为002/048。

  就好比好不容易你暗恋的mm今天见你的时候对你抛了个媚眼,你心花怒放,赶快去买了100块彩票庆祝,到第二天再见到她的时候,她对你说你是谁啊,你悲痛欲绝的刮开那100块彩票,上面清一色的谢谢你。

  因为usbfs文件系统并不属于USB子系统实现的核心部分,与之相关的代码我们可以不必关注。

  74 config USB_SUSPEND
75       bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"
76       depends on USB && PM && EXPERIMENTAL
77       help
78         If you say Y here, you can use driver calls or the sysfs
79         "power/state" file to suspend or resume individual USB
80         peripherals.
81
82         Also, USB "remote wakeup" signaling is supported, whereby some
83         USB devices (like keyboards and network adapters) can wake up
84         their parent hub.  That wakeup cascades up the USB tree, and
85         could wake the system from states like suspend-to-RAM.
86
87         If you are unsure about this, say N here.

这一项是有关USB设备的挂起和恢复。开发USB的人都是节电节能的好孩子,所以协议里就规定了,所有的设备都必须支持挂起状态,就是说为了达到节电的目的,当设备在指定的时间内,如果没有发生总线传输,就要进入挂起状态。当它收到一个non-idle的信号时,就会被唤醒。节约用电从USB做起。不过这个与主题也没太大关系,相关代码也可以不用关注了。

  剩下的还有几项,不过似乎与咱们关系也不大,还是去看看Makefile。

  5 usbcore-objs    := usb.o hub.o hcd.o urb.o message.o driver.o /
6                         config.o file.o buffer.o sysfs.o endpoint.o /
7                         devio.o notify.o generic.o quirks.o
8
9 ifeq ($(CONFIG_PCI),y)
10         usbcore-objs    += hcd-pci.o
11 endif
12
13 ifeq ($(CONFIG_USB_DEVICEFS),y)
14         usbcore-objs    += inode.o devices.o
15 endif
16
17 obj-$(CONFIG_USB)       += usbcore.o
18
19 ifeq ($(CONFIG_USB_DEBUG),y)
20 EXTRA_CFLAGS += -DDEBUG
21 endif

  Makefile可比Kconfig简略多了,所以看起来也更亲切点,咱们总是拿的money越多越好,看的代码越少越好。这里之所以会出现CONFIG_PCI,是因为通常USB的Root Hub包含在一个PCI设备中。hcd-pci和hcd顾名而思义就知道是说主机控制器的,它们实现了主机控制器公共部分,按协议里的说法它们就是HCDI(HCD的公共接口),host目录下则实现了各种不同的主机控制器。

  CONFIG_USB_DEVICEFS前面的Kconfig文件里也见到了,关于usbfs的,与咱们的主题无关,inode.c和devices.c两个文件也可以不用管了。

  那么我们可以得出结论,为了理解内核对USB子系统的实现,我们需要研究buffer.c、config.c、driver.c、endpoint.c、file.c、generic.c、hcd.c  hcd.h、hub.c、message.c、notify.c、otg_whitelist.h、quirks.c、sysfs.c、urb.c 和usb.c文件。这么看来,好像大都需要关注的样子,没有减轻多少压力,不过这里本身就是USB Core部分,是要做很多的事为咱们分忧的,所以多点也是可以理解的

本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2025-01-21 06:38:54

《Linux内核修炼之道》——分析内核源码如何入手?(上)的相关文章

《Linux内核修炼之道》——1.3 获取内核源码

1.3 获取内核源码 Linux内核修炼之道内核源码可以通过HTTP和FTP两种方式从http://www.kernel.org获得. 2.6.x以及2.6.x.y位于http://www.kernel.org/pub/linux/kernel/v2.6. -rc内核位于http://www.kernel.org/pub/linux/kernel/v2.6/testing. -git补丁位于http://www.kernel.org/pub/linux/kernel/v2.6/snapshots

《Linux内核修炼之道》——1.4 Linux发行版

1.4 Linux发行版 Linux内核修炼之道从严格意义上来说,Linux只是一个操作系统内核,然而,一个完整的操作系统不仅仅只是内核而已,它通常还包括了桌面环境.办公套件.媒体播放器.数据库等应用软件. 许多个人.组织和企业开发了基于Linux内核的Linux发行版.现在已经有超过600个Linux发行版,可以在http://en.wikipedia.org/wiki/List_of_Linux_distributions上看到它们的列表,其中,有多于300个正处于活跃的开发中,不断地改进.

《Linux内核修炼之道》——2.2 编译内核

2.2 编译内核 Linux内核修炼之道2.2.1 准备工作 虽然与配置内核相比,编译内核所做的工作要少得多,但是在正式编译之前,我们仍需要做一些必要的准备. 1.需要了解的基础知识 首先我们需要了解系统中与编译过程有关的目录及文件. /boot/vmlinuz-< version >:用于启动的压缩内核镜像. /boot/system.map-< version >:存储内核符号表. /boot/initrd.img-< version >:一个镜像文件,类似ramd

《Linux内核修炼之道》——第1章 初识Linux 1.1 Linux史记

第1章 初识Linux Linux内核修炼之道 我一直都认为自己是个很冷静.很理智的人,但是在过去的某年某月,我初识了Linux,并为之着迷,至今仍深陷其中,找不到出去的路. 如果你尚未与Linux亲密接触过,那么希望本书可以成为你初识Linux的见证.如果你已经是个Linux达人,那么就选个安静的早晨或下午,陪我一起缅怀下这过去的18年吧. 1.1 Linux史记 Linux内核修炼之道 至此落笔之际,恰至Linux问世18周年,18年的成长,风雨颇多,感慨颇多,谨以这18年来的点滴之事为Li

《Linux内核修炼之道》——1.2 内核的版本

1.2 内核的版本 Linux内核修炼之道很多年来,Linux内核的版本都是以X.Y.Z这3个数字的形式设定的,偶数Y代表稳定版,奇数Y代表不稳定的开发版.所谓的稳定版本是指内核的特性已经固定,代码运行稳定可靠,不再增加新的特性,要改进也只是修改代码中的错误.而不稳定版本是指相对于上一个稳定版本增加了新的特性,还处于发展之中,代码运行不大可靠. Z的递增表示个别的修正版发布."稳定"的1.0.0内核在1994年3月发布,随后发布了"不稳定"的1.1.z分支,直到19

Android内核源码 在Ubuntu上下载,编译,安装

从源代码树下载下来的最新Android源代码,是不包括内核代码的,也就是Android源代码工程默认不包含Linux Kernel代码,而是使用预先编译好的内核,也就是prebuilt/android-arm/kernel/kernel-qemu文件.那么,如何才能DIY自己的内核呢?这篇文章一一道来. 一. 首选,参照前一篇在Android源码 在Ubuntu上下载,编译和安装准备好Android源代码目录. 二. 下载Linux Kernel for Android源代码. 1. 使用GIT

Linux CentOS6.6系统中安装mysql源码包的方法_Linux

这里以CentOS6.6系统中安装MySQL的源码包,进行讲解. 1. mysql源码包的下载 mysql安装包的官方下载地址为:http://dev.mysql.com/downloads/mysql/5.6.html 打开该下载地址后,在 "Select Version:"处,选择要下载的mysql的版本,我选择的是5.6.34:在"Select Platform:"处,选择适用的操作系统类型,由于是下载源码包,故这里我们要选择Source Code. 之后,会

Linux有问必答:怎么用CheckInstall从源码创建一个RPM或DEB包

Linux有问必答:怎么用CheckInstall从源码创建一个RPM或DEB包 问题:我想要从源码创建安装的软件包.有没有一种方式从源码来创建和安装软件包,而不是运行"make install"?这样的话,以后如果我想,我可以容易的卸载程序. 如果你已经从它的源码运行"make install"安装了linux程序.想完整移除它将变得真的很麻烦,除非程序的开发者在Makefile里提供了uninstall的目标设置.否则你必须在安装前后比较你系统里文件的完整列表,

《深入解析Android 虚拟机》——第1章,第1.2节分析Android源码结构

1.2 分析Android源码结构获得Android源码后,可以将整个源码分为如下3个部分. Core Project:核心工程部分,这是建立Android系统的基础,被保存在根目录的各个文件夹中.External Project:扩展工程部分,可以使其他开源项目具有扩展功能,被保存在"external"文件夹中.Package:包部分,提供了Android的应用程序.内容提供者.输入法和服务,被保存在"package"文件夹中.无论是Android 1.5还是An