Usb Hub代码分析
如需引用请注明出处:http://blog.csdn.net/zkami 作者:ZhengKui
在host controller初始化的时候一定会调用hub_probe进行初始化,至少对root hub初始化
hub_probe(struct usb_interface *intf, const struct usb_device_id *id) (hub.c)
此时struct usb_interface 和struct usb_device的数据已经在hc初始化的过程中得到
-> hdev = interface_to_usbdev(intf);
由struct usb_interface 得到usb_device, 中间通过struct device转换,
然后:分配struct usb_hub, 并初始化hub->event_list和hub->leds
-> INIT_DELAYED_WORK(&hub->leds, led_work);初始化led_work工作队列
以后调用schedule_delayed_work()来唤醒led_work, 暂时不用led
-> usb_get_intf(intf);
-> usb_set_intfdata (intf, hub);让struct usb_hub和struct usb_interface关联
-> hub_configure(hub, endpoint)
->get_hub_descriptor(hdev, hub->descriptor,sizeof(*hub->descriptor));
得到hub->descriptor
-> usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
USB_DT_HUB << 8, 0, data, size,
USB_CTRL_GET_TIMEOUT);
对tt初始化, struct usb_tt用来匹配低速设备和高速hub.tt与hub相关与OHCI/EHCI无关
这样一个port既能支持high也能支持full/low
-> INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
-> hub_tt_kevent()
-> usb_set_interface(hdev, 0, 1); high speed hub
-> usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
-> usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
sizeof(*status), USB_CTRL_GET_TIMEOUT);
接着:定义每一个port的电流
-> hub_hub_status(hub, &hubstatus, &hubchange);
这个请求是hub自己定义的(spec P425),将当前hub状态保存在hubstatus,已经改变的
hub状态保存在hubchange里
-> get_hub_status(hub->hdev, &hub->status->hub);
->usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
data, sizeof(*data), USB_STS_TIMEOUT);
-> usb_alloc_urb(0, GFP_KERNEL); 分配urb
-> usb_init_urb(urb); 初始化urb
-> usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval); 填充int urb
-> hub_power_on(hub);
-> set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
对每一个port
-> hub_activate(hub);
-> usb_submit_urb(hub->urb, GFP_NOIO);
将之前usb_fill_int_urb()的urb提交
-> schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
延迟LED_CYCLE_PERIOD一段时间后,调度hub->leds, 让led一闪一闪亮晶晶
-> kick_khubd(hub);向&hub_event_list链表挂载event,并唤醒hub_thread()
-> to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
由usb_hub->struct device->usb_interface,增加pm的引用计数
hub要使用了,就别让电源管理把它挂起来了
-> list_add_tail(&hub->event_list, &hub_event_list);
如果list_empty(&hub->event_list)即第一次调用,就把当前hub->event_list
加入到全局hub_event_list中去
-> wake_up(&khubd_wait);
唤醒休眠的hub_thread(),从wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); 继续向下执行,khubd_wait是wait_queue_head_t类型。hub_events()将再次被执行
-> hub_disconnect (intf);
-> usb_get_intfdata (intf);
由usb_interface->struct device->usb_hub 得到usb_hub
-> list_del_init(&hub->event_list);删除当前hub 的event_list
usb_hub_init(void) hub.c
->usb_register(&hub_driver) 注册hub_driver 那末怎莫把hub_driver与hub_device挂接起来呢????
-> kthread_run(hub_thread, NULL, "khubd"); 创建并唤醒线程hub_thread
-> usb_deregister(&hub_driver) 注销hub_driver
hub执行线程
hub_thread(void *__unused) hub.c
-> hub_events();
-> list_entry(tmp, struct usb_hub, event_list); 得到那个触发hub_events()的hub (struct usb_hub)
-> to_usb_interface(hub_dev); 再得到 struct usb_interface
-> usb_lock_device(hdev); 通过semaphone锁住这个usb_device
-> hub_pre_reset(intf); 如果设备状态是USB_STATE_NOTATTACHED
-> usb_autopm_get_interface(intf); 电源管理方面,让这个usb_interface引用计数加1,以防hub自动挂起
-> usb_autopm_do_interface(intf, 1);
-> usb_reset_composite_device(hdev, intf); 如果hub出错,把复合设备reset,复合设备就是有多个interface的设备
-> usb_autoresume_device(udev); 防止在reset过程中自动挂起了
接着:针对设备中的每个interface,找到其driver (usb_driver)并调用usb_driver->pre_reset(usb_interface)
-> usb_reset_device(udev);
接着:针对设备中的每个interface,找到其driver (usb_driver)并调用usb_driver->post_reset(usb_interface)
-> usb_autosuspend_device(udev);
接着:轮询该hub的每个端口,查看是否有变化
-> hub_port_status(hub, i, &portstatus, &portchange);
通过发送Get Port Status标准hub请求,得到Status Bits和Status Change Bits
根据port变化的原因,分别判断处理
-> get_port_status(hub->hdev, port1, &hub->status->port);
-> 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);
-> clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION); //USB_PORT_STAT_C_CONNECTION
hub标准命令,清除USB_PORT_FEAT_C_CONNECTION这个feature, 说明已经确认这个feature了
-> usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
NULL, 0, 1000);
-> clear_port_feature(hdev, i, USB_PORT_FEAT_C_ENABLE); //USB_PORT_STAT_C_ENABLE
-> clear_port_feature(hdev, i, USB_PORT_FEAT_C_SUSPEND); //USB_PORT_FEAT_C_SUSPEND
-> remote_wakeup(hdev-> children[i-1]);
-> hub_port_disable(hub, i, 1);
-> clear_port_feature(hdev, i, USB_PORT_FEAT_C_OVER_CURRENT); //USB_PORT_STAT_C_OVERCURRENT
-> hub_power_on(hub); 轮询hub的每一个port并设置port状态
-> set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
-> usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
NULL, 0, 1000);
-> clear_port_feature(hdev, i, USB_PORT_FEAT_C_RESET); //USB_PORT_STAT_C_RESET
-> hub_port_connect_change(hub, i,portstatus, portchange); 一个usb设备插入port,最终会发生的事情
-> hub_hub_status(hub, &hubstatus, &hubchange)
-> clear_hub_feature(hdev, C_HUB_LOCAL_POWER); //HUB_CHANGE_LOCAL_POWER
-> clear_hub_feature(hdev, C_HUB_OVER_CURRENT); //HUB_CHANGE_OVERCURRENT
-> hub_power_on(hub);
-> usb_enable_root_hub_irq(hdev->bus); 如果是root hub
-> usb_autopm_enable(intf);
-> usb_unlock_device(hdev);
-> wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
只要hub_event_list不为空, 就唤醒。否则休眠,线程不会继续执行。ecos只要用“条件变量”把这个线程阻塞就行了
当再向下执行时,hub_event_list已经不为空了
阅读(2337) | 评论(1) | 转发(1) |