当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > 什么是USB

什么是USB 时间:2017-09-26      来源:未知

一、相关概念:

1.什么是USB?

USB是Universal Serial Bus的缩写,中文译为通用串行总线。

那么与此USB相比,其他还有哪些非串行的总线,以及和此通用的串行总线来说,其他还有哪些相对“不通用”的串行总线呢?

从上述表格中,除了USB接口外,目前已存在的接口,还是很多的,而且各种接口实际上从硬件上也是形状各异,互相也都有自己的应用领域,而且无法兼容。基于此背景,才有下面的解释,以说明,为何会出现这么个USB接口。

 

2. 为何要有USB?

上面已经提到了,在USB出现之前,其实计算机领域中,已经存在众多的接口,而且不同的应用领域,已有一些相对来说是广泛使用的各种接口了。

但是,对于计算机等使用的普通用户来说,由于接口太多,而容易被搞得晕头转向。再加上各个接口从硬件形状和软件配置也都不一样,导致不兼容,为了不同的应用,而要配置多种不同的硬件接口,设置对于有些硬件接口来说,还需要手动去配置一些更细节的参数。

关于USB出现之前,计算机领域中的接口太多太繁杂,可以用下面这张,关于PC机箱背后的接口的图片来说明:

图  PC机箱后面的众多接口

所以,总的来说,在USB出现之前,各种接口太多,而且都不太容易使用,互相之间的兼容性也较差,因此,才出现了USB。

而万能的USB接口出现的话,整个PC机箱背后的接口,就不那么繁杂,显得清静多了:

图 有了USB接口之后的PC机箱背后的接口

 

USB出现的初的目的,根据USB规范中的解释,是为了:

(1)将PC和电话能连起来

由于大家都认识到,下一代的应用,肯定是实现计算机设备和通讯设备的完美融合。而且,为了实现移动领域内的人机数据的交互,也需要方便且不贵的连接方案。但是,计算机领域和通讯领域却是各自为政的发展,没有考虑互联性。由此,USB的出现,就是为了解决这一类互联问题的。

(2)方便用户使用

以前的一些设备,多数不支持即插即用,而且很多设备还需要懂行的用户去手动配置,然后才可以正常工作,而USB的出现,使得用户不用关心设备的细节,不需要去另外再配置什么参数,直接插上就可以用了,而且还支持即插即用,很是方便。

(3)接口扩展性要好

之前的众多接口,导致不同的应用,需要使用不同的接口,很是繁琐。USB的出现,支持众多的应用,都使用统一的USB的接口,方便了用户,不需要再搞懂各种接口的用途和差异。

总的来说,USB的出现,是希望通过此单个的USB接口,同时支持多种不同的应用,而且用户用起来也很方便,直接插上就能用了,也方便不同的设备的之间的互联。

说白了,就相当于在之前众多的接口之上,设计出一个USB这么个万能的接口,以后各种外设,都可以用这一种接口即可。

这估计也是USB的名称中的Universal通用的这一个词的来历吧。

 

3.USB控制器类型:OHCI,UHCI,EHCI,xHCI

【此时可以查看:drivers/usb/host/Kconfig】

OHCI:Open Host Controller Interface,创立者是Compaq,Microsoft和National Semiconductor。

UHCI:Universal Host Controller Interface,创立者是Intel。

两者之间的相同点是:

不论是OHCI还是UHCI都是对应于USB 1.1的标准的,都是完全符合USB协议标准的。

区别在于:只是各自的实现方式有些略微不同而已。当然对应的具体的性能,也略有差别,具体的差异,和实际的应用有关系。

但是本身OHCI和UHCI的区别在于:虽然都是实现了USB1.1协议规范,但是在功能划分上,OHCI更多地把要做的事情,用硬件来实现,因此,实现OHCI的USB控制器的软件驱动的开发工作,相对要容易些,软件要做的事情,相对较少。

对应地,OHCI更多地应用在扩展卡,尤其是嵌入式领域中,常见的很多开发板中的USB的控制器,很多都是OHCI的。

