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已经不为空了 如需引用请注明出处:http://blog.csdn.net/zkami 作者:ZhengKui |
|
来自: Vin的藏書閣 > 《Linux Kernel》