首页 Linux内核USB驱动架构:USB设备驱动架构

Linux内核USB驱动架构:USB设备驱动架构

举报
开通vip

Linux内核USB驱动架构:USB设备驱动架构1USB设备驱动架构LK版本:2.6.35.32013年1月14日任务目标:分析整理插入一个USB设备的处理过程。USB设备、配置、接口、设置以及端点的五者关系图:一个USB设备对应有一个或多个配置;一个配置对应一个或多个的USB接口;一个USB接口又具有一个或多个的设置;一个设置又会拥有一个或多个的USB端点。2五者关系图如下:usb_device{}设备.descriptor*config......usb_host_config{}[]......usb_host_config{}.desc......*...

Linux内核USB驱动架构:USB设备驱动架构
1USB设备驱动架构LK版本:2.6.35.32013年1月14日任务目标:分析整理插入一个USB设备的处理过程。USB设备、配置、接口、设置以及端点的五者关系图:一个USB设备对应有一个或多个配置;一个配置对应一个或多个的USB接口;一个USB接口又具有一个或多个的设置;一个设置又会拥有一个或多个的USB端点。2五者关系图如下:usb_device{}设备.descriptor*config......usb_host_config{}[]......usb_host_config{}.desc......*interface[]usb_interface{}[]......usb_interface{}*altsetting*cur_altsetting.num_altsetting......usb_host_interface{}[]......usb_host_interface{}*endpoint.desc......usb_host_endpoint{}[]......usb_host_endpoint{}.desc......一个配置一个接口一个设置一个端点.urb_listusb_device_descriptor{}配置描述符usb_config_descriptor{}usb_interface_descriptor{}接口描述符usb_endpoint_descriptor{}端点描述符1.定义这个端点的数据输入/输出方向由.bEndpointAddress的bit7决定,0为输出,1为输入。2.至于如何判断是中断、等时、控制或批量传输的类型:可根据.bmAttributes的bit1和bit0决定,00 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示控制传输,01表示等时传输,10表示批量传输,11表示中断传输*ep_in[]*ep_out[].bNumConfigurations设备描述符USB_MAXINTERFACES.bNumEndpoints.bEndpointAddress.bmAttributes1.每个端点拥有一个urb_list2.urb的数据从端点进行收发3.HCD每收到一个urb,就会将它添加到这个urb指定的urb队列中,例:list_add_tail(&urb->urb_list,&urb->ep->urb_list)usb_host_endpoint{}*[]......usb_host_endpoint*{}[]......多个配置多个接口多个设置多个端点指向3#defineUSB_DIR_OUT0#defineUSB_ENDPOINT_DIR_MASK0x80staticinlineintusb_endpoint_dir_out(conststructusb_endpoint_descriptor*epd){return((epd->bEndpointAddress&USB_ENDPOINT_DIR_MASK)==USB_DIR_OUT);}voidusb_enable_endpoint(structusb_device*dev,structusb_host_endpoint*ep,...){intis_out=usb_endpoint_dir_out(&ep->desc);......if(is_out||is_control)dev->ep_out[epnum]=ep;if(!is_out||is_control)dev->ep_in[epnum]=ep;}ep_in、ep_out的来源:4成员变量及意义解说:structusb_device_descriptor{__u8bLength;__u8bDescriptorType;__le16bcdUSB;__u8bDeviceClass;__u8bDeviceSubClass;__u8bDeviceProtocol;__u8bMaxPacketSize0;__le16idVendor;__le16idProduct;__u8bNumConfigurations;......}usb_device_descriptor{}.bLength.bDescriptorType.bDeviceClass.bDeviceSubClass.bDeviceProtocol.bMaxPacketSize0.idVendor.idProduct......设备描述符usb_config_descriptor{}配置描述符.bLength.bDescriptorType.bNumInterfaces.bConfigurationValue.iConfiguration.bmAttributes.bMaxPower接口描述符usb_interface_descriptor{}.bLength.bDescriptorType.bInterfaceNumber.bAlternateSetting.bNumEndpoints.bInterfaceClass.bInterfaceSubClass.bInterfaceProtocol.iInterface端点描述符usb_endpoint_descriptor{}.bLength.bDescriptorType.bEndpointAddress.bmAttributes.wMaxPacketSize.bInterval.bRefresh.bSynchAddress字符串描述符usb_string_descriptor{}.bLength.bDescriptorType.wData[1]5集线器类例子:bLength:描述符的长度#defineUSB_DT_DEVICE_SIZE18;bDescriptorType:值为USB_DT_DEVICE:0x01bcdUSB:USBspec的版本号,如果是2.0版本,值为0x0200,如是1.1版本,则值为0x0110。bDeviceClassbDeviceSubClassbDeviceProtocolidVendoridProductbMaxPacketSize0:端点0一次可以处理的最大字节数。Q:为什么要放在设备描述符里呢?A:由于它自己没有一个描述符,而每个设备又都有这么一个端点所以这个信息被保存在了设备描述符里,其中,这个值只能是8,16,32或64这四者之一,高速模式值只能为64,低速模式只能为8,对于中速,可以为8,16,32,64,单位字节。bNumConfigurations:设备当前速度模式下支持的配置数量分别指每个设备属于一个Class,然后Class下面又分了SubClass,SubClass下面又按各种设备遵循的不同的通信协议继续细分设备的厂商和ID号,在USB设备与驱动匹配时会用到此成员参数包括两份:一份来自USB接口驱动中的module.usbmap文件中,另一份在USB外设中由枚举时获取。设备类代码及例子请见下表6structusb_config_descriptor{__u8bLength;__u8bDescriptorType;__le16wTotalLength;__u8bNumInterfaces;__u8bConfigurationValue;__u8iConfiguration;__u8bmAttributes;__u8bMaxPower;}structusb_interface_descriptor{__u8bLength;__u8bDescriptorType;__u8bInterfaceNumber;__u8bAlternateSetting;__u8bNumEndpoints;__u8bInterfaceClass;__u8bInterfaceSubClass;__u8bInterfaceProtocol;__u8iInterface;}音频类例子如下:bLength:值为9,#defineUSB_DT_INTERFACE_SIZE9bDescriptorType:值为0x04#defineUSB_DT_INTERFACE0x04bInterfaceNumber:接口号,每个设备可以包含多个接口,这个值就是它们的索引值起始值从0开始。bAlternateSetting:接口使用的是哪个可选设置,协议规定:默认使用的设置总为0号设置bInterfaceClassbInterfaceSubClassbInterfaceProtocoliInterface:接口对应的字符串描述符的索引值bLength:值为9#defineUSB_DT_CONFIG_SIZE9bDescriptorType:值为0x02#defineUSB_DT_CONFIG0x02wTotalLength:使用GET_DESCRIPTOR请求从设备中获得配置描述符信息,返回的数据长度,也就是对包括配置描述符、接口描述符、端点描述符等进行统计bConfigurationValue:对于拥有多个配置的设备来说,假如想改变正在使用的配置,可以使用SET_CONFIGURATION请求,bConfigurationValue指明了将要激活哪个配置,注意:设备可以有多个配置,但同一时间只能有一个配置被激活。bmAttributes:表示配置的某些特点,bit7必须为1,bit6表示self-powered,最大供电500mAbit5表示支持远程唤醒,bit4表示batterypowered接口类代码及例子请见下表7structusb_endpoint_descriptor{__u8bLength;__u8bDescriptorType;__u8bEndpointAddress;__u8bmAttributes;__le16wMaxPacketSize;__u8bInterval;__u8bRefresh;__u8bSynchAddress;}bLength:#defineUSB_DT_ENDPOINT_SIZE7或#defineUSB_DT_ENDPOINT_AUDIO_SIZE9后面多了两个字节,那是针对音频设备扩展的。bDescriptorType:#defineUSB_DT_ENDPOINT0x05bEndpointAddress:bit0~bit3表示的就是端点号,使用0x0f和它相与就可以得到端点号,起始号为0,另外bit7表示方向,0为输出,1为输入,输入端点0~15,输出端点0~15。bmAttributes:bit0和bit1共同表示传输类型,00表示控制传输,01表示等时传输,10表示批量传输,11表示中断传输wMaxPacketSize:端点一次可以处理的最大字节数,0~10位表示数据包的长度,不同的传输类型,有不同的要求,详细请见下表Q:它与上面的wMaxPacketSize0有何区别?A:wMaxPacketSize0表示端点0一次可以处理的最大字节数,而wMaxPacketSize表示除0号端点一次可以处理的最大字节数。bInterval:USB是轮询式总线,这个值表示了主机轮询这个端点的时间间隔。控制传输:High-speed:64bytesFull-speed:8,16,32,64bytesLow-speed:8bytes中断传输:High-speed:0~1024bytesFull-speed:0~64bytesLow-speed:0~8bytes批量传输:High-speed:512bytesFull-speed:8,16,32,64bytes低速设备没有批量传输等时传输:High-speed:0~1024bytesFull-speed:0~1023bytes协议规范只列出高速和全速的最大字节数,未找到低速的详细请见下页分析8structusb_string_descriptor{__u8bLength;__u8bDescriptorType;__le16wData[1];/*UTF-16LEencoded*/}bInterval:它只对等时和中断传输有效,单位为ms。对于全速/高速的等时传输端点,它的值范围为1~16;对于全速/低速的中断传输端点,它的值范围为1~255;对于高速的中断传输端点,它的值范围为1~16;bLength:根据协议规范而知,它的值等于整个字符串描述符的成员字节数之和。bDescriptorType:#defineUSB_DT_STRING0x039Hub初始化数据结构关联图usb_driver数据结构图:usb_device{}.bus_mA.level*bus.descriptor......usb_bus{}.devnum_next......usb_hub{}*hdev*intfdev*descriptor.mA_per_port......usb_device_descriptor{}.bMaxPacketSize0......usb_device{}*children[]......usb_interface{}.dev......device{}......usb_host_interface{}*endpoint.......maxchildusb_hub_descriptor{}.bNbrPorts......usb_host_endpoint{}......*cur_altsetting.devnum.levelusb_driver{}*name()*probe()*ioctl()......*id_table.drvwrapusb_device_id{}.match_flags.idVendor.idProduct......usbdrv_wrap{}.driver.for_device......device_driver{}*name*bus*probe......bus_type{}.name.match.uevent.ops10各数据结构成员解说:structusb_device{intdevnum;structusb_bus*bus;structusb_device_descriptordescriptor;unsignedshortbus_mA;u8level;intmaxchild;structusb_device*children[USB_MAXCHILDREN];......};structusb_bus{intdevnum_next;......};devnum:USB设备在一条USB总线上的编号,当USB设备插到Hub上,Hub观察到这个变化,最终会调用choose_address()的函数,为设备选择一个地址。bus:指设备所在的那条总线,从硬件上来讲,一个主机控制器就会连出一条USB总线,从软件上来讲,不管你有多少个主机控制器,或者说有多少条总线,它们通通属于usb_bus_type这个类型,只是每一条总线对应一个structusb_bus结构体变量descriptor:设备描述符,其各成员变量解说在上文有提到。在此是为了获取bMaxPacketSize0的大小bus_mA:这个值是在主机控制器的驱动程序中设置的,通常来讲,计算机的USB端口最大可以提供500mA电流。level:表示USB设备树的级联关系,Root_Hub的level是0,其下面一层level1,再下面一层就是level2,依此类推。maxchild:表示Hub的端口数。children[]:Hub所连设备指针,理论上Hub一共可以接255个端口,不过实际上Hub最多也就是支持10个端口。staticvoidchoose_address(structusb_device*udev){intdevnum;structusb_bus*bus=udev->bus;......devnum=find_next_zero_bit(bus->devmap.devicemap,128,bus->devnum_next);if(devnum<128){set_bit(devnum,bus->devmap.devicemap);udev->devnum=devnum;}}devnum_next:该成员变量记录的就是structusb_devmapdevmap这张表里下一个为0的位,里面为1的都是已经被这条总线上的USB设备占据了。structusb_devmap{unsignedlongdevicemap[128/(8*sizeof(unsignedlong))];};unsignedlongdevicemap[128/(8*sizeof(unsignedlong))]等价于unsignedlongdevicemap[128/(8*4)],即unsignedlongdevicemap[4],而4bytes等于32bits,所以这个数组最终表示的就是128bits,即一条总线可以连接128个USB设备11structusb_interface{structusb_host_interface*cur_altsetting;structdevicedev;......}structusb_hub{structdevice*intfdev;structusb_device*hdev;structusb_hub_descriptor*descriptor;unsignedmA_per_port;......};cur_altsetting:表示设备当前正在使用的设置dev:linux设备模型中的device嵌套在这里的对象。它指向usb_hub{}的成员intfdev。intfdev:linux设备模型中的device嵌套在这里的对象hdev:指向structusb_device结构体,代表一个USB设备descriptor:获取该structusb_hub_descriptor描述符的成员量bNbrPorts,并赋值给structusb_device的maxchild,代表Hub的端口数mA_per_port:获取Hub端口的电流值,并给structusb_device的bus_mA12连接开机默认地址配置集线器重置或取消配置集线器配置挂起总线不活动总线激活重置挂起总线不活动总线激活地址分配挂起总线不活动总线激活设备配置挂起电源中断重置总线不活动总线激活USB设备检测状态图:13总体 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 思想:14插入一个USB设备的处理机理总体设计:插入设备1.hub层处理2.USB枚举3.加入驱动模型4.动态加载驱动5.调用USB前端驱动的probe()2.总体架构设计:1.中断定时查询:初始化hub中断定时查询插入设备拔出设备15中断定时查询:Hub层处理:1.1Hub检测设备Hub检测新设备Hub识别新设备插入USB新设备或开机前已插入此连接端口可能是在根Hub上,或是在下游的其他Hub上。Hub供电,设备处于开机状态。Hub在其两条信号线(D+与D-)上各有15k的衰减电阻器,中速的设备在D+上1.5K的上拉电阻器,低速的设备则是在D-线上有1.5K的上拉电阻器,高速的设备是以中速来连接的。电路原理图请见下页:监视每个端口的信号线(D+和D-)电压电平信号线电压上升,有设备接上,设备速度的确定见下页分析使用中断传输 报告 软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载 Hub上的事件get_port_status请求,获取更多信息1.Hub层处理3.解析各个部分:1.1Hub检测设备1.2Hub速度枚举1.3建立信号路径USB初始化a.&hub_driver注册b.匹配成功调用前端hub_probe()c.配置hub:hub_configure()d.填充中断urb,设置总线访问周期,回调函数等e.提交中断urb,主机定期查询hub状态16端口电路原理图:速度识别:USB中速/低速识别相当简单,就根据D+和D-两条信号线上的电压变化来判断,而高速设备的识别稍微有点复杂。高速设备初始是以一个中速设备的身份出现的,即和中速设备一样,D+线上有一个1.5k的上拉电阻。USB2.0的hub把它当作一个中速设备,之后,hub和设备通过一系列握手信号确认双方的身份。在这里对速度的检测是双向的,比如高速的hub需要检测所挂上来的设备是高速、中速还是低速,高速的设备需要检测所连上的hub是USB2.0的还是1.x的。高速设备连到USB2.0hub上的波形图如下:在重置期间,支持高速的设备会送出一个ChirpK状态,在hub端看到一个约800mV的电压(45欧姆*17.78mA),这就是ChirpK信号。ChirpK信号的持续时间是1ms~7ms。而高速的hub检测到ChirpK之后,开始回复一连串的KJKJKJ序列,而且每个K或J的持续时间在40us~60us之间,KJ序列停止后的100~500us内结束复位操作,并切换到高速模式。切换动作有:1.断开1.5k的上拉电阻。2.连接D+/D-上的高速终端电阻(high-speedtermination),实际上就是全速/低速差分驱动器。3.进入默认的高速状态。注意:执行1,2两步后,USB信号线上看到的现象就发生变化了:hub发送出来的ChirpKJ序列幅值降到了原先的一半,400mV。这是因为设备端挂载新的终端电阻后,配上原先hub端的终端电阻,并联后的阻抗是22.5欧姆。400mV就是由17.78mA*22.5Ohm得来。以后高速操作的信号幅值就是400mV而不像全速/低速那样的3V。Hub速度的枚举框图请见下页17USB枚举:1.2Hub速度枚举在Hub重置设备之前,Hub会检验两条信号线上的电压,判断哪一条线有较高的电压,来确定设备是中速还是低速,USB1.x允许Hub在重置后才检测设备的速度,而USB2.0则是需要在设备重置前知道其速度,如此才能在重置期间检查设备是否有高速的能力。Hub检测设备是否是中速还是低速Hub重置设备重置是发生在D+与D-都是在逻辑低位的时候,Hub将设备的USB数据放在重置状况下至少10ms。Hub只传送重置信号给新设备,其他总线上的Hub与设备都不会看到此重置信号。主机识别一个中速是否支持高速在重置期间,支持高速的设备会送出一个ChirpK状态,高速的Hub检测到该Chirp后,会反映一串的交替ChirpK与ChirpJ,当检测到KJKJKJ的样式后,则转到高速执行所有的通信。如果Hub没有对设备的ChirpK做出响应,设备知道它必须继续使用中速通信。1.3建立信号路径主机送出一个get_port_status请求,来证明设备已经离开重置状态。当Hub移除重置信号后,设备处在默认状态,设备的USB缓存器是在它们的重置状态,而设备已经准备好响应端点0的默认管道上的控制传输,使用默认地址00H与主机开始通信主机发送给Hub一个set_port_feature请求,重置连接端口检测两个特殊的信号状态:Chirpk与ChirpJ2.USB枚举2.1取设备描述符1.Host请求Hubreset设备2.USBspec未定义此重置动作2.3Set_Address为设备指定地址2.4了解设备能力通过这里,设备各个配置信息已经解析完毕,但光获得设备各个配置信息没用,要进入Configured状态,则是后面设备驱动的事情了,USB枚举成功后,调用device_add()将设备添加到总线链表上,并为之匹配合适的驱动。2.2Host请求Hubreset设备Chirpk与ChirpJ的补充:Chirpk与ChirpJ定义成DC差分电压,在ChirpJ状态中D+比较正位,在Chirpk状态中D-比较正位18将USB新设备加入设备模型:2.1取设备描述符2.3Set_Address为设备指定地址2.4了解设备能力3.加入设备模型通信地址:地址0,端点0。设备描述符的第8个字节,包含有端点0支持的最大信息包大小。发送set_address请求,指定设备一个唯一地址。在下一次检测设备时,设备地址可能不同此地址有效至设备移除,重置,或是系统关机时主机发送一个get_descriptor请求到新地址上,读取设备的描述符。接着,主机通过请求一个或多个指定在设备描述符内的配置描述符,开始只请求配置描述符的9个字节,获得总长度,继续再请求一次配置描述符。当获得总长度的数据后,解析配置,接口,端点等描述符了解设备的所有能力后,主机会寻找一个最适合的驱动程序来管理主机与设备的通信在从设备的描述符了解设备后,驱动程序会发送一个set_configuration请求以及配置号码,来请求一个设置配置,请求成功后,设备进入配置状态了解端点0的最大信息包大小3.2选择一个设置配置3.1加载设备驱动程序3.3进入配置状态19插入USB设备的总体程序流程框架图:usb_init()usb_register(&hub_driver)hub_port_connect_change()检测到端口有变化,即有设备插入或拔出usb_alloc_dev()choose_address()usb_new_device()hub_port_init()usb_enumerate_device()USB枚举device_add()usb_get_configuration()usb_get_descriptor()usb_parse_configuration()usb_parse_interface()usb_parse_endpoint()kthread_run(hub_thread,...)有事件触发,运行创建好的进程hub_events()hub_port_status()获取设备信息hub_configure()调用前端hub_probe()usb_fill_int_urb()填充中断urb,并设置轮询时间间隔和回调函数hub_irq()20一、Hub初始化:staticstructusb_driverhub_driver={.name="hub",.probe=hub_probe,.disconnect=hub_disconnect,.suspend=hub_suspend,.resume=hub_resume,.reset_resume=hub_reset_resume,.pre_reset=hub_pre_reset,.post_reset=hub_post_reset,.ioctl=hub_ioctl,.id_table=hub_id_table,};usb_init()kthread_run(hub_rhread,...)hub_events()hub_port_status()hub_port_connect_change()usb_alloc_dev()choose_address()usb_new_device()hub_port_init()hub_configure()调用前端hub_probe()usb_fill_int_urb()填充中断urb,并设置轮询时间间隔和回调函数hub_irq()usb_register(&hub_driver)21intusb_hub_init(void){......usb_register(&hub_driver);khubd_task=kthread_run(hub_thread,NULL,"khubd");......}staticinlineintusb_register(structusb_driver*driver){returnusb_register_driver(driver,...);//driver==>&hub_driver}intusb_register_driver(structusb_driver*new_driver,......)//new_driver==>&hub_driver{......new_driver->drvwrap.driver.name=(char*)new_driver->name;//”hub”new_driver->drvwrap.driver.bus=&usb_bus_type;new_driver->drvwrap.driver.probe=usb_probe_interface;new_driver->drvwrap.driver.remove=usb_unbind_interface;driver_register(&new_driver->drvwrap.driver);......}intdriver_register(structdevice_driver*drv){......bus_add_driver(drv);}intbus_add_driver(structdevice_driver*drv){......if(drv->bus->p->drivers_autoprobe)driver_attach(drv);......}intdriver_attach(structdevice_driver*drv){returnbus_for_each_dev(drv->bus,NULL,drv,__driver_attach);subsys_initcall(usb_hub_init)staticstructtask_struct*khubd_task;//调用sysfs_create_file()函数,创建new_id属性文件usb_create_newid_file(new_driver);//调用sysfs_create_file()函数,创建remove_id属性文件usb_create_removeid_file(new_driver);暂未研究structbus_typeusb_bus_type={.name="usb",.match=usb_device_match,.uevent=usb_uevent,.pm=&usb_bus_pm_ops,};该变量的初始化:在structbus_type_private{}中定义structbus_type_private{unsignedintdrivers_autoprobe:1......}22}staticint__driver_attach(structdevice*dev,void*data){structdevice_driver*drv=data;//data值就是bus_for_each_dev(...,...,drv,...)中drv这个参数......if(!dev->driver)//设备未初始化driver_probe_device(drv,dev);......}intdriver_probe_device(structdevice_driver*drv,structdevice*dev){......really_probe(dev,drv);......}staticintreally_probe(structdevice*dev,structdevice_driver*drv){......dev->driver=drv;//绑定了device{}与device_driver{},防止重复初始化drv->probe(dev);//usb_register_driver():usb_probe_interface()......}staticintusb_probe_interface(structdevice*dev){structusb_driver*driver=to_usb_driver(dev->driver);structusb_interface*intf=to_usb_interface(dev);conststructusb_device_id*id;......id=usb_match_id(intf,driver->id_table);if(!id)id=usb_match_dynamic_id(intf,driver);driver->probe(intf,id);//hub_driver():hub_probe()......}staticinthub_probe(structusb_interface*intf,conststructusb_device_id*id){structusb_host_interface*desc;structusb_endpoint_descriptor*endpoint;structusb_hub*hub;desc=intf->cur_altsetting;23endpoint=&desc->endpoint[0].desc;hub=kzalloc(sizeof(*hub),GFP_KERNEL);......hub_configure(hub,endpoint)......}staticinthub_configure(structusb_hub*hub,structusb_endpoint_descriptor*endpoint){structusb_device*hdev=hub->hdev;unsignedintpipe;intmaxp,ret;hub->buffer=kmalloc(sizeof(*hub->buffer),GFP_KERNEL);hdev->maxchild=hub->descriptor->bNbrPorts;pipe=usb_rcvintpipe(hdev,endpoint->bEndpointAddress);maxp=usb_maxpacket(hdev,pipe,usb_pipeout(pipe));......hub->urb=usb_alloc_urb(0,GFP_KERNEL);usb_fill_int_urb(hub->urb,hdev,pipe,*hub->buffer,maxp,hub_irq,hub,endpoint->bInterval);//提交上面初始化好的中断urb给主机控制器,然后主机控制器根据设定好的//轮询时间,询问hub,看有没有端口有木有变化,有则触发hub的中断服务//程序hub_irq()hub_activate(hub,HUB_INIT);}staticinlinevoidusb_fill_int_urb(structurb*urb,structusb_device*dev,unsignedintpipe,void*transfer_buffer,intbuffer_length,usb_complete_tcomplete_fn,void*context,intinterval){urb->dev=dev;urb->pipe=pipe;urb->transfer_buffer=transfer_buffer;structurb*usb_alloc_urb(intiso_packets,gfp_tmem_flags){structurb*urb;urb=kmalloc(sizeof(structurb)+iso_packets*sizeof(structusb_iso_packet_descriptor),mem_flags);......usb_init_urb(urb);......}第一个参数iso_packets,表示structurb结构最后那个变长数组iso_frame_desc的元素数目,也就是等时包的数量,对于控制/中断/批量传输这个参数都应该为0。24urb->transfer_buffer_length=buffer_length;urb->complete=complete_fn;urb->context=context;if(dev->speed==USB_SPEED_HIGH||dev->speed==USB_SPEED_SUPER)urb->interval=1<<(interval-1);//高速或超速:单位微帧,经过2的(bInterval-1)次方计算//这里的bInterval为12elseurb->interval=interval;//低速或全速:单位为帧urb->start_frame=-1;//专门给等时传输用的}staticvoidhub_activate(structusb_hub*hub,enumhub_activation_typetype){structusb_device*hdev=hub->hdev;//在hub_probe()处初始化intport1;unsigneddelay;if(type==HUB_INIT2)gotoinit2;if(type==HUB_INIT3)gotoinit3;if(type==HUB_INIT){//首先传入参数类型是HUB_INITdelay=hub_power_on(hub,false);//定时结束后,进入init2阶段PREPARE_DELAYED_WORK(&hub->init_work,hub_init_func2);schedule_delayed_work(&hub->init_work,msecs_to_jiffies(delay));return;}staticunsignedhub_power_on(structusb_hub*hub,booldo_delay){intport1;unsignedpgood_delay=hub->descriptor->bPwrOn2PwrGood*2;unsigneddelay;......for(port1=1;port1<=hub->descriptor->bNbrPorts;port1++)//将USB_PORT_FEAT_POWER这一位置1set_port_feature(hub->hdev,port1,USB_PORT_FEAT_POWER);//等待至少100ms让端口电源稳定之后,再访问它delay=max(pgood_delay,(unsigned)100);if(do_delay)msleep(delay);returndelay;}staticvoidhub_init_func2(structwork_struct*ws){......hub_activate(hub,HUB_INIT2);}25init2://检查每个端口并设置hub->change_bits,让khubd知道哪个端口需要关注//hdev->maxchild的初始化在hub_configure()for(port1=1;port1<=hdev->maxchild;++port1){structusb_device*udev=hdev->children[port1-1];u16portstatus,portchange;portstatus=portchange=0;hub_port_status(hub,port1,&portstatus,&portchange);staticinthub_port_status(structusb_hub*hub,intport1,u16*status,u16*change){......//GetPortStatus是Hub的一个标准请求,它将获取端口状态//和变化状态,并存于*status和*change中.get_port_status(hub->hdev,port1,&hub->status->port);*status=le16_to_cpu(hub->status->port.wPortStatus);*change=le16_to_cpu(hub->status->port.wPortChange);......}staticintget_port_status(structusb_device*hdev,intport1,structusb_port_status*data){inti,status=-ETIMEDOUT;for(i=0;i<USB_STS_RETRIES&&status==-ETIMEDOUT;i++){usb_control_msg(hdev,usb_rcvctrlpipe(hdev,0),USB_REQ_GET_STATUS,USB_DIR_IN|USB_RT_PORT,0,port1,data,sizeof(*data),USB_STS_TIMEOUT);}......}intusb_control_msg(structusb_device*dev,unsignedintpipe,__u8request,__u8requesttype,__u16value,__u16index,void*data,__u16size,inttimeout){structusb_ctrlrequest*dr;dr=kmalloc(sizeof(structusb_ctrlrequest),GFP_NOIO);dr->bRequestType=requesttype;dr->bRequest=request;dr->wValue=cpu_to_le16(value);dr->wIndex=cpu_to_le16(index);dr->wLength=cpu_to_le16(size);usb_internal_control_msg(dev,pipe,dr,data,size,timeout);......}staticintusb_internal_control_msg(structusb_device*usb_dev,unsignedintpipe,structusb_ctrlrequest*cmd,void*data,intlen,inttimeout){structurb*urb;......urb=usb_alloc_urb(0,GFP_NOIO);//将data(即上面的&hub->status->port)封装成urb,进行控制传输usb_fill_control_urb(urb,usb_dev,pipe,(unsignedchar*)cmd,data,len,usb_api_blocking_completion,NULL);usb_start_wait_urb(urb,timeout,&length);......}26......//清掉端口状态和变化状态,并稍后进行去抖if(portchange&USB_PORT_STAT_C_CONNECTION){need_debounce_delay=true;clear_port_feature(hub->hdev,port1,USB_PORT_FEAT_C_CONNECTION);}if(portchange&USB_PORT_STAT_C_ENABLE){need_debounce_delay=true;clear_port_feature(hub->hdev,port1,USB_PORT_FEAT_C_ENABLE);}//need_debounce_delay相当于一个去抖作用,防止电磁干扰if(need_debounce_delay){delay=HUB_DEBOUNCE_STABLE;if(type==HUB_INIT2){PREPARE_DELAYED_WORK(&hub->init_work,hub_init_func3);schedule_delayed_work(&hub->init_work,msecs_to_jiffies(delay));return;staticvoidhub_init_func3(structwork_struct*ws){......hub_activate(hub,HUB_INIT3);}staticinlinevoidusb_fill_control_urb(structurb*urb,structusb_device*dev,unsignedintpipe,unsignedchar*setup_packet,void*transfer_buffer,intbuffer_length,usb_complete_tcomplete_fn,void*context){urb->dev=dev;urb->pipe=pipe;urb->setup_packet=setup_packet;urb->transfer_buffer=transfer_buffer;urb->transfer_buffer_length=buffer_length;urb->complete=complete_fn;urb->context=context;}staticintusb_start_wait_urb(structurb*urb,inttimeout,int*actual_length){structapi_contextctx;unsignedlongexpire;init_completion(&ctx.done);urb->context=&ctx;urb->actual_length=0;//提交上面刚刚创建的控制urbusb_submit_urb(urb,GFP_NOIO);//当提交urb给USBcore和HCD处理完之后,就会调用结束处理函数//usb_api_blocking_completion,从而调用complete来通知usb_start_wait_urb,//传输应经完成了expire=timeout?msecs_to_jiffies(timeout):MAX_SCHEDULE_TIMEOUT;if(!wait_for_completion_timeout(&ctx.done,expire)){usb_kill_urb(urb);}......}27}init3:usb_submit_urb(hub->urb,GFP_NOIO);//提交刚才初始化好的中断urb给主机控制器......kick_khubd(hub);}intusb_submit_urb(structurb*urb,gfp_tmem_flags){intxfertype,max;structusb_device*dev;structusb_host_endpoint*ep;dev=urb->dev;ep=usb_pipe_endpoint(dev,urb->pipe);urb->ep=ep;xfertype=usb_endpoint_type(&ep->desc);max=le16_to_cpu(ep->desc.wMaxPacketSize);if(xfertype==USB_ENDPOINT_XFER_CONTROL){......}urb->transfer_flags&=~(URB_DIR_MASK|URB_DMA_MAP_SINGLE|URB_DMA_MAP_PAGE|URB_DMA_MAP_SG|URB_MAP_LOCAL|URB_SETUP_MAP_SINGLE
本文档为【Linux内核USB驱动架构:USB设备驱动架构】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: ¥18.0 已有0 人下载
最新资料
资料动态
专题动态
个人认证用户
像风一样
人民教师
格式:pdf
大小:1016KB
软件:PDF阅读器
页数:0
分类:互联网
上传时间:2019-05-03
浏览量:22