而UHCI把更多的功能,留给了软件,相对来说,软件做的事情,即负担要重些。但是实现对应的UHCI的硬件的USB控制器,价格上,就相对便宜些。

对应地,UHCI更多地应用在PC机中的主板上的USB控制器。

EHCI:定义了USB 2.0的主机控制器的规范,定义了USB 2.0的主控,需要包括哪些硬件实现,需要实现哪些功能,其也对应着对应的系统软件,所面对的是哪些接口

xHCI:Extensible Host Controller Interface,同EHCI是针对USB 2.0类似,xHCI是针对的USB 3.0规范。

 

4.USB的接口(connector)类型

由于USB的产生就是为了支持众多种应用的,而由于各种应用中,对于硬件接口的大小也有一些限制,比如有些小型设备或者移动式设备中,接口不能太大等,所以而设计出多种类型的接口,用于不同的应用。

在介绍插头和插座之前,先多解释一下,基本的叫法。

插头,plug,对应的也叫公口;

插座,receptacle,对应也叫做母口;

 

下面就来简单的介绍一下不同的USB接口类型,即各种不同的插头插座:

USB的接口类型,根据接口形状不同,主要可以分为三大类:

普通的硬件直接叫做Type

然后有小型版本的叫Mini迷你的

和更加小的,叫做Micro微小的

其中每一种大类中,又都可以分为两类

A类(Type A)

B类(Type B)

下面就用表格的形式,详细对比USB的各种接口,包括对应的插头和插座

5.USB系统架构

(1)拓扑结构

USB的结构主要包括了 USB 连接、 USB host controller和 USB device 三个部分。 而 USB device 还包括了 hub 和功能设备,什么是 USB controller?在一个 USB 系统中只能有一个 host,其实说白了就是咱们的主机,而 USB 和主机的接口就是 host controller,一个主机可以支持多个 host controller,比如分别属于不同厂商的。那么 USB host controller 本身是做什么的? controller,控制器,顾名思义,用于控制,控制什么,控制所有的 usb 设备的通信。通常计算机的 cpu 并不是直接和 usb 设备打交道,而是和控制器打交道,他要对设备做什么,他会告诉控制器,而不是直接把指令发给设备, 然后控制器再去负责处理这件事情, 他会去指挥设备执行命令,而 cpu 就不用管剩下的事情,他还是该干嘛干嘛去,控制器替他去完成剩下的事情,事情办完了再通知 cpu。 

一个 usb 控制器和一个 hub 绑定在一起,专业一点说叫集成,而这个 hub 也被称作 root hub, 其它的 hub 可以连接到她这里,然后可以延伸出去,外接别的设备,当然也可以不用别的 hub,让 usb 设备直接接到 root hub 上。 

USB 连接指的就是连接 device 和 host(或 hub)的四线电缆。

 

6.USB协议

 USB总线是一种轮询方式的总线。 协议规定所有的数据传输都必须由主机发起, host controller初始化所有的数据传输,各种设备紧紧围绕在主机周围。

USB 通信基本的形式是通过 USB 设备里一个叫 endpoint 的东东,而主机和 endpoint之间的数据传输是通过 pipe。 endpoint 就是通信的发送或者接收点,你要发送数据,那你只要把数据发送到正确的端点那里就可以了。端点也是有方向的,从 usb 主机到设备称为out 端点,从设备到主机称为 in 端点。严格来说,管道的另一端应该是 usb 主机,即前面说的那个 host,usb 协议里边也是这么说的,协议里边说pipes 代表着一种能力,怎样一种能力呢,在主机和设备上的端点之间移动数据。

为什么端点 0 就非要那么的个性那?这还是有内在原因的。管道的通信方式其实有两种,一种是 stream 的,一种是 message 的, message 管道要求从它那儿过的数据必须具有一定的格式,不是随便传的,因为它主要就是用于主机向设备请求信息的,必须得让设备明白请求的是什么。而 stream 管道就没这么苛刻,要随和多了,它对数据没有特殊的要求。

