这是使用的是RP4412 开发板进行调的USB,以下是整理的一些相关的内容,希望可以给大家带来一些作用。 一、USB概述 当 USB设备接上或从USB设备移开的时候,主机启动一个被称作总线标识(bus enumera tion)的进程,来标识并管理设备状态的改变,当USB设备接上一个加电端口时,系统当采取以下操作: USB设备所连的集线器通过其通向主机的状态改变通道向主机汇报本USB设备已连接上。此时,USB设备处于加电状态,它所连接的端口是无效的。 主机通过询问集线器决定此次状态改变的确切含义。 主机一旦得知新设备已连上以后,它至少等待100ms以使得插入操作的完成以及设备 电源稳定工作。然后主机发出端口使能及复位命令给那个端口。 集线器将发向端口的复位信号持续10ms。当复位信号撤消后,端口已经有效了。这时USB设备处于缺省状态,并且可从VBUS汲取小于100mA的电能,所有设备寄存器及状态已经被复位,设备可对缺省地址产生响应。 主机给设备分配一个唯一的地址,设备转向编址状态。(Addressstate)。 在USB设备接受设备地址之前,它的缺省控制通道(Default Control Pipe)在缺省地址处自然是可寻址的,主机通过读取设备描述表,判决设备缺省通道的实际净数据负载。 主机从设备读取配置信息要从配置0读到配置n-1,其中n为配置个数,此操作须花费几个毫秒。 基于从设备取来的配置信息及设备如何被使用的信息,主机给设备一个配置值,此刻,设备就处于配置状态(Configured state)并此配置有关的所有端节点,都按照配置各就各位,USB设备现在可以从 VBUS得到描述中所要求的电量了。从设备的角度来讲,它已经准备就绪了。 当USB设备被取走时,集线器同样会通知主机,断开一个设备连接会使得设备所连接的端口无效,一收到断开通知后,主机就会更新拓扑信息。 从上述USB上电的整个过程中,我们可以看到,为了实现USB设备能正确被主机识别,首先需要解决描述符的问题,只要描述符能够被主机正确识别,USB系统基本能够工作了,剩下的就是把用户协议添加到USB系统中。 描述符问题(descriptor),描述符包括report描述符、HID描述符、设备(device)描述符、配置(configuration)描述符、接口(interface)描述符、端点(endpoint)描述符;其中report描述符是不定长的,设备不同会不同,而其他描述符一般都有固定的格式。主要实现这些描述符的格式定义以及相应的数据初始化。 主机与设备间的通讯协议问题,使上位机(电脑)能够正确识别设备,并能实现正常的数据交换。主要包括USB设备能够正确回复上位机的查询(USB实现相应的中断处理,实现对上位机的数据的接收与解析以及正确回复等)。 用户协议问题,实现用户方的协议与USB搭配使用,并得到正确及时的数据响应 二、USB描述: 描述符多种多样,下表给出了各个描述符类型的对应编码: 描述符种类 值 Device descriptor 1 Configuration descriptor 2 String descriptor 3 Interface descriptor 4 Endpoint descriptor 5 实际在给描述符表赋值时,对应的描述符类型按照上表进行 1、设备描述: struct u***_device_descriptor { __u8 bLength; -------------------------------u***设备描述的长度(0x12) __u8 bDescriptorType;----------------------------设备描述类型一般都是0x1 __le16bcdUSB; __u8 bDeviceClass; __u8 bDeviceSubClass; __u8 bDeviceProtocol; __u8 bMaxPacketSize0; __le16idVendor; ------------------------------------ U*** 设备版本ID __le16idProduct;-------------------------------------U*** 设备产品ID __le16bcdDevice; __u8 iManufacturer; __u8 iProduct; __u8 iSerialNumber; __u8 bNumConfigurations; -----------------------配置信息的个数 } __attribute__ ((packed)); 2、配置描述: struct u***_config_descriptor { __u8 bLength;------------------------------配置描述长度 __u8 bDescriptorType; ------------------配置描述类型(0x02) __le16wTotalLength; -----------配置描述总长度(包括接口描述+端口描述) __u8 bNumInterfaces;------------------接口个数 __u8 bConfigurationValue; __u8 iConfiguration; __u8 bmAttributes; __u8 bMaxPower; } __attribute__ ((packed)); 3、接口描述: struct u***_interface_descriptor { __u8 bLength;-------------------------------接口长度 __u8 bDescriptorType;---------------------接口类型为0x04 __u8 bInterfaceNumber;--------------------替换接口数 __u8 bAlternateSetting; __u8 bNumEndpoints;-----------------------端口个数 __u8 bInterfaceClass; __u8 bInterfaceSubClass; __u8 bInterfaceProtocol; __u8 iInterface; } __attribute__ ((packed)); 4、端口描述: struct u***_endpoint_descriptor { __u8 bLength;--------------------------------端口长度 __u8 bDescriptorType;----------------------端口类型0x05 __u8 bEndpointAddress;--------------------端口号,最高位为1 IN ,0 OUT __u8 bmAttributes;---------------定义端口为INT,ISO,BULK,CONTROL __le16wMaxPacketSize;-----------端口支持的传输的数据大小 __u8 bInterval; __u8 bRefresh; __u8 bSynchAddress; } __attribute__ ((packed)); 5、字符描述: struct u***_string_descriptor { __u8 bLength;---------------------------------长度 __u8 bDescriptorType;----------------------类型定义为0x03 __le16wData[1]; ---------------------这个一般都是地址来读数据 } __attribute__ ((packed)); 不管什么USB设备,都有这些配置信息,这些配置信息给出,就知道该u***设备支持什么样的数据传输类型及传输数据大小。 USB HID配置的描述和u*** 设备有点出别,如果大家感兴趣的用户可以去多了解这方面的资料,网上都有这方面的资料描述。 三、USB状态 USB设备有若干可能的状态, 其中一些对于USB与主机(host)来说是外置的,而另外一些对 USB 设备来说是内置的。对于外置设备状态有以下几种:Attached(连接状态)、Powered(上电状态)、Default(缺省状态)、Address(地址状态)、Configured(配置状态)、Suspended(挂起状态)。 连接状态:USB 设备可被连接到 USB 接口上或从接口断开; 上电状态:USB 设备的电源可来自外部电源,也可从 USB 接口的集线器而来。电源来自外部电源的 USB 设备被称作自给电源式的(self-powered)。尽管自给电源式的USB 设备可能在连接上 USB 接口以前可能已经带电,但它们直到连线上 USB 接口后才能被看作是加电状态(Powered state)。而这时候 VBUS 已经对设备产生作用了。 缺省状态:设备加电以后,在它从总线接收到复位信号之前不会对总线传输发生响应。在接收到复位信号之后,设备才在缺省地址处变得可寻址。 地址状态:所有的 USB 设备在加电复位以后都使用缺省地址。每一设备在连接或复位后由主机分配一个唯一的地址。 配置状态:在USB设备正常工作以前,设备必须被正确配置。从设备的角度来看,配置包括一个将非零值写入设备配置寄存器的操作。配置一个设备或改变一个可变的设备设置会使得与这个相关接口的终端结点的所有的状态与配置值被设成缺省值。 挂起状态:为节省电源,USB 设备在探测不到总线传输时自动进入挂起状态。当中止时,USB设备保持本身的内部状态,包括它的地址及配置 四、USB标准请求 所有的 USB 设备在设备的缺省控制通道(Default Control Pipe)处对主机的请求发出响应。这些请求是通过使用控制传输来达到的,请求及请求的参数通过Setup包发向设备,由主机负责设置Setup包内的每个域的值。每个Setup包有8个字节。 Setup包由5个域所组成,包括请求类型(bmRequestType)、请求名称(bRequest)、wValue、wIndex、wLength。 bmRequestType的格式为D7D6D5D4D3D2D1D0B,D7表示传输方向(0表示主机到设备,1表示设备到主机),D6D5表示种类(0表示标准,1表示类,2表示厂商,3为保留),D4D3D2D1D0为接受者(0表示设备,1表示接口,2表示端点,3表示其他,4以后为保留)。 下表是标准请求表: bmRequestType bRequest wValue Windex wLength Data 00000000B CLEAR_FEATURE 1 特性选择符 零 零 无 00000001B 接口号 00000010B 端点号 10000000B GET_CONFIGURATION 8 零零一配置值 10000000B GET_DESCRIPTOR6 描述表种类索引 零或语言标志 描述表长 描述表 10000001B GET_INTERFACE 10 零接口号一可选设置 10000000B GET_STATUS 0 零 零二设备,接口或端点标志 10000001B 接口号 10000010B 端点号 00000000B SET_ADDRESS 5 设备地址 零零无 00000000B SET_CONFIGURATION 9 配置值零零无 00000000B SET_DESCRIPTOR7 描述表种类索引 零或语言标志 描述表长 描述表 00000000B SET_FEATURE 3 特性选择符 零零无 00000001B 接口号 00000010B 端点号 00000001B SET_INTERFACE 11 可选设置 接口号 零 无 10000010B SYNCH_FRAME 12 零 端点号二帧号 在USB完成配置之后,USB设备就处于就绪状态,这是USB标准请求表,一定要弄明白,在做u*** 设备的固件程序和USB驱动必须要用到的! 五、介绍三星RP4412开发板 USB方面的驱动功能: 1、 在RP4412开发板 kernel下的arch/arm/mach-exynos/mach-smdk4x12.c,在这个文件里面有USB的EHCI,OCHI,GADGET,OTG设备加载及介绍 OHCI主要为非PC系统上以及带有SiS和 ALi芯片组的PC主板上的USB芯片
UHCI大多为Intel和Via主板上的USB控制器芯片。UHCI的硬件 电路比OHCI简单,成本低,但驱动复杂,但他们都是由USB1.1规格的。
EHCI是有Intel等几个厂商研发,兼容OHCI UHCI 遵循USB2.0规范。
USB规范都是从寄存器级别规定好的,不过各个厂商可能有自己的几个专用的寄存器。 三星为了实现ECHI,OCHI,OTG,gadget三星提供了相关的驱动程序, #ifdef CONFIG_USB_EHCI_S5P smdk4x12_ehci_init(); #endif #ifdef CONFIG_USB_OHCI_S5P smdk4x12_ohci_init(); #endif #ifdef CONFIG_USB_GADGET smdk4x12_u***gadget_init(); #endif #ifdef CONFIG_USB_EXYNOS_SWITCH smdk4x12_u***switch_init(); #endif archarmplat-s5p dev-ehci.c 此文件实现了ECHI,OCHI, OTG中断及IO内存声明 archarmplat-s5pdev-u***gadget.c 此文件定义了USB类型u***_mass_storage,adb,mtp,rndis等,里面同时也定义相关的类型的USB产品ID及adb序列号。 archarmmach-exynossetup-u***-phy.c 此文件实现USB OTG,ECHI,OCHI等寄存器配置功能 archarmmach-exynos setup-sdhci-gpio.c此文件是配置4412 GPIO为USB 功能 smdk4x12_u***switch_init();此函数定义了三星的OTG功能,OTG实现的原理就是利用, OTG驱动关联在driversu***misc exynos-u***-switch.c
USB_OTG实现,三星4412利用两个GPIO定义,一个GPIO为实现HOST中断,当插入设备是U 盘及键盘、鼠标,而GPIO(HOST_PW_EN)脚拉低,同时给VBUS线设置电源,给插入到u*** host的设备供电 同理,另外一个GPIO定义是实现USB 线连接PC电脑设备等,这时MID是作为设备使用的功能,而这个USB_DET的IO脚拉高。 exynos-u***-switch.c文件主要实现上面两个功能的需求,根据其中的ID变化能识别插入到OTG设备是什么设备,自动加载相应的设备驱动模块,这个文件关键的函数是exynos_change_u***_mode(),此函数就实现了HOST,设备之间的切换。 不过三星实现的USB OTG功能还是比较复杂,三星OTG利用两个中断来实现host,设备切换,如果不修改此文件,三星exynos-u***-switch.c文件在待机有问题。 2、由于u*** 实现的驱动比较庞大,主要u*** 类设备太多,现在大都设备都可以利用u***接口来实现功能. EHCI驱动driversu***hostehci-hcd.c,此文件ehci_hcd_init()函数加载driversu***hostehci-s5p.c,ehci-s5p.c函数实现ECHI功能,初始配置三星USB寄存器功能配置及USB总线和USB root HUB,在USB_HCD中有一个重要的结构: static const struct hc_driver s5p_ehci_hc_driver ,这个结构实现了USB 总线和跟u*** hub的功能,下面有几个重要的函数介绍:
3、USB驱动中OCHI介绍,驱动路径, driversu***host ohci-hcd.c, driversu***host ohci-s5p.c关键是OCHI-s5p.c文件,此文件实现OCHI功能配置,其中下面几个重要的函数:
U***_hcd在OCHI也有一个重要的结构static const struct hc_driverohci_s5p_hc_driver ,结构也实现了上面函数定义,也定义了USB hub及USB总线的实现。 4、gadget功能实现, 实现了 USB 协议定义的设备端的 软件功能driversu*** gadget s3c_udc_otg.c,此文件时三星实现功能,如果要了解gadget功能,请网上多搜索有关的GadGet文档了解,如果产品只有一个OTG接口,那么于OTG通讯都在在这个文件里面实现数据传输gadget功能驱动层是USB Gadget软件结构的最上层。主要是实现USB设备的功能,这一层通常与linux内核的其他层有密切的联系。模拟U盘的gadget就与文件系统层与块IO层有着联系。 5、u*** hub介绍: 一个USB设备插上linux系统的PC后是如何一步一步调到我们的u***设备驱动的probe 函数的, 我们知道我们的USB驱动的probe函数中的一个参数是interface结构, 因此一般来说, 一个USB设备中的任何一个接口都应该有对应的一个驱动程序/*driver/u***/core/hub.c*/:u***_hub_init()-->hub_thread()-->hub_events()-->hub_port_connect_change()我们知道USB设备都是通过插入上层HUB的一个Port来连入系统并进而被系统发现的,当USB设备插入一个HUB时,该HUB的那个port的状态就会改变, 从而系统就会知道这个改变, 此时会调用hub_port_connect_change()/*driver/u***/core/hub.c*/函数创建一个u***_device的对象udev, 并初始化它,接着调用u***_new_device()来获取这个u***设备的各种描述符并为每个interface找到对用的driver.intu***_new_device(struct u***_device *udev){…. u***_enumerate_device()-àu***_get_configuration(udev);….device_add(&udev->dev);}该函数首先调用u***_get_configuration()来获取设备的各种描述符(设备描述符,配置描述符等),接着调用device_add()来把这个USB设备添加到USB系统中去, 也就是在这个过程中系统回去为这个设备找到相应的驱动.USB 功能驱动,一般都是用户自己编写代码,编写USB功能驱动一般利用u***_register()函数注册,卸载u***驱动利用u***_deregister()如果用户想自己编写u***驱动,可以参考driversu***u***-skeleton.c
|