Others6_USB Type-C到底是什么

本文详细介绍了Type-C接口的特点和优势,包括其正反插设计、兼容性以及未来的应用场景。Type-C不仅解决了传统USB接口方向难以辨认的问题,还具备高速数据传输、视频输出和大功率充电的能力。

1 多功能正反插 苹果让大众认识Type-C

    “Type-C”这个名称随着苹果全新一代MacBook笔记本电脑的发布而变得人尽皆知,很多人都惊呼“哇!一个接口就可以充当USB、视频输出及电源如此多接口的作用,真是神了!”

    Type-C接口的出现似乎又把苹果推向了神坛,很多人认为这是苹果的壮举,殊不知在新Macbook发布之前Type-C接口就早已出现,而Type-C的标准当然也不是苹果指定的。在这里,笔者要为诺基亚N1平板默默的流个泪,因为N1所配备的Type-C接口明明要比新Macbook早出现了2个月。

新MacBook绝招:Type-C USB到底是什么
新MacBook携Type-C接口横空出世也让普通大众认识到了这种新型接口

    不得不承认,沾了苹果的光就可以迅速的被人熟知,而苹果也的确有能力将一个标准进一步推广,且往往能够获得成功……当然,悲催的雷电(Thunderbolt)接口除外,它基本上已经销声匿迹了。不过本次新MacBook应用Type-C接口真的是非常恰当,薄至极限的机身无法承载大量且体积不小的接口,而小巧的Type-C能够集充电、数据传输及视频输出于一身。作为行业的领导者,苹果的创新能力及实力还是值得肯定的。

    回到我们讨论的原点:那么Typc-C到底是什么

新MacBook绝招:Type-C USB到底是什么

    Type-C全称USB Type-C接口,是一种全新的USB接口形式,它伴随最新的USB3.1标准横空出世,从发布至今已经有近一年的时间了(没错,真的是一年)。说到底,它就是一个USB接口(没错)。其实,Type-C对于新MacBook的价值甚至没有它作为一个单纯的USB接口大,因为它解决了自USB接口出现以来最令人头疼的世界性难题,那就是它“不再区分方向,正反都可插”。

新MacBook绝招:Type-C USB到底是什么
正反都可插的USB接口,这简直太爽了

    Type-C接口的出现可以说拯救了强迫症及处女座,也让诸如“吸引力法则”、“墨菲定律”等令人头疼的问题得以消失。

    好的,尽管知道了Type-C接口大概能实现什么功能以及它究竟是个什么东西,但可能很多人还会有一个疑问如鲠在喉,那就是“为什么叫Type-C?A和B都去哪了呢?

    的确,A和B都去哪了呢?这的确是一个好问题,另外,笔者也将深入的对USB历代标准及接口发展进行展开讨论,让大家明明白白。


这一页让你搞清所有规格USB接口

    既然有Type-C,那一定就会有Type-A和Type-B。究竟Type-A和Type-B长得什么样子,看下面这张图各位就一目了然了:

新MacBook绝招:Type-C USB到底是什么
USB接口:从左到右依次为标准Type-A接口、Type-B接口及Type-C接口

    看完图大家就应该恍然大悟了:原来Type-A接口就是我们平常用的最多的标准USB接口!也的确,Type-A接口的英文名称就是“Standard Type-A USB”,这说明它是标准的USB接口,而其它形状的USB接口都是它的衍生物。

    对于Type-B USB接口,尽管它的出镜率远没有标准Type-A接口高,但想必大家对它也不会陌生,因为诸如打印机、显示器USB HUB等诸多外部USB设备都采用了Type-B USB接口。一般来说,PC上的USB接口均为标准Type-A,而外部设备则多采用Type-B

    最后,就是全新出场的Type-C接口了。它拥有比Type-A及Type-B均小得多的体积,其大小甚至能与Mini-USB及Micro-USB相媲美,是最新的USB接口外形标准。另外,Type-C是一种既可以应用在PC(主设备)又可以应用在外部设备(从设备)的接口类型,这是划时代的

    等等,刚才提到的Mini-USBMicro-USB是否再可以详细讲一讲呢?

    没问题……

●看完别晕:USB接口全家福

    在Type-C接口发布后,有朋友问到笔者:“是不是Mini-USB就叫Type-A,Micro-USB就叫Type-B,新出来的这个叫Type-C?”事实上笔者前文已经告诉大家并不是这么回事,那么看完下面这张USB接口的全家福,相信大家一定都会明白了。

新MacBook绝招:Type-C USB到底是什么
USB接口全家福(除Type-C)

    什么也比不上一张图直观。我们经常使用的Mini-USB及Micro-USB都是根据USB2.0传输协议诞生,神奇的是,它们也都分别分为Type-A和Type-B。到了USB3.0时代,由于传输速度的提升带来了针脚位的提升,因此仅有Type-A USB3.0接口保持与以往形状一样,Type-B和Micro-USB都改变了外形(体积增大)。

Mini-USB2.0接口

新MacBook绝招:Type-C USB到底是什么
Mini-USB 2.0的A及B型接口

    Mini-USB接口也是我们非常熟悉的一种接口,它被广泛应用在数码产品上,诸如MP3,数码相机以及移动硬盘等等。相较标准USB接口及Type-B USB接口,它的体积大大缩小。可能大家见到的Mini-USB接口绝大多数都是Mini-B型,这是因为Mini-A型就接口的防呆性较差,因此才有了取代它的Mini-B型。不过不用担心,即使是较老的配备Mini-A接口的设备仍然可以通用Mini-B型的数据线。