协议里说, message 管道必须对应两个相同号码的端点,一个用来 in,一个用来 out,咱们的缺省管道就是 message 管道,当然,与缺省管道对应的端点 0 就必须是两个具有同

样端点号 0 的端点。

USB endpoint 有四种类型,也就分别对应了四种不同的数据传输方式。它们是控制传输

( Control Transfers),中断传输( Interrupt Data Transfers),批量传输(Bulk DataTransfers),等时传输(Isochronous Data Transfers)。

控制传输:用来控制对 USB 设备不同部分的访问,通常用于配置设备,获取设备信息,发送命令到设备,或者获取设备的状态报告。总之就是用来传送控制信息的,每个 USB 设备都会有一个 endpoint 0 的控制端点,内核里的 USB core 使用它在设备插入时进行设备的配置。

中断传输:用来以一个固定的速率传送少量的数据,USB 键盘和 USB 鼠标使用的就是这种方式, USB 的触摸屏也是,传输的数据包含了坐标信息。

批量传输:用来传输大量的数据,确保没有数据丢失,并不保证在特定的时间内完成。 U 盘使用的就是批量传输,咱们用它备份数据时需要确保数据不能丢,而且也不能指望它能在一个固定的比较快的时间内拷贝完。

等时传输:同样用来传输大量的数据,但并不保证数据是否到达,以稳定的速率发送和接收实时的信息,对传送延迟非常敏感。显然是用于音频和视频一类的设备,这类设备期望能够有个比较稳定的数据流。

 

7.USB设备框架

在USB设备的逻辑组织中,包含设备、配置、接口和端点 4 个层次。

每个USB设备都提供了不同级别的配置信息,可以包含一个或多个配置,不同的配置使设备表现出不同的功能组合;

配置代表一个基本的功能,由多个接口组成,接口由多个端点组成,接口是 USB 设备驱动程序控制的对象,一个功能复杂的 USB 设备可以具有多个接口。每个配置中可以有多个接口,而设备接口是端点的汇集( collection)。

接口是设备的接口。设备可以有多个接口,每个接口代表一个功能,每个接口对应着一个驱动。例如:USB扬声器,可以包含一个音频接口以及对旋钮和按钮的接口。一个配置中的所有接口可以同时有效,并可被不同的驱动程序连接。每个接口可以有备用接口,以提供不同质量的服务参数。

(1)设备通常有一个或多个配置;

(2)配置通常有一个或多个接口;

(3)接口通常有一个或多个设置;

(4)接口有零或多个端点。

分析各个结构体:

结构体分析:

struct usb_device_descriptor {

__u8  bLength;

__u8  bDescriptorType;

 

__le16 bcdUSB;//USB版本号

__u8  bDeviceClass;//类

__u8  bDeviceSubClass;//子类

__u8  bDeviceProtocol;//协议

__u8  bMaxPacketSize0;//端点0的大包数量

__le16 idVendor;//厂家ID

__le16 idProduct;//产品ID

__le16 bcdDevice;

__u8  iManufacturer;

__u8  iProduct;

__u8  iSerialNumber;

__u8  bNumConfigurations;//配置的个数

} __attribute__ ((packed));

此时查看设备中的USB设备中的属性,这些属性的获得是通过发出命令,获取该结构体信息;除了设备描述符还有那些描述符呢?

 

配置描述符:

struct usb_config_descriptor {

__u8  bLength;//该描述符的长度

__u8  bDescriptorType;//类型

 

__le16 wTotalLength;//该配置下所有信息的总长度

__u8  bNumInterfaces;//接口个数

__u8  bConfigurationValue;

__u8  iConfiguration;

__u8  bmAttributes;//属性

__u8  bMaxPower;//消耗的电源

} __attribute__ ((packed));

 

接口描述符:----->逻辑上的设备---->功能

例如:usb声卡,硬件上只有一个声卡,但是其逻辑功能既可以录音又可以播放,故此时需要用两个接口描述符对其进行描述;驱动写的是逻辑上的设备

