USB子系统源码分析

本文导读:本文主要分析USB子系统的内核源代码(V2.6.34)实现.主要实现三个目标:1.充分理解设备模型以及相关的结构:bus, driver, device. 2.类似与其他子系统,本子系统是怎么在内核中执行。3设备驱动程序的编写,从而帮助理解驱动开发中的各种语法细节

 Keywords: usb子系统,设备模型,驱动开发                         writed by huangjl

1.     找地图开始分析

/kernel/driver/usb目录下三个文件readme,kconfig,makefile

/*************************readme.txt*******************************/

Here is a list of what each subdirectory here is, and what is contained in  them.

 core/                  - This is for the core USB host code, including the

                     usbfs files and the hub class driver ("khubd").

host/                  - This is for USB host controller drivers.  This

                     includes UHCI, OHCI, EHCI, and others that might

                     be used with more specialized "embedded" systems.

gadget/             - This is for USB peripheral controller drivers and

                     the various gadget drivers which talk to them.

 Individual USB driver directories.  A new driver should be added to the

first subdirectory in the list below that it fits into.

image/               - This is for still image drivers, like scanners or

                     digital cameras.

../input/   - This is for any driver that uses the input subsystem,

                     like keyboard, mice, touchscreens, tablets, etc.

../media/ - This is for multimedia drivers, like video cameras,

                     radios, and any other drivers that talk to the v4l

                     subsystem.

../net/                - This is for network drivers.

serial/                - This is for USB to serial drivers.

storage/   - This is for USB mass-storage drivers.

class/                  - This is for all USB device drivers that do not fit

                     into any of the above categories, and work for a range

                     of USB Class specified devices.

misc/                  - This is for all USB device drivers that do not fit

                     into any of the above categories.

/*************************readme.txt*******************************/

  从readme.txt文件中对该目录做了个全局的介绍。Core文件代码提供对USB主机代码提供支持。Host目录下对不同的USB主机控制器支持。Gadget则是对USB外围控制器驱动。由于USB支持不同类型的外围设备,这些设备通常被分为不同的逻辑连接,所以才有像image,input等目录。这些目录下是外围设备驱动程序。再来看Kconfig文件

 /************************Kconfig*******************************/

config USB_ARCH_HAS_HCD

…..

config USB_ARCH_HAS_OHCI

….

config USB_ARCH_HAS_EHCI

….

config USB

/************************Kconfig*******************************/

/************************Makefile*******************************/

obj-$(CONFIG_USB)          += core/

….

obj-$(CONFIG_PCI)           += host/

……

obj-$(CONFIG_USB_STORAGE)        += storage/

/************************Makefile*******************************/

从上面两个文件看出,USB子系统最主要的就是目录core,host,各类驱动程序目录。

 2.USB子系统的分层设计

USB模块在内核层次结构

首先我们来看看USB驱动程序在内核系统中的层次如下:

 

VFS Layer

Block Layer

Net Layer

char Layer

TTY Layerv…etc….

USB Device Driver

USB Core

USB Host Controllers

Hardware

 

对于设备驱动程序,从设备的角度来看

 

       Device

interface

Endpoint

Endp

int

Endpoint

Endpoint

 

interface

Endpoint

Endpoint

Endpoint

Endpoint

 

 

<<<driver

 

 

Kernel

 

 

<<<driver

    很容易看出,usb各层在代码目录体现得很具体

3.USB子系统是怎么被系统识别和运行的

/********************core.c***********************/

subsys_initcall(usb_init);

module_exit(usb_exit);

/*******************core.c***********************/

/******************include/linux/init.h*********************/

#define __define_initcall(level,fn,id) \

     static initcall_t __initcall_##fn##id __used \

     __attribute__((__section__(".initcall" level ".init"))) = fn

* This only exists for built-in code, not for modules.

 */

#define pure_initcall(fn)                __define_initcall("0",fn,0)

#define core_initcall(fn)                __define_initcall("1",fn,1)

#define core_initcall_sync(fn)               __define_initcall("1s",fn,1s)

#define postcore_initcall(fn)                  __define_initcall("2",fn,2)