Micro-USB2.0接口

新MacBook绝招:Type-C USB到底是什么
Micro-USB 2.0的A及B型接口

    Mini-USB接口分A/B,Micro-USB也不例外。Micro-USB接口是Mini-USB接口的改良版,它再次缩小了体积,更适用于现在越来越轻薄的移动设备。目前我们所使用的便携设备,绝大多数都采用了Micro-USB接口,Mini-USB已基本被淘汰。另外,欧盟也规定到2017年,所有在加盟国销售的手机必须采用Micro-USB接口,足见其成功及广大覆盖率。

    同样的,Micro-USB接口的Type-B型也是Type-A型的改良版,从图中大家不难看出Micro-A接口形状为矩形,这大大增加了误插率!要知道连标准USB接口还经常插错的我们,怎么可能玩得转如此之效的Micro-A?很快Micro-B出现,防呆设计优秀,Micro-A也就迅速的被淘汰了。

Micro-USB3.0接口

新MacBook绝招:Type-C USB到底是什么
Micro-USB 3.0的A及B型接口

    由于USB3.0接口的传输速度相较USB2.0有了大幅度的提高,因此它的针脚也发生了变化。这样一来,Micro-USB3.0接口不得不在外观上做出改变。Micro-USB3.0接口在高度上与Micro-USB2.0无异,但是长度明显增长了。同样的,A型和B型也在Micro-USB3.0上出现了……笔者真的无法理解为什么USB协会每次都要在小型的USB接口上搞个A和B,这里就不多吐槽了。

    我们接触最多的Micro-USB3.0接口设备就要数高速移动硬盘了,其中绝大多数均为Type-B类型。

USB Type-B有点囧

新MacBook绝招:Type-C USB到底是什么
同样是Type-B接口,USB3.0(右)比USB2.0(左)增加了接口高度

    标准Type-A USB接口由于体积较大,因此在发展到USB3.1的今天,它的外形也没有改变。但是Type-B USB接口就稍微有些尴尬了,因为论体积它并不比标准Type-A USB接口小多少,但是或许是设计之初并未考虑到今后的发展,导致了增加的针脚无处放置。因此Type-B USB3.0接口不得不改变了外观,较Type-B USB2.0增加了高度。

USB3.1接口与Type-C

新MacBook绝招:Type-C USB到底是什么 USB3.1接口与USB3.0接口仍然以颜色来区分

    在行业内,USB3.0接口被做成蓝色以便和USB2.0接口的黑色相区分。目前,华硕已经推出了配备标准Type-A USB3.1接口的主板,其接口颜色为蓝绿色,与USB3.0相区分。尽管USB协会并未对USB3.1的颜色做出规定,但是以颜色来区分也将是必然。

    笔者再次重申,Type-C接口与USB3.1标准几乎同时推出,Type-C的规范也确实是按照USB3.1所制定,因此USB3.1当然可以制作为Type-C类型,但Type-C≠USB3.1:比如诺基亚N1平板就采用了USB2.0规范的Type-C接口,而华硕Z97-K/USB3.1就使用了标准Type-A的USB3.1接口

历代USB规格对比

版本

最大传输速率

代号

最大输出电流

USB1.0

1.5Mbps

LowSpeed

500mA

USB1.1

12Mbps

FullSpeed

500mA

USB2.0

480Mbps

HighSpeed

500mA

USB3.0

5Gbps

SuperSpeed

900mA

USB3.1

10Gbps

SuperSpeed+

900mA

Micro-USB/Lightning/Type-C对比

    除苹果公司产品之外,先进市面上几乎所有的移动设备都采用了Micro-USB接口。而苹果自从iPhone 5开始也将之前的Dock口换为了体积更加小巧的Lightning接口,它与Micro-USB接口的大小相近。而现在,Type-C接口横空出世,未来一段时间内很可能会出现三足鼎立之势。

新MacBook绝招:Type-C USB到底是什么 新MacBook绝招:Type-C USB到底是什么
从上到下依次为:Micro-USB-B/Lightning/Type-C

    上图为三款设备分别为采用Micro-USB接口的安卓手机、采用Lightning接口的iPhone 5S以及采用Type-C接口的诺基亚N1。

    其中,Micro-USB接口拥有防呆设计,只能单面插入。而Lightning接口及Type-C接口则均可以正反插,大大方便了用户平日的使用。不过在这里还是要说句题外话,那就是自从苹果采用Lightning接口后,算上购买手机附送的数据线,笔者已经更换了6、7条Lightning数据线,它们会在很快的时间坏掉,这可是Dock口时代笔者从未经历的事!或许Lightning接口的耐用度设计还有待完善。

新MacBook绝招:Type-C USB到底是什么
Type-C/Lightning/Micro-USB-B公头对比

    Type-C接口的尺寸为8.3mm×2.5mm,它的大小与Micro-USB及Lightning都较为相近,便携度毋庸置疑。

