标签:ret 地址 设置 设备驱动 sep 选择 总结 usb 初始化
现象:将USB设备接入PC,PC右下角上会弹出"发现xx新设备",例如"发现andriod phone"若PC上没有安装该设备的驱动程序,则会弹出对话框提示"安装驱动程序"。
问1:没有安装设备的驱动程序之前,为什么PC还能发现andriod phone设备呢?
答1:windows系统中已经安装了USB的"总线驱动程序",是"总线驱动程序"发现了新的设备,而提示我们安装的是"设备驱动程序"。
问2:USB设备种类繁多,为何一接入电脑,就可以识别出来?
答2:PC与USB设备都要遵循一些规范。
比如:USB设备插入PC机后,PC会发出"你是什么"?
USB设备回答"我是xxx",且回答的语言必须是中文。
USB总线驱动程序会发出某些命令获取设备的信息(描述符)。
USB设备必须返回"描述符"给PC。
问3:PC机上接有很多的USB设备,如何区分这些设备?
USB接口上有四条线:5V、GND、D+、D-
答3:每一个USB设备在接入到总线上后,USB驱动程序都会给它分配一个固定的编号。
接在USB总线上的USB设备都拥有属于自己的编号(地址),PC发送含有对应USB设备的编号(地址)的命令进行访问。
问4:新接入的USB设备还没有编号,PC如何将总线"分配的编号"告诉对应的USB设备?
答4:新接入的USB设备默认的编号是0,在未分配新的编号前,PC机使用0编号和设备进行通信。
问5:为什么设备一插入PC机,就能被PC机发现了?
答5:PC机的USB口内部,D+和D-都接有15k的下拉电阻,未接入USB设备时为低电平;
USB设备的USB口内部,D+或者D-接有1.5k的上拉电阻,他一接入PC,就会把PC的USB口的D+或者D-拉高,从而通过硬件通知PC有新的USB 设备接入。
USB概念简介
所有的USB传输,都是从USB主机这方发起,USB设备方不能主动发起通信。
a、控制传输:可靠的,时间有保证,比如:USB设备的识别过程
b、批量传输:可靠,不实时,时间没有保证,比如:U盘
c、中断传输(不断的查询实现实时性):可靠,实时,比如:USB鼠标
d、实时传输:不可靠,实时,比如:USB摄像头
端点0用于控制传输,既能输出也能输入。
除了端口0外,每一个端点只支持一个方向的数据传输。
linux内核中USB架构
如下图所示,linux内核中USB驱动采用一种分层架构,由USB总线驱动和USB设备驱动构成。其中,USB总线驱动程序的作用主要包括:a 、识别USB设备;b、查找并安装对应的设备驱动程序;c、提供USB读写函数。
OHCI(Open Host Controller Interface):由Compaq,Microsoft和National Semiconductor创立,支持USB1.1的标准,硬件复杂,软件相对简单,主要用于非x86的USB,如扩展卡、嵌入式开发板的USB主控。
UHCI(Universal Host Controller Interface):Intel主导的USB1.0、USB1.1的接口标准,与OHCI不兼容,其硬件较为简单,软件则比较复杂。
EHCI(Enhanced Host Controller Interface),是Intel主导的USB2.0的接口标准。提供USB2.0的高速功能。
xHCI(eXtensible Host Controller Interface),是最新最火的USB3.0的接口标准,它在速度、节能、虚拟化等方面都比前面3种有了较大的提高。xHCI支持所有种类速度的USB设备(USB 3.0 SuperSpeed,USB 2.0 Low-,Full-,and High-speed,USB 1.1 Low- and Full-speed)。
USB驱动程序框架分析
往开发板上插入一个U盘,借助系统打印出的信息,分析Linux内核系统中USB总线驱动程序是如何运行的。
插上u盘后,终端输出的信息。
拔出u盘后
选择"usb 1-1: new full speed USB device using s3c2410-ohci and address 2"中部分信息,使用grep命令在内核中进行查找,搜索结果如下。
找到drivers\usb\core\hub.c文件,发现是在hub_port_init函数中打印的上述信息。继续搜索,最后列出函数的调用关系如下:
hub_irq
kick_khubd
->wake_up(&khubd_wait); 唤醒khubd_wait
hub_thread
hub_events
wait_event_interruptible (khubd_wait,..) 等待khubd_wait事件
hub_port_connect_change
usb_alloc_dev
dev->dev.bus = &usb_bus_type;
…
choose_address 为新的USB设备分配一个编号(地址)
hub_port_init
-> hub_port_reset
-> hub_set_address 为新的USB设备设置分配的地址编号
-> usb_get_device_descriptor 获取USB的设备描述符
usb_new_device
usb_get_configuration 获取并解析USB设备的配置描述符
device_add 将新的dev放入到usb_bus_ type的dev链表中,
再从usb_bus_ type的driver链表中取出drv进行一一比较,
若匹配成功,则可以调用drv的probe函数。
有关USB设备描述符,请参考:https://www.cnblogs.com/beijiqie1104/p/11725775.html。
进入hub_port_connect_change函数。
代码第7行,申请一个usb_dev,并将其挂接到usb_bus上。
代码第9行,为usb_dev分配一个地址编号。
代码第11行,初始化hub port端口。
代码第13行,创建一个新的usb device。
查看usb_alloc_dev函数。
代码中第6行,分配了一个usb_dev结构体。
代码第10行,将结构体usb_dev的dev.bus指向usb_bus_type。其中usb_bus_type是linux内核中bus_type的一种,与之前的平台总线platform_bus_type类似,具体的定义如下:
其中usb_device_match函数用于实现device与drvier的匹配。
代码第11行,将dev.type指向usb_device_type。其中usb_device_type的定义如下:
紧接着来看看hub_port_connect_change函数中的choose_address函数。
代码第9行,在bus->devnum_next到128之间,查找一个非0的编号。
代码第11行,当编号大于等于128的时候,从1开头处开始查找。
代码第14行,设置下次查找的起始位置。
hub_port_init函数
代码第10行,设置usb device的地址编号。
代码第12行,获取设备描述符的前8个字节,这8个字节是USB设备描述符的固定字节数,先将8个字节数据读出后,在解析后续需要再重新读取的字节数。
代码第14行,再次获取完整的设备描述符信息。
usb_new_device函数如下:
代码第4行,获取设备的配置描述符,其中usb_get_configuration函数定义如下:
接着来看看device_add函数。
总结:
linux内核中USB的驱动分为USB总线驱动和USB设备驱动两部分。系统中hub_thread在没有USB连接的时候,处于睡眠状态,一旦主机控制器检测到USB设备插入的时候,会产生hub_irq中断,唤醒hub_thread线程。然后会创建新的USB设备,分配地址编号,获取设备的描述符信息,将其放入到设备链表中,并和drv链表中的id_table进行匹配,若匹配成功则调用drv的probe函数。框架中已经将总线驱动完成,我们需要做的是编写usb的设备驱动,重点就是probe函数。
标签:ret 地址 设置 设备驱动 sep 选择 总结 usb 初始化
原文地址:https://www.cnblogs.com/beijiqie1104/p/11731123.html