八、USB驱动分析
学习目标:分析USB驱动源码结构。
一、Windows下USB驱动理论问题
1. 当usb设备接入PC时,右下角弹出"发现AAA",并弹出对话框,提示安装驱动程序。没有驱动程序,Windows是怎样知道是AAA设备?
--> Windows有USB的总线驱动程序,接入USB设备后,"总线驱动程序"就会知道该设备是"AAA",提示安装的是”AAA的设备驱动程序"。这里USB总线驱动程序负责:识别USB设备, 给USB设备找到对应的驱动程序。
USB总线驱动程序的作用:(1) 识别USB设备 (2)查找并安装对应的设备驱动程序 (3)提供USB读写函数。
2. Windows是怎样识别出该USB设备的种类/名称?
--> PC和USB设备都得遵守一些规范。USB总线驱动程序会发出某些命令想获取设备信息(描述符),USB设备必须返回"描述符"给PC。
3. PC机是怎样分辨USB设备?
--> 每一个USB设备接入PC时,USB总线驱动程序都会给它分配一个编号(地址),PC机想访问某个USB设备时,发出的命令都含有对应的编号(地址);新接入的USB设备的默认编号是0,在未分配新编号前,PC使用0编号和它通信。
4. 为什么一接入USB设备,PC机就能发现它?
--> 由于硬件接口连接问题提示的。USB接口只有4条线: 5V,GND,D-,D+。USB设备接入PC,会把PC USB口的D-或D+拉高,从而通知有新设备接入。
注意:
(1)USB是主从结构的,所有的传输都是由USB主机方发起的。例如,USB键盘按下立刻产生数据,但是它没有能力通知PC机来读数据,只能等待PC机来读。
(2)USB在数据传输中,以端点为对象的,其有传输类型,传输方向。每个端点只有一个方向的功能(除了端点0控制传输,既能输出也能输入外),例如把数据从端点1读出,向端点2写入数据。