一些遐(瞎)想

    USB3.1规格拥有10Gbps的传输速率,是USB3.0 5Gbps的两倍之多,达到了雷电接口一样的速度。拥有超高带宽的同时它还支持高达100W的强悍电力传输功能,另外,Type-C接口还可作为视频输出接口。

新MacBook绝招:Type-C USB到底是什么
采用三种接口的主流设备

    目前HDMI 1.4规范的带宽为10.2Gbps,与USB3.1的10Gbps近乎于等速,加之新MacBook所采用的Type-C接口已经集成了DP、HDMI与D-Sub接口。多种功能的高集成度以及强力的性能,在未来我们完全可以有理由相信Type-C会成为取代诸多视频以及数据接口,成为统一众多接口的完美解决方案。

    另外,高冷的苹果总会与别人不一样,无论是之前的Dock口还是现在的Lightning口,都异于非苹果设备的Micro-USB接口。但是新MacBook采用了Type-C接口可以说给了大家以期盼:在未来苹果产品是否会统一采用Type-C呢?毕竟Type-C接口是通用标准,这样以后我们再也不用配备很多根数据线了。

新MacBook绝招:Type-C USB到底是什么
Type-C是一种既可以用在主设备又可用在从设备上的划时代接口(图片援引Intel IDF官方资料)

    Type-C是革命性的出现,什么这么说?在前文当笔者放出那张USB接口全家福的时候,大家是否都会感觉太乱了呢?没错,主设备接口、从设备接口以及移动设备接口的形状全都不一样,而每类接口还又分为A/B等等……我们不禁发出一声感叹:为什么就不能统一呢?Type-C的出现则解决了这一问题,不同于只在主设备使用的Type-A、只在从设备使用的Type-B以及只在移动设备使用的Mini&Micro-USB,它是一种既可以在主设备,又可以在从设备,还可以在移动设备使用的接口。

新MacBook绝招:Type-C USB到底是什么
不光USB接口规范众多(混乱),其它接口同样存在这个问题(图为HDMI接口的四种类型)

    USB接口规范的混乱并不是个例,有很多接口也存在着类似的问题。比如HDMI,我们常见的是标准HDMI(A)以及mini HDMI(B),但还有Micro(D)以及体积庞大的D型,似乎后两者的出现也显得没有必要。不过Type-C这么强劲,在未来HDMI接口是否还会有生存的空间呢?

    搭上高速的USB3.1速度规格,拥有小巧的外形,解决了困扰用户多年的“世界性难题”(终于可以正反插),模糊了主设备和从设备的接口区别,打破了移动设备的专属接口规范,集成了视频传输功能,继承了USB接口一切优良的血统……这就是Type-C,一个未来不容小视的新霸主接口。


http://diy.pconline.com.cn/628/6288037_3.html

在通用路上越走越远:USB接口演化史

USB,全称为通用串行总线,是连接计算机系统与外部设备的一种串口总线标准,也是一种I/O接口的技术规范。如今的USB接口可以说已经是最为人们所熟知的一种I/O接口,被广泛地应用于个人电脑和移动电子设备之中。而作为一种通用性极强的技术标准,它的发展也并非我们想象中那么一帆风顺,水到渠成。随着配备最新USB 3.1接口设备的逐渐到来,今天我们就来细说一下USB接口那一段不平凡的演化史。

USB 1.1/1.0:简化复杂的连接方式

老式设备中常见的LPT和COM接口已被USB取代

在USB接口诞生之前,那时候的计算机大多通过串行接口和并行接口与外部设备交换数据。但问题是,这些接口的传输速率都比较低,有时这些接口甚至还不能同时运行,而随着处理器速度的快速提升,电脑与外部设备之间的接口数据传输速度也需要逐步提高,不然就会成为电脑发展的瓶颈。此外,外部设备的传输接口也不尽相同,如打印机需要用并口、MODEM要使用串口、鼠标键盘要接PS/2口等等。数量繁多的接口种类,还要安装驱动才能正常使用,都容易造成用户的困扰。于是乎,随着PC硬件的发展,人们越来越需要一种适用性广、传输速度快、软件配置简单的外部接口,这就促成了USB(通用串行总线)接口的诞生。1994年,一个由Intel、微软、IBM、NEC、Compaq、DEC、Nortel等公司为成员组成的USB开发者论坛(USB-IF)正式成立。

iMac G3大胆启用USB取代传统接口

在1994到1995年间历经多个预发布版本之后,1996年1月,USB 1.0正式版终于发布,它支持两种数据传输速率,一种为1.5Mb/s的低速速率(Low Speed),另一种则是12Mb/s的全速速率(Full Speed)。但作为一种新兴接口,当时支持USB接口设备较少,而且因为延时和供电问题,USB 1.0接口也不支持使用延长线,对比传统的传输接口,USB尚未具备明显的优势。USB 1.1标准在1998年8月发布,着力改进了此前USB HUB方面的问题,理论上最多可支持127个外部设备。同年,PC历史上具有里程碑意义的苹果iMac G3发布,它非常激进地使用了USB接口取代传统的串行和并行接口;Intel也在其主板芯片组上不断加强对USB的支持,这些都为日后USB的普及铺平了道路,也是从此时USB开始逐渐被人们所接受。凭借其易用性、更高的传输速率和其他技术特性,USB终于一举超越先前其他各种接口,直至今天依然是最被广泛使用的接口标准。

TREK拇指盘,首款在市场上销售的U盘类设备

