Usb设备驱动3:root hub守护进程2

Hub正常工作后,主控制器就会定时询问hub是否有中断产生,当hub端口上有一个设备插入或拔除,hub就向主控制器发送urb请求,即把hub端口的变化状况告诉主控制器,这是通过urb请求来完成的,主机在处理完了这个urb后,就会调用urb所提供的完成函数,来调用hub的中断函数,即hub_irq。

 

Hub_irq是hub的中断处理函数,处理程序首先判断主控制器处理urb的结果状态,如果状态是OK的,则继续处理。

1.扫描hub的所有端口,确定是哪个端口发生了变化。端口是用位图来表示的,一个long型数据可以表示32个hub端口(每位表示一个端口),有多少个端口,就用多少位表示,而8位用一个字节表示,因此,最后的使用的位都是转化成了字节的的,比如一个hub有18个端口,则需要用18位来表示,但是一个字节只有8位,因此,需要用3个字节才能表示完。

2.调用kick_khubd函数,把当前hub加入到hub驱动队列hub_event_list中,然后唤醒hub守护进程wake_up(khubd_wait),开始解析hub发生的事情了。

3.hub_thread被唤醒后,将得到执行,hub_events也将得到执行

4.hub_events是分析hub事件的主函数,hub分析的相关内容都在这里执行。这个函数是一个大的死循环。

5.Hub_events处理流程

5.1先从hub_event_list中取出此次处理的hub节点,并把hub节点从原来的队列中删除,使之独立于任何链表,因为我们处理完事件后,hub结构体就要删除,因此不能保留在任何队列中。hub可以是根hub,也可以是接到根hub上的子hub,只是,不论是什么hub,都使用同样的守护进程了。

5.2.通过宏转换,找到hub节点对以的hub结构体,进而得到hub结构体对应的usb结构体,以及hub接口结构体usb_intfdev,得到这三个结构体是这个函数处理的关键。

5.3.锁住当前的hub树,因为hub只有一个守护进程,所有的hub都使用这个守护进程,而守护进程每次只能服务一个hub,因此,只要有一个hub在使用这个守护进程,就需要锁住,以防止其他hub的使用。

5.4.按位检索hub每个端口是否正在执行reset或resume操作,注意是从1开始检索的,位0表示整个hub的情况,如果当前端口正在执行reset或resume操作,则跳过对这端口的检查,否则,测试这个端口是否有状态改变,如果没有状态改变,也跳过此端口。

5.5.如果端口有状态改变,则判断端口是发生了什么状态的改变,有以下的状态

#define USB_PORT_STAT_C_CONNECTION    0x0001

#define USB_PORT_STAT_C_ENABLE              0x0002

#define USB_PORT_STAT_C_SUSPEND           0x0004

#define USB_PORT_STAT_C_OVERCURRENT  0x0008

#define USB_PORT_STAT_C_RESET         0x0010

 

5.6.确定有状态改变后,就开始对有改变的端口的状态进行进一步的处理,此时的处理,就要根据刚刚分析得到的各种状态,分开进行处理。

5.7.首先要确定端口是否还有设备,如果有,则要把设备删除,原因是,hub端口上有两种状态发生转换,1为端口从无设备到有设备的状态,此时设备还在认证中,因此端口不应该有设备,2是端口从有到无设备的转换,此时检测到还有设备,表示设备还没有被移除,因此,需要直接把设备disable掉。

5.8.把设备disable掉的动作,需要进行反弹的检查,一个设备至少需要100ms的时间,才能表示此状态是稳定的,因此,等100ms后再判断端口是否是disable了,就可以判断了

5.9.判断设备状态为无设备插入时,需要检测是否是端口电源被disable掉了,如果是,则需要开启端口电源,如果电源是开启的,则表示设备有误,结束判断,返回上层。

5.10.经过上面的判断,能执行到这里,表示端口是有设备插入了,此时,就需要要分析端口的状态了,对端口的分析,可以尝试4次,主要是为了排除各种干扰。

5.11.为即将到来的设备分配空间(struct usb_device),对这个即将到来的设备的设备结构体设置状态为连接状态,速度为未知,电源为hub分配给的,这些都是默认状态。

5.12.准备为设备分配地址,此时是子系统软件的操作,就是查看总线上128位位图中,哪位为0的,就选择出来,查找的方式是从上次记录的下一位开始查找,如果超过128了还没有找到,就接着从0开始查找,即如果频繁的拔插usb设备,即使只有一个设备,则每次插入,设备地址都会增加1,直到到达128后,从0接着开始,此时的设备地址,还不是设备的真实地址,因为还没有发送给设备。

5.13.复位设备,通过对设备的复位来达到使能设备的目的,此时,如果复位成功,则设备的状态将成为USB_STATE_DEFAULT状态,主控制器就可以通过控制端口获得设备的描述符符,通过对设备描述符的解析,可以得到设备的速度,从而可以根据速度猜测控制端口的空间大小。

5.14.得到控制端点的大小后,就开始准备往控制端点发送urb请求,获得设备的真正的设备描述符。

5.15.获得设备描述符时分两种模式,新模式和旧模式,每种模式最多试两次,每次可以最多读三回端口。对于新模式,需要分配一个64字节的空间,用于接收从设备返回的设备描述符。通过获得的设备描述符来判断端口的类别是不是确实是设备类别的,如果是,则只需要读取一次端口,就可以判断是设备描述符了,把描述符中记录的端口的空间大小给刚刚申请的空间的对应字节赋值了。

5.16.复位设备,准备给设备设置刚刚系统选择好,但还没有设置的那个地址,这个设置可以最多尝试设置两次,之间要停留200ms。

5.17.一旦设置成功,就要把设备的状态转变为地址状态(USB_STATE_ADDRESS),同时把控制端口0给disable掉,这样,这个端口上的urb链表都被清除了。

5.18.如果新的模式能走到这里,就表明新模式成功的获得了设备描述符了,因此旧模式就不要试了,而旧模式是分两次来获得设备的描述符的,第一次是发送要求获得8字节的urb请求,经过这个请求得到的数据,就可以知道设备的端口大小到达是多大,再按照获得的端口大小,获得端口的真实的设备描述符。

5.19.接下来,就要开始把这个设备加入设备模式中去了(usb_new_device)。

5.20.首先,要获得设备的配置描述符,注意,只有设备才有配置,接口,端口都是没有配置的,接口有设置。设备有多少个配置,就要分配多少个配置的空间,用于接收,而有多少个配置,已经在设备描述符中获得了,这时只需要从设备中读取就可以。

5.21.设置配置描述符指针,同样有多少个配置多少个这样的指针

5.22.一个配置描述符有9个字节,此时需要分配出这个空间,用于接收从设备中读回的配置描述符。

5.23.循环读取设备中的配置描述符,并把读回的数据放在设备结构体中的相应位置,之后,从配置中获得接口数,接口设置,以及接口下面的端点,通通都是在这里分析的,好长的几个函数。

5.24.接着,把设备添加到设备模型中去,这部分工作由设备模型完成,主要包括完成了设备链表的添加,和查找设备驱动程序的,此处是设备的驱动,usb系统只有一个设备驱动,而且是系统已经做好的,当设备里的接口被添加时,我们的编写的驱动,就是在这里被调用,用来判断驱动是否符合设备的了。

5.25.扫描设备的所有配置,选择最优的当前配置,再用选中的这个配置去设置设备。

5.26.到此,设备的配置,设置,什么都配置妥当了,系统就可以正常的使用设备了。 

posted on 2012-02-04 20:09  image eye  阅读(3097)  评论(0编辑  收藏  举报