Linux设备模型中的总线落实在USB子系统里就是usb_bus_type,它在usb_init的函数bus_register(&usb_bus_type)里注册。usb_bus_type定义如下:

struct bus_type usb_bus_type = {

.name = "usb",

.match = usb_device_match,

.uevent = usb_uevent,

.suspend = usb_suspend,

.resume = usb_resume,

};

显然,在这个结构体里重要的是usb_device_match函数,以后会专门一节来详细分析

static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) { /* interface drivers never match devices */
if (!is_usb_device_driver(drv))
return 0;usb_device_driver /* TODO: Add real matching code */
return 1; } else if (is_usb_interface(dev)) {
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id; /* device drivers never match interfaces */
if (is_usb_device_driver(drv))
return 0; intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv); id = usb_match_id(intf, usb_drv->id_table);
if (id)
return 1; id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
} return 0;
}

熟悉Linux设备模型,上述函数的参数我们应该也能够理解。对应的就是总线两条链表里的设备和驱动。注释已经很明确告诉我们分两条路走,一条是设备,另一条是接口,你问我为什么?我说你去问问内核吧。(其实我也不知道)

/* devices and interfaces are handled separately */

接口是设备的接口。设备可以有多个接口,每个接口代表一个功能,每个接口对应着一个驱动。Linux设备模型的device落实在USB子系统,成了两个结构,一个是struct usb_device,一个是struct usb_interface。假设一个usb设备具有两种功能,一个是键盘功能,还有扬声器功能,那么就会存在两个接口,对应得要有两个驱动程序,一个是键盘驱动程序,一个是音频流驱动程序。兄弟喜欢把这样两个整合在一起的东西叫做一个设备,那好,让他们去叫吧,我们用interface来区分这两者行了吧。于是有了这里提到的那个数据结构,struct usb_interface。去看看usb_interface结构体吧。

struct usb_interface {

/* array of alternate settings for this interface,

* stored in no particular order */

struct usb_host_interface *altsetting;

struct usb_host_interface *cur_altsetting; /* the currently

* active alternate setting */

unsigned num_altsetting; /* number of alternate settings */

int minor; /* minor number this interface is

* bound to */

enum usb_interface_condition condition; /* state of binding */

unsigned is_active:1; /* the interface is not suspended */

unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */

struct device dev; /* interface specific device info */

struct device *usb_dev; /* pointer to the usb class's device, if any */

int pm_usage_cnt; /* usage counter for autosuspend */

};

这里有个altsetting成员,意思就是alternate setting,可选的设置,cur_altsetting表示当前正在使用的设置;num_altsetting表示这个接口具有可选设置的数量;minor,分配给接口的次设备号;,condition字段表示接口和驱动的绑定状态,前面说linux设备模型的时候说了,设备和驱动是相生相依的关系usb_interface_condition形象的描绘了这个过程中接口的个中心情,孤苦、期待、幸福、分开,人生又何尝不是如此?is_active:1、needs_remote_wakeup:1和pm_usage_cnt是关于挂起和唤醒的。协议里规定,所有的usb设备都必须支持挂起状态,就是说为了达到节电的目的,当设备在指定的时间内,3ms吧,如果没有发生总线传输,就要进入挂起状态。当它收到一个non-idle的信号时,就会被唤醒。 is_active表示接口是不是处于挂起状态。needs_remote_wakeup表示是否需要打开远程唤醒功能。远程唤醒允许挂起的设备给主机发信号,通知主机它将从挂起状态恢复,注意如果主机处于挂起状态,就会唤醒主机,不然主机仍然在睡着。协议里并没有要求USB设备一定要实现远程唤醒的功能,即使实现了,从主机这边儿也可以打开或关闭它。pm_usage_cnt,就是使用计数,当它为0时,接口允许autosuspend。什么叫autosuspend?有时合上笔记本后,它会自动进入休眠,这就叫autosuspend。但不是每次都是这样的,就像这里只有当pm_usage_cnt为0时才会允许接口autosuspend。

struct device dev和struct device *usb_dev,看到struct device没,它们就是linux设备模型里的device嵌在这儿的对象,我们的心中要时时有个模型。不过这么想当然是不正确的,两个里面只有dev才是模型里的device嵌在这儿的,usb_dev则不是。当接口使用USB_MAJOR作为主设备号时,usb_dev才会用到,你找遍整个内核,也只在usb_register_dev和usb_deregister_dev两个函数里能够看到它,usb_dev指向的就是usb_register_dev函数里创建的usb class device。