struct usb_interface_descriptor {

__u8  bLength;//长度

__u8  bDescriptorType;

 

__u8  bInterfaceNumber;//接口个数

__u8  bAlternateSetting;

__u8  bNumEndpoints;//端点个数

__u8  bInterfaceClass;

__u8  bInterfaceSubClass;

__u8  bInterfaceProtocol;

__u8  iInterface;

} __attribute__ ((packed));

 

端点描述符:

struct usb_endpoint_descriptor {

__u8  bLength;

__u8  bDescriptorType;

 

__u8  bEndpointAddress;//端点地址

__u8  bmAttributes;//属性,端点类型:输入/输出/批量/控制等

__le16 wMaxPacketSize;//大包的大小

__u8  bInterval;//端点被查询的频繁程度

 

/* NOTE:  these two are _only_ in audio endpoints. */

/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */

__u8  bRefresh;

__u8  bSynchAddress;

} __attribute__ ((packed));

 

8.usb设备的链接

将 usb 设备连接在 hub 的某个端口上, hub 检测到有设备连接了进来,就觉得有必要为设备做点什么。它会为设备分配一个 struct usb_device (usb_alloc_dev )结构的对象并初始化,并调用设备模型提供的接口将设备添加到 usb 总线的设备列表里,然后 usb 总线会遍历驱动列表里的每个驱动,调用自己的 match 函数看它们和你的设备或接口是否匹配。

 

1.由电脑上插接usb设备引出相应概念

(1)右下角弹出“发现xxx设备”;

(2)若未安装驱动程序,则自行安装驱动;

 

匹配图:

问题1.既然还没有“相应设备的驱动程序”为何能知道“phone”?

答:windows中已经有了USB的总线驱动程序,接入USB设备后,是“总线驱动程序”指导设备识别“phone”并提示安装“设备驱动程序”;“usb总线驱动”负责识别USB设备,给USB设备找到对应的驱动程序;

 

问题2.USB设备种类非常多,为什么一接入电脑,就能识别出来?

答:PC和USB都得遵守一些规范;

比如:USB设备接入电脑后,PC机会发出“你是什么”?

 USB设备就必须回答“我是xxx”.并且回答的格式也得一致;

 USB总线驱动程序会发出某些命令想获取设备信息(描述符)。

 USB设备必须返回“描述符”给PC.

 

引出USB驱动框架:

APP:

设备驱动:--->usb设备

(1)知道收发数据的具体含义

usb驱动:

USB总线驱动:--->usb主机控制器

(1)识别设备

(1.1)分配编号

(1.2)并告诉USB设备(set address)

(1.3)发出命令获取描述符

(2)找到并安装对应的USB设备驱动

(3)提供USB读写函数

USB主机控制器

UHCI OHCI EHCI

硬件:

USB设备

使用USB总线控制器程序的函数把包发送给USB主机控制器,由USB主机控制器产生信号发送给USB设备;

UHCI:intel,低速usb1.1(1.5mbps)/全速usb2.0(12mbps)(全速/高速)

OHCI:microsoft,低速/全速

EHCI:高速(480mbps)

当插入一个USB设备时,主机控制器会因为d+/d-出现电平变化,主机控制器会产生一个中断——hub_irq();

问题3.PC机上有非常多的USB设备,怎么分辨他们?

答:USB接口只有四根线:5v ,gnd , d+ , d-

每个USB设备接入PC时,USB总线驱动程序都会给它分配一个编号,接在USB总线上的每一个USB设备都有自己的编号(地址),pc机想访问某个USB设备时,发出的命令都含有对应的编号。

 

问题4.USB设备刚接入PC时,还没有编号,那么PC怎么把“分配的编号”告诉它?

答:新接入的USB设备的默认编号是0,在未分配新编号前,PC使用0和他进行通信。

 

问题5.为什么一接入USB设备,pc机就能发现它?

答:PC的USB口内部,D-和D+接有15K的下拉电阻,未接入USB设备时为低电平。

USB设备的USB口内部,D+或D-接有1.5K的上拉电阻,它一接入PC就会把PC的USB口的D+/D-拉高,从而从硬件的角度通知PC有usb设备接入。

 