#define postcore_initcall_sync(fn)       __define_initcall("2s",fn,2s)

#define arch_initcall(fn)                __define_initcall("3",fn,3)

#define arch_initcall_sync(fn)               __define_initcall("3s",fn,3s)

#define subsys_initcall(fn)             __define_initcall("4",fn,4)

#define subsys_initcall_sync(fn)   __define_initcall("4s",fn,4s)

#define fs_initcall(fn)                      __define_initcall("5",fn,5)

#define fs_initcall_sync(fn)           __define_initcall("5s",fn,5s)

#define rootfs_initcall(fn)              __define_initcall("rootfs",fn,rootfs)

#define device_initcall(fn)             __define_initcall("6",fn,6)

#define device_initcall_sync(fn)  __define_initcall("6s",fn,6s)

#define late_initcall(fn)                 __define_initcall("7",fn,7)

#define late_initcall_sync(fn)                   __define_initcall("7s",fn,7s)

代码中给出的注释是built-in code,也就是内建代码。也就是内核的构成

该部分的功能是将某个函数放在区域里,该区域的内存分布如下: 

 subsys_initcall(usb_init)就是将usb_init函数放在.initcall4.init这段内存中,系统在启动的时候,会按照先后顺序全部调用这段内存中的全部函数指针,调用的方式如下:

extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

static void __init do_initcalls(void)

{

         initcall_t *fn;

          for (fn = __early_initcall_end; fn < __initcall_end; fn++)

                   do_one_initcall(*fn);

          /* Make sure there is no pending stuff from the initcall sequence */

         flush_scheduled_work();

}

 下面是usb_init的执行路线:

 

   

为了分析驱动程序的模型,需要一个个函数追根到底分析。Usb_debugfs_init与USB文件系统的调试有关。与模型无关,暂时不分析。

3.1.   bus_register:

    bus_register(struct bus_type *bus)函数:该函数注册总线到系统,具体来说将总线注册到Kobject框架中,然后才能注册总线所属设备和驱动的子系统。

      首先来看看bus_type结构:

/*****************************device.h*************************************/

struct bus_type {

         const char                  *name;

         struct bus_attribute         *bus_attrs;

         struct device_attribute   *dev_attrs;

         struct driver_attribute    *drv_attrs;

          int (*match)(struct device *dev, struct device_driver *drv);

         int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

         int (*probe)(struct device *dev);

         int (*remove)(struct device *dev);

         void (*shutdown)(struct device *dev);

          int (*suspend)(struct device *dev, pm_message_t state);

         int (*resume)(struct device *dev);

         const struct dev_pm_ops *pm;   /*电源管理操作指针*/

         struct bus_type_private *p;

};

/**************************************************************************/

pm指向电源管理指针,设计者真是个节能减员的好孩子。

P指向总线私带的指针数据,这个指针只有驱动核心才能使用

/********************kernel/drivers.h/base.h*************************************/

struct bus_type_private {

         struct kset subsys;

         struct kset *drivers_kset;           /*挂属于该总线的 驱动*/

         struct kset *devices_kset;           /*挂属于该总线的 设备*/

         struct klist klist_devices;

         struct klist klist_drivers;

         struct blocking_notifier_head bus_notifier;    /*挂该总线的事件通知链表*/

         unsigned int drivers_autoprobe:1;

         struct bus_type *bus;

};

/**************************************************************************/

/****************kernel/include/linux/Kobject.h********************************/

struct kobject {

         const char                  *name;

         struct list_head        entry;

         struct kobject            *parent;

         struct kset                  *kset;      /*设置所属的kset集*/

         struct kobj_type       *ktype;     /*设置的obj类型*/

         struct sysfs_dirent   *sd;

         struct kref                  kref;

         unsigned int state_initialized:1;

         unsigned int state_in_sysfs:1;

         unsigned int state_add_uevent_sent:1;

         unsigned int state_remove_uevent_sent:1;

         unsigned int uevent_suppress:1;

};

struct kset {

         struct list_head list;

         spinlock_t list_lock;

         struct kobject kobj;

         const struct kset_uevent_ops *uevent_ops;

};

/**************************************************************************/

 

 如上图:总线注册要做的事情分为下几类:

1.       将bus_type_private与bus相关联

2.       初始化bus_type_private事件通知链表

3.       设置bus_type_private的内嵌object中的Kset,ktype

4.       创建该总线所属的子系统集

5.       创建属于该总线的设备和驱动链表

6.       创建该总线的属性文件,方便用户在sysfs中查看(根据配置不同,在用户空间来是否支持热拔插)

7.       增加引用计数

可以看出,总线的注册其实就是配置bus_type_private结构

 3.2 . bus_register_notifier

   这个函数在前面稍微有接触,这个应该比较熟悉。总之执行后结果如下:

 

3.3. usb_major_init

该函数主要对文件系统提供支持。 即提供驱动程序对sysfs文件系统的操作

 3.4 usb_register

     函数调用是usb_register(&usbfs_driver);

    可以看出,该接口提供对usb文件系统的支持。方便用户以用户接口调用

先看看这个结构:

struct usb_driver {

     const char *name;

     int (*probe) (struct usb_interface *intf,   const struct usb_device_id *id);

     void (*disconnect) (struct usb_interface *intf);

     int (*ioctl) (struct usb_interface *intf, unsigned int code,void *buf);

     int (*suspend) (struct usb_interface *intf, pm_message_t message);

     int (*resume) (struct usb_interface *intf);

     int (*reset_resume)(struct usb_interface *intf);

     int (*pre_reset)(struct usb_interface *intf);

     int (*post_reset)(struct usb_interface *intf);

     const struct usb_device_id *id_table;

     struct usb_dynids dynids;

     struct usbdrv_wrap drvwrap;

     unsigned int no_dynamic_id:1;

     unsigned int supports_autosuspend:1;

     unsigned int soft_unbind:1;

};

#define         to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)

该结构是对interface的抽象,在core层识别接口驱动。

 从上图可以看出,驱动的注册是很繁杂的过程,特别是跟object核心交互,在注册过程中驱动就开始寻找设备,这是自动搜索过程,从这些可以看出,总线有驱动和设备的两边,到最后驱动和设备的匹配最终要调用总线的match函数。如果支持设备的热拔插,需要提供设备的厂商,ID等信息,具体的实现见源代码。到此驱动模型可以说分析得差不多了,设备和驱动就是通过这样的思路关联起来的。

 3.5. usb_devio_init

这个函数功能文件解释如下:

*  This file implements the usbfs/x/y files, where

*  x is the bus number and y the device number.

*  It allows user space programs/"drivers" to communicate directly

*  with USB devices without intervening kernel driver.

这个函数功能放到后面分析。

 3.6. usbfs_init

 3.7. usb_hub_init

 3.8. usb_register_device_driver

* drivers/usb/generic.c - generic driver for USB devices (not interfaces)

* usb_register_device_driver - register a USB device (not interface) driver

这个函数是对设备驱动层来说的

 4.自下而上全面分析Core层

好了,这个子系统的识别完了。好像没有想象得那么难。工作才开始,因为现在不是设计驱动程序,而是分析提供给驱动程序的接口,那么这就相当于分析库函数。下面才是真正的开始。

4.1. 找地图,重新选择路线

/************************core/makefile******************************/

usbcore-objs     := usb.o hub.o hcd.o urb.o message.o driver.o \

                            config.o file.o buffer.o sysfs.o endpoint.o \

                            devio.o notify.o generic.o quirks.o devices.o

/************************core/makefile******************************/

从上面来看,需要关注的.c文件有

Usb.c, hub.c, hcd.c, urb.c, message.c, driver.c, config.c, file.c, buffer.c, sysfs.c, endpoint.c

Devio.c, notify.c, generic.c, quirks.o, devices.c.

 为了方便,分析的过程,我不再详述,直接在源码中注释。有关流程图可能需要,因此这里只总结每个文件的用途,细节到每个函数。当然先从简单的开始。既然core屏蔽了硬件的细节,为了更加深入的了解core层,必须有一种硬件(HC:主机控制器作为参考),还是MPC8309体系结构为例。那么开始从hcd.h,hcd.c两个文件开始,首先看一下相关的硬件知识【待续】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值