下面插讲一下关于设备号的概念。

linux下所有的硬件设备都是用文件来表示的,俗称设备文件,在/dev目录下边儿,为了显示自己并不是普通的文件,它们都会有一个主设备号和次设备号,比如

brw-r----- 1 root disk 8, 0 Sep 26 09:17 /dev/sda

brw-r----- 1 root disk 8, 1 Sep 26 09:17 /dev/sda1

crw-r----- 1 root tty 4, 1 Sep 26 09:17 /dev/tty1

这是在我的系统里使用ls –l命令查看的,当然只是显示了其中的几个来表示表示而已。很显然,任何一个有理智有感情的人都会认为USB设备是很常见的,linux理应为它预留了一个主设备号。看看include/linux/usb.h文件

7 #define USB_MAJOR 180

8 #define USB_DEVICE_MAJOR 189

你可以在内核里搜索它们都曾经出现什么地方,或者就跟随我回到usb_init函数。

之前和usbfs相关的就简单的飘过了,这里略微说的多一点。usbfs为咱们提供了在用户空间直接访问usb硬件设备的接口,但是世界上没有免费的午餐,它需要内核的大力支持,usbfs_driver就是用来完成这个光荣任务的。咱们可以去usb_init的usb_devio_init函数里看一看,它在drivers/usb/devio.c文件里定义

retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,

"usb_device");

if (retval) {

err("unable to register minors for usb_device");

goto out;

}

register_chrdev_region函数获得了设备usb_device对应的设备编号,设备usb_device对应的驱动当然就是usbfs_driver,参数USB_DEVICE_DEV也在同一个文件里有定义

#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)

终于再次见到了USB_DEVICE_MAJOR,也终于明白它是为了usbfs而生,为了让广大人民群众能够在用户空间直接和usb设备通信而生。因此,它并不是我们所要寻找的。

那么答案很明显了,USB_MAJOR就是咱们苦苦追寻的那个她,就是linux为USB设备预留的主设备号。事实上,前面usb_init函数的880行,usb_major_init函数已经使用USB_MAJOR注册了一个字符设备,名字就叫usb。我们可以在文件/proc/devices里看到它们。

localhost:/usr/src/linux/drivers/usb/core # cat /proc/devices

Character devices:

1 mem

2 pty

3 ttyp

4 /dev/vc/0

4 tty

4 ttyS

5 /dev/tty

5 /dev/console

5 /dev/ptmx

7 vcs

10 misc

13 input

14 sound

29 fb

116 alsa

128 ptm

136 pts

162 raw

180 usb

189 usb_device

/proc/devices文件里显示了所有当前系统里已经分配出去的主设备号,当然上面只是列出了字符设备。事实上,USB设备有很多种,并不是都会用到这个预留的主设备号。比如移动硬盘显示出来的主设备号是8,你的摄像头在linux显示的主设备号也绝对不会是这里的USB_MAJOR。坦白的说,咱们经常遇到的大多数usb设备都会与input、video等子系统关联,并不单单只是作为usb设备而存在。如果usb设备没有与其它任何子系统关联,就需要在对应驱动的probe函数里使用usb_register_dev函数来注册并获得主设备号USB_MAJOR,你可以在drivers/usb/misc目录下看到一些例子,drivers/usb/ usb-skeleton.c文件也属于这种。如果usb设备关联了其它子系统,则需要在对应驱动的probe函数里使用相应的注册函数,USB_MAJOR也就该干吗干吗去,用不着它了。比如,usb键盘关联了input子系统,驱动对应drivers/hid/usbhid目录下的usbkbd.c文件,在它的probe函数里可以看到使用了input_register_device来注册一个输入设备。准确的说,这里的USB设备应该说成USB接口,毕竟一个USB接口才对应着一个USB驱动。当USB接口关联有其它子系统,也就是说不使用USB_MAJOR作为主设备号时,struct usb_interface的字段minor可以简单的忽略。minor只在USB_MAJOR起作用时起作用。