2其他概念:

(1)usb是主从结构的:所有usb的传输都是从USB主机这方发起,USB设备没有主动通知USB主机的能力;

例如:usb鼠标滑动一下立刻产生数据,但是他没有能力主动通知PC来读取数据,只能被动地等待pc机读取,PC连续不断地进行查询;

(2)USB传输类型

a.U盘:批量传输,可靠,但是时间没有保证;

b.USB鼠标:中断传输,实时,可靠;

c.USB摄像头:实时传输,实时,数据不可靠;

d.usb设备识别:控制传输,可靠,时间有保证;

 

3.USB传输的对象:端点(endpoint)

“读U盘”:把数据写到U盘的端点1;

“写U盘”:从U盘的端点2读出数据;

除了端点0外,每一个端点只支持一个方向数据传输;

端点0用于控制传输(识别USB设备);既能输出也能输入;

 

4.每一个端点都有传输类型,传输方向

 

5.程序中,术语中所说的输入IN/输出OUT都是基于USB主机的立场而言的;

比如:鼠标:鼠标------数据------>PC机      输入端点

 

6. 既然USB总线驱动程序已经有了USB的读写函数,那么应用程序能否跨过USB设备驱动,直接通过这些读写函数直接访问对应的USB设备?

答:可以,通过libusb

当USB设备插入主机,则USB主机控制器会出现电平变化,则此时就会出现一个中断,参考:/driver/usb/core/hub.c

int usb_hub_init(void)

khubd_task = kthread_run(hub_thread, NULL, "khubd");

static int hub_thread(void *__unused)

hub_events();

hub_port_connect_change(hub, i,portstatus, portchange);

udev = usb_alloc_dev(hdev, hdev->bus, port1);

dev->dev.bus = &usb_bus_type;

struct bus_type usb_bus_type = {

.name = "usb",

.match = usb_device_match,

.uevent = usb_uevent,

};

static int usb_device_match(struct device *dev, struct  device_driver *drv)

intf = to_usb_interface(dev);

id = usb_match_id(intf, usb_drv->id_table);

id = usb_match_dynamic_id(intf, usb_drv);

 

choose_devnum(udev);

devnum = find_next_zero_bit(bus->devmap.devicemap, 128,

   bus->devnum_next);

devnum = find_next_zero_bit(bus->devmap.devicemap,128, 1);

bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);

status = hub_port_init(hub, udev, port1, i);

retval = hub_set_address(udev, devnum);

retval = usb_get_device_descriptor(udev, 8);//获取设备描述符的前八 //个成员

retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);

 

status = usb_new_device(udev);

 

wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) ||

kthread_should_stop());

9.USB的设备驱动

USB设备驱动指的是从主机角度来观察,怎样访问被插入的USB设备,而不是指USB设备内部本身运行的固件程序,usbfs ——“USB device filesystem”,动态跟踪总线上插入和移除的设备,通过它可以查看系统中 USB 设备的信息,包括拓扑、带宽、设备描述符信息、产品 ID、字符串描述符、配置描述符、接口描述符、端点描述符等。

在上面已经分析过当USB设备插入时,usb主机会对该USB进行相应的端点分配及设备描述符识别,此时相当于设备信息已经被提供了。在编写USB驱动时主要是实现struct usb_driver的分配,填充及注册等;

1 struct usb_driver {

2 const char *name; /* 驱动名称 */

3 int (*probe) (struct usb_interface *intf,

4 const struct usb_device_id *id); /*探测函数*/

5 void (*disconnect) (struct usb_interface *intf); /*断开函数*/

6 int (*ioctl) (struct usb_interface *intf, unsigned int code,

7 void *buf); /* I/O 控制函数 */

8 int (*suspend) (struct usb_interface *intf, pm_message_t message);/*挂起函数*/

9 int (*resume) (struct usb_interface *intf); /* 恢复函数 */

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

11 void (*pre_reset) (struct usb_interface *intf);

12 void (*post_reset) (struct usb_interface *intf);

13 const struct usb_device_id *id_table;/* usb_device_id 表指针 */

14 struct usb_dynids dynids;

15 struct usbdrv_wrap drvwrap;

16 unsigned int no_dynamic_id:1;

17 unsigned int supports_autosuspend:1;

18 unsigned int soft_unbind:1;

19 };