usb 1-1: configuration #1 chosen from 1 choice
scsi0 : SCSI emulation for USB Mass Storage devices
scsi 0:0:0:0: Direct-Access HTC Android Phone 0100 PQ: 0 ANSI: 2
sd 0:0:0:0: [sda] Attached SCSI removable disk
拔掉后会打印:
usb 1-1: USB disconnect, address 2
drivers/usb/core/hub.c:2186: "%s %s speed %sUSB device using %s and address %d\n",
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, udev->devnum);
2) 接下来在source insight中查看源码调用:
hub_thread-->
hub_events()-->
hub_port_connect_change()-->
调用 hub_port_init()
在hub_thread()函数中:可知hub_events() 的调用,需要等待中断khubd_wait被唤醒;
static int hub_thread(void *__unused)
{
do {
hub_events();
wait_event_interruptible(khubd_wait,
!list_empty(&hub_event_list) ||
kthread_should_stop());
try_to_freeze();
} while (!kthread_should_stop() || !list_empty(&hub_event_list)); pr_debug("%s: khubd exiting\n", usbcore_name);
return ;
}
3) 搜索“中断khubd_wait”,可以得到它是在drivers/usb/core/Hub.c --> kick_khubd()函数中:
static void kick_khubd(struct usb_hub *hub)
{
unsigned long flags;
/* Suppress autosuspend until khubd runs */
to_usb_interface(hub->intfdev)->pm_usage_cnt = ; spin_lock_irqsave(&hub_event_lock, flags);
if (list_empty(&hub->event_list)) {
list_add_tail(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);
}
spin_unlock_irqrestore(&hub_event_lock, flags);
}
4) 继续搜索kick_khubd(),可知该函数被hub_irq()调用,因此当USB设备插入后,D+ 或者D-会被拉高,从而使USB控制器产生usb_irq中断。
5) 在hub_port_connect_change()实现了设备注册、端口连接、创建USB设备等功能。
static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange)
{
udev = usb_alloc_dev(hdev, hdev->bus, port1); //注册usb_device,放在usb总线上
device_initialize(&dev->dev); // 初始化usb_device
dev->dev.bus = &usb_bus_type; // 设置usb_device的成员device->bus等于usb_bus总线
dev->dev.type = &usb_device_type; // 设置usb_device的成员device->type等于usb_device_type
return dev; // 返回一个usb_device结构体
usb_set_device_state(udev, USB_STATE_POWERED); //设置注册的USB设备的状态标识
choose_address(udev); /*分配一个地址编号 */
/* usb 1-1: new full speed USB device using s3c2410-ohci and address 3 **初始化端口,与USB设备建立连接*/
hub_port_init(hub, udev, port1, i)
retval = hub_set_address(udev); //(1)设置地址,告诉USB设备新的地址编号
retval = usb_get_device_descriptor(udev, 8); //(2)获得USB设备描述符前8个字节 status = usb_new_device(udev); //创建USB设备,与USB驱动连接
err = usb_get_configuration(udev); // 把所有的描述符都读出来,并解析
-->usb_parse_configuration
-->device_add // 把device放入usb_bus_type的dev链表,
// 从usb_bus_type的driver链表里取出usb_driver,
// 把usb_interface和usb_driver的id_table比较
// 如果能匹配,调用usb_driver的probe
}
小结
1)USB驱动程序源码的执行流程为:
2)usb_bus_type是一个全局变量, 和我们之前学的platform平台总线原理、结构体、设备与驱动节点、函数调用等相似, 属于USB总线, 是Linux中bus的一种. 每当创建一个USB设备,或者USB设备驱动时,USB总线都会调用match成员来匹配一次,使USB设备和USB设备驱动联系起来.
3)在分配一个地址编号时,USB接口最大能接127个设备,连续插拔两次USB键盘,也可以看出,如下图所示:
4)usb_get_device_descriptor()函数主要是获取目标设备描述符前8个字节,为什么先只开始读取8个字节?是因为开始时还不知道对方所支持的信包容量,这8个字节是每个设备都有的,后面再根据设备的数据,通过usb_get_device_descriptor()重读一次目标设备的设备描述结构.
5)那么USB驱动的id_table又该如何定义?
例如:参考/drivers/hid/usbhid/usbmouse.c (鼠标驱动)
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
//(1)USB_INTERFACE_CLASS_HID 为设置匹配USB的接口类型为HID类, 因为USB_INTERFACE_CLASS_HID=0x03,HID类是属于人机交互的设备,比如:USB键盘,USB鼠标,USB触摸板,USB游戏操作杆都要填入0X03
//(2)USB_INTERFACE_SUBCLASS_BOOT 为设置匹配USB的接口子类型为启动设备
//(3)USB_INTERFACE_PROTOCOL_MOUSE 设置匹配USB的接口协议为USB鼠标的协议,等于2;当.bInterfaceProtocol=1也就是USB_INTERFACE_PROTOCOL_KEYBOARD时,表示USB键盘的协议
{ } /* Terminating entry */
}; MODULE_DEVICE_TABLE (usb, usb_mouse_id_table); static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table,
};
源码分析完后,就可以自己写USB设备驱动程序了。
参考:https://www.cnblogs.com/lifexy/p/7631900.html
八、USB驱动分析的更多相关文章
- USB驱动分析
INIT函数: 这是内核模块的初始化函数,其所作的工作只有注册定义好的USB驱动结构体. USB驱动结构体如下: Usb_driver中的probe函数是驱动和设备匹配成功后调用. Usb_drive ...
- usb键鼠标驱动分析
一.鼠标 linux下的usb鼠标驱动在/drivers/hid/usbhid/usbmouse.c中实现 1.加载初始化过程 1.1模块入口 module_init(usb_mouse_init); ...
- Linux 串口、usb转串口驱动分析(2-2) 【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...
- Linux 串口、usb转串口驱动分析(2-1) 【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186851 Linux 串口.usb转 ...
- linux下usb转串口驱动分析【转】
转自:http://blog.csdn.net/txxm520/article/details/8934706 首先说一下linux的风格,个人理解 1. linux大小结构体其实是面向对象的方法,( ...
- linux设备驱动之USB主机控制器驱动分析 【转】
转自:http://blog.chinaunix.net/uid-20543183-id-1930831.html ---------------------------------------- ...
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
- linux驱动基础系列--Linux 串口、usb转串口驱动分析
前言 主要是想对Linux 串口.usb转串口驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如字符设备驱动.平台驱动等也不进行详细说明原理.如果有任何错误地方,请指出, ...
- linux驱动学习(八) i2c驱动架构(史上最全) davinc dm368 i2c驱动分析【转】
转自:http://blog.csdn.net/ghostyu/article/details/8094049 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 预备知识 lin ...
随机推荐
- 简谈 Java 中的泛型通配符
很好的一篇文章https://zhuanlan.zhihu.com/p/26681625
- spark学习地址
http://blog.sina.com.cn/s/blog_64d9a6ef0101ghvs.html http://blog.sina.com.cn/s/blog_49cd89710102v3b1 ...
- Java—IO流 RandomAccessFile类
RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件. 支持随机访问文件,可以访问文件的任意位置. java文件模型,在硬盘上的文件是byte byte byt ...
- 三大框架之list
前言: 在我们平常开发中难免会用到List集合来存储数据,一般都会选择ArrayList和LinkedList,以前只是大致知道ArrayList查询效率高LinkedList插入删除效率高,今天来实 ...
- C#使用Process类杀死进程,执行命令等
c#之process类相关整理 一.根据进程名获取进程的用户名? 需要添加对 System.Management.dll 的引用 using System.Diagnostics; using Sys ...
- Shell脚本批量修改图片尺寸
#!/bin/sh function scandir(){ local cur_dir parent_dir workdir workdir=$ cd ${workdir} if [ ${workdi ...
- Selenium2学习(十一)-- select下拉框
本篇以百度设置下拉选项框为案例,详细介绍select下拉框相关的操作方法. 一.认识select 1.打开百度-设置-搜索设置界面,如下图所示 2.箭头所指位置,就是select选项框,打开页面 ...
- March 2 2017 Week 9 Thursday
The first duty of love is to listen. 爱的首要责任是倾听. Yesterday, I read an article that says a successful ...
- Excel-怎样实现行列转置
有时候,我们为了某些需要,必须把工作表的行列进行转置的方式显示.重新输入很浪费时间,怎样简单的实现转置呢,强大的excel2007提供了此项功能,具体怎么做,下面看我来演示一下. 工具/原料 装有 ...
- makefile 编译指定目录
makefile 编译指定目录 sub1=test1 sub2=test2 subs = sub1 sub2 SUBDIRS =$(foreach i, $(subs), $($(i))) .PHON ...