usb驱动开发5之总线设备与接口的更多相关文章

  1. usb驱动开发4之总线设备驱动模型

    在上文说usb_init函数,却给我们留下了很多岔路口.这次就来好好聊聊关于总线设备驱动模型.这节只讲理论,不讲其中的函数方法,关于函数方法使用参考其他资料. 总线.设备.驱动对应内核结构体分别为bu ...

  2. HarmonyOS USB DDK助你轻松实现USB驱动开发

    HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态开放的基础,为开发者提供了驱动加载.驱动服务管理和驱动消息机制等驱动能力,让开发者能精准且高效地开发驱 ...

  3. usb驱动开发9之设备描述符

    前面分析了usb的四大描述符之端点描述符,接口描述符(每一个接口对应一个功能,与之配备相应驱动),配置描述符,最后分析设备如何包括这些描述符.首先记住,在usb的世界里,设备大于配置,配置大于接口,接 ...

  4. usb驱动开发16之设备生命线

    回到struct usb_hcd,继续努力的往下看. kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看hcd.c文件. static void hcd_ ...

  5. usb驱动开发15之设备生命线

    总算是进入了HCD的片儿区,既然来到一个片区,怎么都要去拜会一下山头几个大哥吧.,先回忆一些我们怎么到这里的?给你列举一个调用函数过程usb_control_msg->usb_internal_ ...

  6. usb驱动开发14之设备生命线

    直接看代码吧. /*-------------------------------------------------------------------*/ /** * usb_submit_urb ...

  7. usb驱动开发12之设备生命线

    函数usb_control_msg完成一些初始化后调用了usb_internal_control_msg之后就free urb.剩下的活,全部留给usb_internal_control_msg去做了 ...

  8. usb驱动开发11之设备生命线

    暂时先告别媒人,我们去分析各自的生命旅程,最后还会回到usb_device_match函数. 首先当你将usb设备连接在hub的某个端口上,hub检测到有设备连接了进来,它会为设备分配一个struct ...

  9. usb驱动开发1之学习准备

    此系列是http://blog.csdn.net/fudan_abc/博文的整理,同时加入了自己的理解.很敬佩fudan_abc的文章,仔细学习和分析受益很多.注:fundan_abc所分析linux ...

随机推荐

  1. 2015年第12本(英文第8本):the Old Man and the Sea 老人与海

    书名:The Old Man and The Sea(老人与海) 作者:Ernest Hemingway 单词数:2.7万 不重复单词数:2600 首万词不重复单词数:1500 蓝思值:940 阅读时 ...

  2. JavaWeb开发必过关-Servlet学习(一)

    一.什么是Servlet servlet其实是一个小程序,它是运行在服务器上的,一个servlet就是一个Java类,可以通过"请求-响应"编程模型来访问这个驻留在服务器内存的Se ...

  3. iOS之Cookie

    iOS之Cookie使用 简介 概念:Cookie中文名称叫做"小型文本文件",指某些网站为了辨别用户身份而存储在用户本地终端上的数据(通常经过加 密). Web服务器可以用过Se ...

  4. 【读书笔记】iOS-UIFont-动态下载系统提供的字体-官方代码

    一,工程目录 二,AppDelegate.m - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOption ...

  5. IOS 杂笔-18 (let 与 var)

    var 是 variable的缩写形式,是变量的意思 ,是可改变的,并不是数据类型. let 是常量的意思,不可改变的.

  6. Android常用设计模式(一)

    java有23中设计模式,Android中也用到了很多的设计模式,本篇就来介绍Android中常用的几种设计模式 一.普通工厂设计模式 普通工厂设计模式,就是创建一个工厂类负责创建对象 ,用户根据需求 ...

  7. 保持listview当前位置

    保持listview滑动的位置,一般用在增加listview子item中布局的评论或者退出当前活动,再次进入继续阅读时. 利用ListView.getFirstVisiblePosition()来获取 ...

  8. iOS设计模式 - 单例

    备注:只能通过类的类方法才能创建单例类的实例,[[类名 alloc]init]创建实例没有用的. 原理图 说明 1. 单例模式人人用过,严格的单例模式很少有人用过 2. 严格的单例模式指的是无法通过常 ...

  9. Swift面向对象基础(中)——Swift中的存储属性和计算属性

    学习来自<极客学院> 1.存储属性:存储在类.结构体里的变量或者常量 2.分为:实例存储属性.类型存储属性 3.所有的存储属性必须显示的指定初始值,在定义时或者构造器当中指定 4.可选类型 ...

  10. Java 之 内部类

    (static修饰的成员属于整个类,而不属于单个对象) 定义:将一个类放到另一个类的内部定义,这个在内部定义的类就叫做内部类(也有的成嵌套类),包含内部类的类被称为外部类(也有的称宿主类). 1.非静 ...