在编写新的 USB 设备驱动时,主要应该完成的工作是 probe()和 disconnect()函数,即探测和断开函数,它们分别在设备被插入和拔出的时候被调用,用于初始化和释放软硬件资源。对usb_driver 的注册和注销通过这两个函数完成:

(1)int usb_register(struct usb_driver *new_driver);

功能:注册usb驱动

参数:struct usb_driver :struct usb_driver 结构体指针

返回值:成功: 0    失败:错误码的绝对值

(2)void usb_deregister(struct usb_driver *driver);

功能:注销usb驱动

参数:struct usb_driver :struct usb_driver 结构体指针

返回值:无

usb_driver 结构体中的 id_table 成员描述了这个 USB 驱动所支持的 USB 设备列表,它指向一个 usb_device_id 数组, usb_device_id 结构体用于包含 USB 设备的制造商 ID、产品 ID、产品版本、设备类、接口类等信息及其要匹配标志成员 match_flags(标明要与哪些成员匹配,包含 DEV_LO、DEV_HI、 DEV_CLASS、 DEV_SUBCLASS、 DEV_PROTOCOL、 INT_CLASS、 INT_SUBCLASS、INT_PROTOCOL)。可以借助下面一组宏来生成 usb_device_id 结构体的实例:

 

USB_DEVICE(vendor, product);

该宏根据制造商 ID 和产品 ID 生成一个 usb_device_id 结构体的实例,在数组中增加该元素将意味着该驱动可支持匹配制造商 ID、产品 ID 的设备。

USB_DEVICE_VER(vendor, product, lo, hi);

该宏根据制造商 ID、产品 ID、产品版本的小值和大值生成一个 usb_device_id 结构体的实例,在数组中增加该元素将意味着该驱动可支持匹配制造商 ID、产品 ID 和 lo~hi 范围内版本的设备。

USB_DEVICE_INFO(class, subclass, protocol);

该宏用于创建一个匹配设备指定类型的 usb_device_id 结构体实例。

USB_INTERFACE_INFO(class, subclass, protocol)

该宏用于创建一个匹配接口指定类型的 usb device id 结构体实例。

 

当 USB 核心检测到某个设备的属性和某个驱动程序的 usb_device_id 结构体所携带的信息一致时,这个驱动程序的 probe()函数就被执行。拔掉设备或者卸掉驱动模块后, USB 核心就执行disconnect()函数来响应这个动作。

上述 usb_driver 结构体中的函数是 USB 设备驱动中 USB 相关的部分,而 USB 只是一个总线,真正的 USB 设备驱动的主体工作仍然是 USB 设备本身所属类型的驱动,如字符设备、 tty 设备、块设备、输入设备等。因此 USB 设备驱动包含其作为总线上挂在设备的驱动和本身所属设备类型的驱动两部分。

与 platform_driver 类似, usb_driver 起到了“牵线”的作用,即在 probe()里注册相应的字符、tty 等设备,在 disconnect()注销相应的字符、 tty 等设备,而原先对设备的注册和注销一般直接发生在模块加载和卸载函数中。

尽管 USB 本身所属设备驱动的结构与其不挂在 USB 总线上时完全相同,但是在访问方式上却发生了很大的变化,例如,对于 USB 接口的字符设备而言,尽管仍然是 write()、 read()、 ioctl()这些函数,但是在这些函数中,贯穿始终的是称为 URB 的 USB 请求块。

usb_driver 本身只是起到了找到 USB 设备、管理 USB 设备连接和断开的作用。

 

程序编写流程:

1.定义struct usb_driver

2.设置struct usb_driver

3.注册

4.硬件相关的操作

上一篇:五种常见的IO模型

下一篇:Zigbee——串口无线透传分析

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部