正如外部设备催生了USB接口标准,USB的普及同时也推动了其他外部设备的快速发展。已知的第一款正式在市场上销售的U盘,在2000年由新加坡的TREK公司推出,支持USB 1.1标准。现在我们可以轻松地一眼认出这是一个U盘,因为从外观上说它跟目前市面上很多其他的U盘并无大的区别,但它只有8MB大的存储空间;而现在市售的U盘中,我们可以买到容量高达1TB的U盘(嗯没错就是国民老公同款U盘),达到了前者10万倍以上。

USB 2.0:More than PC

不过随着各种外部设备对数据传输速率需求的提高,USB 1.1那12Mb/s的带宽也是越发捉襟见肘,在接入较多外部设备时,多个数据流同时传输容易引发瓶颈效应,为了解决传输速率问题,USB 2.0应运而生。USB 2.0标准在2000年正式发布,加入了40倍于原先全速速率(Full Speed)的高速速率(Hi-Speed),理论带宽达到480Mb/s,同时也向下兼容USB1.1标准的全速速率(因此需要注意的是,并非所有宣称支持USB 2.0的设备都能达到高速速率,也可能是速度较低的全速速率)。由于受制于BOT传输协议和NRZI编码方式,实际USB 2.0的最大传输速度在30~35MB/s之间。

Micro B、Mini B开拓便携设备市场

但USB接口的演化并非只有速率变化那么简单。对于体积比较轻薄小巧的外部设备来说,PC上面常见的Type-A接口,显然不太适合。同年10月,USB-IF非常有预见性地发布了Mini A、Mini B接口标准,为USB接口在移动设备上的普及打下了坚实的基础。2007年加入的Micro USB标准,比起Mini USB更加小巧和耐用,目前已经被应用于大部分的移动设备上。

非标准USB的Nokia Pop-Port、苹果Lightning接口

虽然基于技术和市场等原因,曾经也有不少厂商没有使用标准的USB接口,而采用自己设定的一套接口规范(比如Nokia Pop-Port),但如今也只有牛气如苹果,才能继续坚持这样做下去。

USB OTG使传统的从属设备也能成为主机端

另一个USB 2.0后带来的重要变化,就是引入了USB OTG(On-The-Go)作为其补充标准。简单来说,标准的USB使用主从式的架构,USB主机端(PC)为“主”,而USB外部设备为“从”,只有主机端可以调度该链接的设置与数据传输,而外接的USB设备不能够自行启动数据传输,只能回应主机端的指令。OTG的加入改变了这种状况,传统的外部设备也并不一定就只能是外部设备,它们也可以成为主机端。比如,手机、平板等设备在连接电脑时作为外接存储设备存在,但当它们通过OTG与U盘等设备连接时,又能作为主机端,修改和读取U盘内的数据。当然,除了U盘,这些设备还可以是键盘、鼠标、打印机等等很多……

USB诞生的初衷是为了简化电脑和外部设备的连接,但至此USB已经从PC跨越到其他电子产品领域上,并由此衍生出了多种新的应用。

USB 3.0:速度大爆发

随着技术的发展和高清播放时代的来临,就如当初USB 1.1一样,USB 2.0 Hi-Speed 480Mb/s的传输速度逐渐也不能满足我们的需求,于是在2008年,USB-IF又带来了USB 3.0标准。新标准带来了高达5Gb/s(Super Speed)的理论带宽,达到原有USB 2.0 480Mb/s的十倍以上,但同时也向下兼容USB 2.0和1.1标准。

USB 3.0新增两对线路(SDP Signal Pair)使数据可以同时双向传输

USB 2.0时代使用半双工的传输方式,即只能提供单向的数据传输;而USB 3.0接口增加了在2.0基础上增加了4条引脚(一对负责发送,一对负责接收),实现了全双工传输,发送数据和接收数据可以同步进行,从而大大提高了传输带宽。

8b/10b编码方式

为了实现更高的传输速度,USB 3.0没有再使用此前的NRZI编码方式,而是引入了被广泛应用于PCIE 2.0、SATA 3.0、光纤通道上的8b/10b编码方式,因此从传输角度上看,比起USB 2.0,USB 3.0反而与PCIE 2.0、SATA 3.0更为相似。这种编码方式是在每8bit数据内插入2bit校验数据,以保证接收端数据能正确还原。当然这种编码方式也会导致数据传输时不能达到理论的最大带宽,实则为5Gb/s的八成,即4Gb/s(500MB/s)。传输协议同样会导致一定的可用带宽损失,不过在实际使用中,仍然能够达到接近400MB/s的极限传输速度。

USB 3.0接口的最大输出电流达到900mA,比起USB 2.0的500mA增加了80%。USB 2.0时代,不少7200转的2.5英寸移动硬盘,都需要使用Y型的USB线材,接入多一个额外的USB接口才能作为补充供电,才能正常运行;而USB 3.0充足的电力供应使单接口就能够驱动更多类似的设备,同时也能缩短移动设备的充电时间。虽然因为速度的提高,数据传输时USB 3.0要比USB 2.0更加耗电,但与此同时传输耗时大大缩短,每1GB数据传输的耗电量要远低于USB 2.0。电源管理方面也更加智能,在USB 3.0中,除了原有的U0(连接)及U3(暂停)外,还加入了U1(待机和快速恢复)和U2(待机和缓慢恢复)两种电源状态,可有效降低设备在不传输或接收数据时的耗电量。

USB 3.0扩展卡可能不能完全发挥性能

然而,USB 3.0同样存在着一些小问题。虽然在2008年该标准就已正式发布,但直至2012年7系主板推出之后,Intel才正式原生提供对USB 3.0支持。而在USB 3.0普及的前期,接口主要是通过第三方芯片接入主板南桥提供的,通道的速率最大可能只有2.5Gb/s,这还只有USB 3.0的5Gb/s的一半,因此性能受到了一定的限制。

使用延长线避免无线设备受到USB 3.0干扰

此外,USB 3.0接口在使用时,有可能会对附近使用2.4GHz频段的无线和蓝牙设备造成干扰,从而引起设备信号衰减甚至是失去响应,因此需要使用HUB延长线或是将无线设备接入到离USB 3.0接口较远的接口处,才能解决这个问题。

USB 3.1与Type-C:接口大一统时代来临?

USB 3.1速度翻一番

最后我们来谈谈最新的USB 3.1标准。USB 3.1标准于2013年7月发布,最大理论带宽相比3.0时翻了一番,达到10Gb/s(Super Speed+),与第一代的Thunderbolt相同。USB 3.1编码方式从此前的8b/10b换成了128b/132b,带宽损耗率从20%大幅下降到3%左右,换算之后带宽同样超过了1.2GB/s,这也意味着在真实使用中USB 3.1的极限传输速率有望突破每秒1GB。USB 3.1可向下兼容USB 3.0/2.0/1.1等旧标准。

加入屏蔽处理措施避免电磁干扰

另外,针对USB 3.0时出现的电磁干扰问题,USB 3.1的Type-A接口处加入了金属屏蔽罩和更多的接地弹片,从而有效降低了对附近其他设备的干扰。

小巧、正反可插的USB 3.1 Type-C接口被寄予厚望

虽然像过去的升级一样,USB 3.1同样带来了更高的传输速率,并修复了此前存在的各方面问题,但人们谈论更多的都是随USB 3.1引入的全新Type-C接口。与苹果的Lightning接口相似,Type-C接口取消了曾经的防呆保护设计,因此不分正反均可正常插入使用,免去了辨识插入方向的麻烦。而在尺寸上,8.3mm*2.5mm比标准的Type-A也小了很多,仅比目前常用的USB 2.0 Micro B稍大,因此也特别适合用在各种轻薄设备上面。但是如上图所示,USB 3.1的速度竟然也分了Gen1(5Gb/s)和Gen2(10Gb/s)两个版本,所以并非所有Type-C接口就一定是最大10Gb/s的版本,也可能只有5Gb/s的理论带宽,苹果的New MacBook就是一个很好的例子。

Type-C接口的最大供电为12V/3A

而USB 3.1 Type-C的另一个大卖点就是对移动设备充电能力的的增强。USB 3.1接口下的供电最高允许标准大幅提高到了20V/5A(仅限于Type-A/B),能够提供达100W的供电输出能力。而Type-C的最高标准为12V/3A,36W的充电能力已经足够一些轻薄型笔记本的使用,这也是New MacBook敢于放弃MagSafe而采用Type-C作为充电接口的重要原因。

Type-C Alt Mode已获得DisplayPort和MHL支持

从功能上看,USB 3.1 Type-C还引入了全新的Alternate Mode(交替模式),这意味着Type-C接口和数据线能传送非USB数据信号。目前Alt Mode已经能够支持DisplayPort 1.3和MHL 3.2规范,而USB-IF同时也在寻求对其他的功能标准的支持,除了视频接口,像以太网等其他接口同样也可以被Type-C支持。

ThunderBolt是很强大,但USB更加亲民

结合以上几点来看,除了带来更多的便利之外,Type-C接口似乎还有很大的野心——凭借这一种新的接口形式实现各种接口功能的大一统。它小巧易用,具备强大的供电能力,还具备扩展更多其他功能的潜力,这些都不得不令人联想到,未来的各种电子设备,只需要配备同样一种接口,即可实现各种各样的功能。而Intel的Thunderbolt接口虽然曾经也有过这样的愿景,功能和性能上也都要比USB 3.1更强,但无奈定位太高,普及程度远不及USB,因此在这方面显然后来居上的USB 3.1要更受业界欢迎。

结语:就像之前说到,USB诞生的初衷是为了简化计算机和外部设备的连接,但至此USB的应用早已不仅仅限于电脑,各种各样的电子设备也早已离不开这种看起来并不复杂的接口。正如其“通用串行总线”之名,USB正在“通用”的道路上越走越远。至于以后USB还会继续衍生出怎样的应用,是否能够一统接口界的江湖,还是让我们拭目而待吧。


原文来自:http://mb.zol.com.cn/514/5145370_all.html#p5147157

这个内核代码实现了哪些功能: // SPDX-License-Identifier: GPL-2.0-or-later /* * Host Side support for RNDIS Networking Links * Copyright (C) 2005 by David Brownell */ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/mii.h> #include <linux/usb.h> #include <linux/usb/cdc.h> #include <linux/usb/usbnet.h> #include <linux/usb/rndis_host.h> /* * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of * course ACM was intended for modems, not Ethernet links! USB's standard * for Ethernet links is "CDC Ethernet", which is significantly simpler. * * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues * include: * - Power management in particular relies on information that's scattered * through other documentation, and which is incomplete or incorrect even * there. * - There are various undocumented protocol requirements, such as the * need to send unused garbage in control-OUT messages. * - In some cases, MS-Windows will emit undocumented requests; this * matters more to peripheral implementations than host ones. * * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". * * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and * currently rare) "Ethernet Emulation Model" (EEM). */ /* * RNDIS notifications from device: command completion; "reverse" * keepalives; etc */ void rndis_status(struct usbnet *dev, struct urb *urb) { netdev_dbg(dev->net, "rndis status urb, len %d stat %d\n", urb->actual_length, urb->status); // FIXME for keepalives, respond immediately (asynchronously) // if not an RNDIS status, do like cdc_status(dev,urb) does } EXPORT_SYMBOL_GPL(rndis_status); /* * RNDIS indicate messages. */ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, int buflen) { struct cdc_state *info = (void *)&dev->data; struct device *udev = &info->control->dev; if (dev->driver_info->indication) { dev->driver_info->indication(dev, msg, buflen); } else { u32 status = le32_to_cpu(msg->status); switch (status) { case RNDIS_STATUS_MEDIA_CONNECT: dev_info(udev, "rndis media connect\n"); break; case RNDIS_STATUS_MEDIA_DISCONNECT: dev_info(udev, "rndis media disconnect\n"); break; default: dev_info(udev, "rndis indication: 0x%08x\n", status); } } } /* * RPC done RNDIS-style. Caller guarantees: * - message is properly byteswapped * - there's no other request pending * - buf can hold up to 1KB response (required by RNDIS spec) * On return, the first few entries are already byteswapped. * * Call context is likely probe(), before interface name is known, * which is why we won't try to use it in the diagnostics. */ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; struct usb_cdc_notification notification; int master_ifnum; int retval; int partial; unsigned count; u32 xid = 0, msg_len, request_id, msg_type, rsp, status; /* REVISIT when this gets called from contexts other than probe() or * disconnect(): either serialize, or dispatch responses on xid */ msg_type = le32_to_cpu(buf->msg_type); /* Issue the request; xid is unique, don't bother byteswapping it */ if (likely(msg_type != RNDIS_MSG_HALT && msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; if (!xid) xid = dev->xid++; buf->request_id = (__force __le32) xid; } master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, master_ifnum, buf, le32_to_cpu(buf->msg_len), RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0 || xid == 0)) return retval; /* Some devices don't respond on the control channel until * polled on the status channel, so do that first. */ if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) { retval = usb_interrupt_msg( dev->udev, usb_rcvintpipe(dev->udev, dev->status->desc.bEndpointAddress), &notification, sizeof(notification), &partial, RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0)) return retval; } /* Poll the control channel; the request probably completed immediately */ rsp = le32_to_cpu(buf->msg_type) | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), USB_CDC_GET_ENCAPSULATED_RESPONSE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, master_ifnum, buf, buflen, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { msg_type = le32_to_cpu(buf->msg_type); msg_len = le32_to_cpu(buf->msg_len); status = le32_to_cpu(buf->status); request_id = (__force u32) buf->request_id; if (likely(msg_type == rsp)) { if (likely(request_id == xid)) { if (unlikely(rsp == RNDIS_MSG_RESET_C)) return 0; if (likely(RNDIS_STATUS_SUCCESS == status)) return 0; dev_dbg(&info->control->dev, "rndis reply status %08x\n", status); return -EL3RST; } dev_dbg(&info->control->dev, "rndis reply id %d expected %d\n", request_id, xid); /* then likely retry */ } else switch (msg_type) { case RNDIS_MSG_INDICATE: /* fault/event */ rndis_msg_indicate(dev, (void *)buf, buflen); break; case RNDIS_MSG_KEEPALIVE: { /* ping */ struct rndis_keepalive_c *msg = (void *)buf; msg->msg_type = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); msg->msg_len = cpu_to_le32(sizeof *msg); msg->status = cpu_to_le32(RNDIS_STATUS_SUCCESS); retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, master_ifnum, msg, sizeof *msg, RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0)) dev_dbg(&info->control->dev, "rndis keepalive err %d\n", retval); } break; default: dev_dbg(&info->control->dev, "unexpected rndis msg %08x len %d\n", le32_to_cpu(buf->msg_type), msg_len); } } else { /* device probably issued a protocol stall; ignore */ dev_dbg(&info->control->dev, "rndis response error, code %d\n", retval); } msleep(40); } dev_dbg(&info->control->dev, "rndis response timeout\n"); return -ETIMEDOUT; } EXPORT_SYMBOL_GPL(rndis_command); /* * rndis_query: * * Performs a query for @oid along with 0 or more bytes of payload as * specified by @in_len. If @reply_len is not set to -1 then the reply * length is checked against this value, resulting in an error if it * doesn't match. * * NOTE: Adding a payload exactly or greater than the size of the expected * response payload is an evident requirement MSFT added for ActiveSync. * * The only exception is for OIDs that return a variably sized response, * in which case no payload should be added. This undocumented (and * nonsensical!) issue was found by sniffing protocol requests from the * ActiveSync 4.1 Windows driver. */ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, void *buf, u32 oid, u32 in_len, void **reply, int *reply_len) { int retval; union { void *buf; struct rndis_msg_hdr *header; struct rndis_query *get; struct rndis_query_c *get_c; } u; u32 off, len; u.buf = buf; memset(u.get, 0, sizeof *u.get + in_len); u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); u.get->oid = cpu_to_le32(oid); u.get->len = cpu_to_le32(in_len); u.get->offset = cpu_to_le32(20); retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", oid, retval); return retval; } off = le32_to_cpu(u.get_c->offset); len = le32_to_cpu(u.get_c->len); if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) goto response_error; if (*reply_len != -1 && len != *reply_len) goto response_error; *reply = (unsigned char *) &u.get_c->request_id + off; *reply_len = len; return retval; response_error: dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) " "invalid response - off %d len %d\n", oid, off, len); return -EDOM; } /* same as usbnet_netdev_ops but MTU change not allowed */ static const struct net_device_ops rndis_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_get_stats64 = usbnet_get_stats64, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; int generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) { int retval; struct net_device *net = dev->net; struct cdc_state *info = (void *) &dev->data; union { void *buf; struct rndis_msg_hdr *header; struct rndis_init *init; struct rndis_init_c *init_c; struct rndis_query *get; struct rndis_query_c *get_c; struct rndis_set *set; struct rndis_set_c *set_c; struct rndis_halt *halt; } u; u32 tmp; __le32 phym_unspec, *phym; int reply_len; unsigned char *bp; /* we can't rely on i/o from stack working, or stack allocation */ u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (!u.buf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) goto fail; u.init->msg_type = cpu_to_le32(RNDIS_MSG_INIT); u.init->msg_len = cpu_to_le32(sizeof *u.init); u.init->major_version = cpu_to_le32(1); u.init->minor_version = cpu_to_le32(0); /* max transfer (in spec) is 0x4000 at full speed, but for * TX we'll stick to one Ethernet packet plus RNDIS framing. * For RX we handle drivers that zero-pad to end-of-packet. * Don't let userspace change these settings. * * NOTE: there still seems to be wierdness here, as if we need * to do some more things to make sure WinCE targets accept this. * They default to jumbograms of 8KB or 16KB, which is absurd * for such low data rates and which is also more than Linux * can usually expect to allocate for SKB data... */ net->hard_header_len += sizeof (struct rndis_data_hdr); dev->hard_mtu = net->mtu + net->hard_header_len; dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); if (dev->maxpacket == 0) { netif_dbg(dev, probe, dev->net, "dev->maxpacket can't be 0\n"); retval = -EINVAL; goto fail_and_release; } dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); dev->rx_urb_size &= ~(dev->maxpacket - 1); u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); net->netdev_ops = &rndis_netdev_ops; retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); goto fail_and_release; } tmp = le32_to_cpu(u.init_c->max_transfer_size); if (tmp < dev->hard_mtu) { if (tmp <= net->hard_header_len) { dev_err(&intf->dev, "dev can't take %u byte packets (max %u)\n", dev->hard_mtu, tmp); retval = -EINVAL; goto halt_fail_and_release; } dev_warn(&intf->dev, "dev can't take %u byte packets (max %u), " "adjusting MTU to %u\n", dev->hard_mtu, tmp, tmp - net->hard_header_len); dev->hard_mtu = tmp; net->mtu = dev->hard_mtu - net->hard_header_len; } /* REVISIT: peripheral "alignment" request is ignored ... */ dev_dbg(&intf->dev, "hard mtu %u (%u from dev), rx buflen %zu, align %d\n", dev->hard_mtu, tmp, dev->rx_urb_size, 1 << le32_to_cpu(u.init_c->packet_alignment)); /* module has some device initialization code needs to be done right * after RNDIS_INIT */ if (dev->driver_info->early_init && dev->driver_info->early_init(dev) != 0) goto halt_fail_and_release; /* Check physical medium */ phym = NULL; reply_len = sizeof *phym; retval = rndis_query(dev, intf, u.buf, RNDIS_OID_GEN_PHYSICAL_MEDIUM, reply_len, (void **)&phym, &reply_len); if (retval != 0 || !phym) { /* OID is optional so don't fail here. */ phym_unspec = cpu_to_le32(RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED); phym = &phym_unspec; } if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && le32_to_cpup(phym) != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires wireless physical medium, but device is not\n"); retval = -ENODEV; goto halt_fail_and_release; } if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && le32_to_cpup(phym) == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires non-wireless physical medium, but device is wireless.\n"); retval = -ENODEV; goto halt_fail_and_release; } /* Get designated host ethernet address */ reply_len = ETH_ALEN; retval = rndis_query(dev, intf, u.buf, RNDIS_OID_802_3_PERMANENT_ADDRESS, 48, (void **) &bp, &reply_len); if (unlikely(retval< 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); goto halt_fail_and_release; } if (bp[0] & 0x02) eth_hw_addr_random(net); else ether_addr_copy(net->dev_addr, bp); /* set a nonzero filter to enable data transfers */ memset(u.set, 0, sizeof *u.set); u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); u.set->msg_len = cpu_to_le32(4 + sizeof *u.set); u.set->oid = cpu_to_le32(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); u.set->len = cpu_to_le32(4); u.set->offset = cpu_to_le32((sizeof *u.set) - 8); *(__le32 *)(u.buf + sizeof *u.set) = cpu_to_le32(RNDIS_DEFAULT_FILTER); retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); goto halt_fail_and_release; } retval = 0; kfree(u.buf); return retval; halt_fail_and_release: memset(u.halt, 0, sizeof *u.halt); u.halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); u.halt->msg_len = cpu_to_le32(sizeof *u.halt); (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); fail_and_release: usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver_of(intf), info->data); info->data = NULL; fail: kfree(u.buf); return retval; } EXPORT_SYMBOL_GPL(generic_rndis_bind); static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) { return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS); } void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) { struct rndis_halt *halt; /* try to clear any rndis state/activity (no i/o from stack!) */ halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (halt) { halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); halt->msg_len = cpu_to_le32(sizeof *halt); (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); kfree(halt); } usbnet_cdc_unbind(dev, intf); } EXPORT_SYMBOL_GPL(rndis_unbind); /* * DATA -- host must not write zlps */ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { /* This check is no longer done by usbnet */ if (skb->len < dev->net->hard_header_len) return 0; /* peripheral may have batched packets to us... */ while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; struct sk_buff *skb2; u32 msg_type, msg_len, data_offset, data_len; msg_type = le32_to_cpu(hdr->msg_type); msg_len = le32_to_cpu(hdr->msg_len); data_offset = le32_to_cpu(hdr->data_offset); data_len = le32_to_cpu(hdr->data_len); /* don't choke if we see oob, per-packet data, etc */ if (unlikely(msg_type != RNDIS_MSG_PACKET || skb->len < msg_len || (data_offset + data_len + 8) > msg_len)) { dev->net->stats.rx_frame_errors++; netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n", le32_to_cpu(hdr->msg_type), msg_len, data_offset, data_len, skb->len); return 0; } skb_pull(skb, 8 + data_offset); /* at most one packet left? */ if (likely((data_len - skb->len) <= sizeof *hdr)) { skb_trim(skb, data_len); break; } /* try to return all the packets in the batch */ skb2 = skb_clone(skb, GFP_ATOMIC); if (unlikely(!skb2)) break; skb_pull(skb, msg_len - sizeof *hdr); skb_trim(skb2, data_len); usbnet_skb_return(dev, skb2); } /* caller will usbnet_skb_return the remaining packet */ return 1; } EXPORT_SYMBOL_GPL(rndis_rx_fixup); struct sk_buff * rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { struct rndis_data_hdr *hdr; struct sk_buff *skb2; unsigned len = skb->len; if (likely(!skb_cloned(skb))) { int room = skb_headroom(skb); /* enough head room as-is? */ if (unlikely((sizeof *hdr) <= room)) goto fill; /* enough room, but needs to be readjusted? */ room += skb_tailroom(skb); if (likely((sizeof *hdr) <= room)) { skb->data = memmove(skb->head + sizeof *hdr, skb->data, len); skb_set_tail_pointer(skb, len); goto fill; } } /* create a new skb, with the correct size (and tailpad) */ skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); dev_kfree_skb_any(skb); if (unlikely(!skb2)) return skb2; skb = skb2; /* fill out the RNDIS header. we won't bother trying to batch * packets; Linux minimizes wasted bandwidth through tx queues. */ fill: hdr = __skb_push(skb, sizeof *hdr); memset(hdr, 0, sizeof *hdr); hdr->msg_type = cpu_to_le32(RNDIS_MSG_PACKET); hdr->msg_len = cpu_to_le32(skb->len); hdr->data_offset = cpu_to_le32(sizeof(*hdr) - 8); hdr->data_len = cpu_to_le32(len); /* FIXME make the last packet always be short ... */ return skb; } EXPORT_SYMBOL_GPL(rndis_tx_fixup); static const struct driver_info rndis_info = { .description = "RNDIS device", .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, .bind = rndis_bind, .unbind = rndis_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, }; static const struct driver_info rndis_poll_status_info = { .description = "RNDIS device (poll status before control)", .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, .data = RNDIS_DRIVER_DATA_POLL_STATUS, .bind = rndis_bind, .unbind = rndis_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, }; /*-------------------------------------------------------------------------*/ static const struct usb_device_id products [] = { { /* 2Wire HomePortal 1000SW */ USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042, USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_poll_status_info, }, { /* Hytera Communications DMR radios' "Radio to PC Network" */ USB_VENDOR_AND_INTERFACE_INFO(0x238b, USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long)&rndis_info, }, { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), .driver_info = (unsigned long) &rndis_poll_status_info, }, { /* RNDIS for tethering */ USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), .driver_info = (unsigned long) &rndis_info, }, { /* Novatel Verizon USB730L */ USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1), .driver_info = (unsigned long) &rndis_info, }, { }, // END }; MODULE_DEVICE_TABLE(usb, products); static struct usb_driver rndis_driver = { .name = "rndis_host", .id_table = products, .probe = usbnet_probe, .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, .disable_hub_initiated_lpm = 1, }; module_usb_driver(rndis_driver); MODULE_AUTHOR("David Brownell"); MODULE_DESCRIPTION("USB Host side RNDIS driver"); MODULE_LICENSE("GPL");
最新发布
09-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值