A 调用 B
A 是用户代码, B 是 hub控制,控制传输,bulk传输,中断传输,等时传输
如果B是中断传输代码和等时传输代码
A来负责阻塞,B不负责阻塞
// A 在用户空间读取数据的时候 加锁
// A 利用 complete(来数据时被调用) 调用自己的解锁机制来 解除阻塞
如果B是其他代码
B来负责阻塞,A不负责阻塞
urb
roothub设备
控制传输 : hub控制
中断传输 : hub 状态监测
等时传输 : 不存在
批量传输 : 不存在
非roothub设备
控制传输
中断传输
等时传输
批量传输
如果传输对象是 roothub,则
1.数据(urb) 不过总线
2.直接调roothub驱动处理
如果传输对象是 非roothub(一般hub设备或者function设备),则
1.数据(urb) 在总线中传送
2.直接调用 hcd 驱动处理 (hcd经编程控制后,数据传送给phy,phy将数据传输到总线上)
第一次RHSC中断后
就开始loop ,直到 loop中没有得到 hub change // loop的主函数是 usb_hcd_poll_rh_status
loop 中会
1.查询 hub change 并查看是否有urb
2.查到且有urb的话 :
2.1 调用 hub_irq->kick_hub_wq(hub) 处理hub change
2.2 开启下一次loop
2.2.1 hub_irq->hub_resubmit_irq_urb
2.2.2 usb_hcd_poll_rh_status->mod_timer
3.没查到的话 :
什么都不做 , 即 下一次loop 不会开启了
既然 usb_hcd_poll_rh_status 只被 中断调用了一次,剩下的都是timer
那是怎么处理 ohci_irq调用usb_hcd_poll_rh_status 和 timer调用usb_hcd_poll_rh_status 的并发 的?
插入后
ohci_irq
usb_hcd_poll_rh_status
有urb usb_hcd_giveback_urb->hub_irq->usb_submit_urb->usb_hcd_submit_urb->...->rh_queue_status->没timer
// 这次的urb 来自于 hub_configure->usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);
// hub_activate -> usb_submit_urb(hub->urb, GFP_NOIO);
设置timer
run_timer_softirq -> rh_timer_func
usb_hcd_poll_rh_status
有urb usb_hcd_giveback_urb->hub_irq->usb_submit_urb->usb_hcd_submit_urb->...->rh_queue_status->没timer
设置timer
run_timer_softirq -> rh_timer_func
usb_hcd_poll_rh_status
length = 0
没设置timer
usb_hcd_poll_rh_status
length = hcd->driver->hub_status_data(hcd, buffer); // 即ohci_hub_status_data
if (ohci_root_hub_state_changes(ohci, changed, any_connected, rhsc_status))set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
else clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
if (length > 0) && (hcd->status_urb != NULL){
clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
memcpy(urb->transfer_buffer, buffer, length);
usb_hcd_unlink_urb_from_ep(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, 0);
__usb_hcd_giveback_urb
urb->complete(urb); // 即 hub_irq
kick_hub_wq(hub); // 做事情
usb_submit_urb // 开启下一次循环 条件1
usb_hcd_submit_urb
if (is_root_hub(urb->dev)) // 传输对象是 roothub设备
rh_urb_enqueue
if (usb_endpoint_xfer_int(&urb->ep->desc)) rh_queue_status
hcd->status_urb = urb;
if (HCD_POLL_PENDING(hcd)) mod_timer(&hcd->rh_timer, jiffies); //枚举过程中没有
}else if (length > 0) && (hcd->status_urb != NULL){
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); // 枚举过程中没有发生
}
// 开启下一次循环条件2
if (HCD_POLL_RH(hcd)) mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
boot 时
SUD File: drivers/usb/core/hcd.c, Line: 00723: rh_queue_status
[<c003cca8>] (unwind_backtrace+0x0/0xfc) from [<c054d70c>] (dump_stack+0x18/0x1c)
[<c054d70c>] (dump_stack+0x18/0x1c) from [<c031e2d0>] (usb_hcd_submit_urb+0x324/0x834)
[<c031e2d0>] (usb_hcd_submit_urb+0x324/0x834) from [<c031ef60>] (usb_submit_urb+0xfc/0x2d0)
[<c031ef60>] (usb_submit_urb+0xfc/0x2d0) from [<c03190d4>] (hub_activate+0x218/0x424)
[<c03190d4>] (hub_activate+0x218/0x424) from [<c0319338>] (hub_init_func2+0x18/0x1c)
[<c0319338>] (hub_init_func2+0x18/0x1c) from [<c006ab38>] (process_one_work+0x164/0x480)
[<c006ab38>] (process_one_work+0x164/0x480) from [<c006b8c4>] (worker_thread+0x174/0x468)
[<c006b8c4>] (worker_thread+0x174/0x468) from [<c0070ae4>] (kthread+0x8c/0x94)
[<c0070ae4>] (kthread+0x8c/0x94) from [<c0037a34>] (kernel_thread_exit+0x0/0x8)
SUD File: drivers/usb/core/hcd.c, Line: 00750: rh_queue_status
boot
SUD File: drivers/usb/core/hcd.c, Line: 00707: usb_hcd_poll_rh_status,uses_new_polling:1,HCD_POLL_RH:0
插入时
2次
SUD File: drivers/usb/core/hcd.c, Line: 00723: rh_queue_status
[<c003cca8>] (unwind_backtrace+0x0/0xfc) from [<c054d70c>] (dump_stack+0x18/0x1c)
[<c054d70c>] (dump_stack+0x18/0x1c) from [<c031e2d0>] (usb_hcd_submit_urb+0x324/0x834)
[<c031e2d0>] (usb_hcd_submit_urb+0x324/0x834) from [<c031ef60>] (usb_submit_urb+0xfc/0x2d0)
[<c031ef60>] (usb_submit_urb+0xfc/0x2d0) from [<c03193cc>] (hub_irq+0x90/0xe8)
[<c03193cc>] (hub_irq+0x90/0xe8) from [<c031d598>] (usb_hcd_giveback_urb+0x58/0xcc)
[<c031d598>] (usb_hcd_giveback_urb+0x58/0xcc) from [<c031d6d4>] (usb_hcd_poll_rh_status+0xc8/0x164)
[<c031d6d4>] (usb_hcd_poll_rh_status+0xc8/0x164) from [<c032d41c>] (ohci_irq+0x410/0x4b8)
[<c032d41c>] (ohci_irq+0x410/0x4b8) from [<c031c878>] (usb_hcd_irq+0x3c/0xac)
[<c031c878>] (usb_hcd_irq+0x3c/0xac) from [<c008ec74>] (handle_irq_event_percpu+0x78/0x22c)
[<c008ec74>] (handle_irq_event_percpu+0x78/0x22c) from [<c008ee58>] (handle_irq_event+0x30/0x40)
[<c008ee58>] (handle_irq_event+0x30/0x40) from [<c0091060>] (handle_level_irq+0x88/0xf0)
[<c0091060>] (handle_level_irq+0x88/0xf0) from [<c008ebdc>] (generic_handle_irq+0x38/0x44)
[<c008ebdc>] (generic_handle_irq+0x38/0x44) from [<c0036038>] (asm_do_IRQ+0x38/0x8c)
[<c0036038>] (asm_do_IRQ+0x38/0x8c) from [<c054ff94>] (__irq_svc+0x34/0x80)
Exception stack(0xc07dff40 to 0xc07dff88)
ff40: c07e59c8 00000000 c07dff88 00000000 c07de000 c0826884 c07e6f64 c07e0000
ff60: 50004008 410fb766 5002f038 c07dff94 c07dff98 c07dff88 c0038198 c0037ac4
ff80: 60000013 ffffffff
[<c054ff94>] (__irq_svc+0x34/0x80) from [<c0037ac4>] (default_idle+0x20/0x24)
[<c0037ac4>] (default_idle+0x20/0x24) from [<c0038198>] (cpu_idle+0x60/0x94)
[<c0038198>] (cpu_idle+0x60/0x94) from [<c0549034>] (rest_init+0x60/0x78)
[<c0549034>] (rest_init+0x60/0x78) from [<c0008a28>] (start_kernel+0x284/0x31c)
[<c0008a28>] (start_kernel+0x284/0x31c) from [<5000803c>] (0x5000803c)
SUD File: drivers/usb/core/hcd.c, Line: 00750: rh_queue_status
1次
SUD File: drivers/usb/core/hcd.c, Line: 00723: rh_queue_status
[<c003cca8>] (unwind_backtrace+0x0/0xfc) from [<c054d70c>] (dump_stack+0x18/0x1c)
[<c054d70c>] (dump_stack+0x18/0x1c) from [<c031e2d0>] (usb_hcd_submit_urb+0x324/0x834)
[<c031e2d0>] (usb_hcd_submit_urb+0x324/0x834) from [<c031ef60>] (usb_submit_urb+0xfc/0x2d0)
[<c031ef60>] (usb_submit_urb+0xfc/0x2d0) from [<c03193cc>] (hub_irq+0x90/0xe8)
[<c03193cc>] (hub_irq+0x90/0xe8) from [<c031d598>] (usb_hcd_giveback_urb+0x58/0xcc)
[<c031d598>] (usb_hcd_giveback_urb+0x58/0xcc) from [<c031d6d4>] (usb_hcd_poll_rh_status+0xc8/0x164)
[<c031d6d4>] (usb_hcd_poll_rh_status+0xc8/0x164) from [<c031dd3c>] (rh_timer_func+0x10/0x14)
[<c031dd3c>] (rh_timer_func+0x10/0x14) from [<c0060b90>] (run_timer_softirq+0x1e0/0x35c)
[<c0060b90>] (run_timer_softirq+0x1e0/0x35c) from [<c0058d34>] (__do_softirq+0xc4/0x1d0)
[<c0058d34>] (__do_softirq+0xc4/0x1d0) from [<c0058fb4>] (irq_exit+0x48/0x50)
[<c0058fb4>] (irq_exit+0x48/0x50) from [<c003603c>] (asm_do_IRQ+0x3c/0x8c)
[<c003603c>] (asm_do_IRQ+0x3c/0x8c) from [<c054ff94>] (__irq_svc+0x34/0x80)
Exception stack(0xc07dff40 to 0xc07dff88)
ff40: c07e59c8 00000000 c07dff88 00000000 c07de000 c0826884 c07e6f64 c07e0000
ff60: 50004008 410fb766 5002f038 c07dff94 c07dff98 c07dff88 c0038198 c0037ac4
ff80: 60000013 ffffffff
[<c054ff94>] (__irq_svc+0x34/0x80) from [<c0037ac4>] (default_idle+0x20/0x24)
[<c0037ac4>] (default_idle+0x20/0x24) from [<c0038198>] (cpu_idle+0x60/0x94)
[<c0038198>] (cpu_idle+0x60/0x94) from [<c0549034>] (rest_init+0x60/0x78)
[<c0549034>] (rest_init+0x60/0x78) from [<c0008a28>] (start_kernel+0x284/0x31c)
[<c0008a28>] (start_kernel+0x284/0x31c) from [<5000803c>] (0x5000803c)
SUD File: drivers/usb/core/hcd.c, Line: 00750: rh_queue_status
插入后
ohci_irq
usb_hcd_poll_rh_status
有urb usb_hcd_giveback_urb->hub_irq->usb_submit_urb->usb_hcd_submit_urb->rh_queue_status->没timer
设置timer
run_timer_softirq -> rh_timer_func
usb_hcd_poll_rh_status
有urb usb_hcd_giveback_urb->hub_irq->usb_submit_urb->usb_hcd_submit_urb->rh_queue_status->没timer
设置timer
run_timer_softirq -> rh_timer_func
usb_hcd_poll_rh_status
length = 0
没设置timer
构造USB标准请求,来控制
但是在ohci中,是直接控制寄存器的,所以
在 ohci_hub_control 中,做了一层 描述符 和 寄存器的转换
ohci_hub_control
673 int ohci_hub_control(
674 struct usb_hcd *hcd,
675 u16 typeReq,
676 u16 wValue,
677 u16 wIndex,
678 char *buf,
679 u16 wLength
680 );
// 调用时机 : 枚举过程中
// 具体调用时机:https://blog.csdn.net/u011011827/article/details/128092508
hub_port_reset
set_port_feature(hub->hdev, port1, (warm ? USB_PORT_FEAT_BH_PORT_RESET : USB_PORT_FEAT_RESET));
usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, NULL, 0, 1000);
usb_hcd_submit_urb
rh_urb_enqueue
rh_call_control
hcd->driver->hub_control/即ohci_hub_control
912 [<c03a2900>] (ohci_hub_control) from [<c038de5c>] (usb_hcd_submit_urb+0x22c/0x9c4)
913 [<c038de5c>] (usb_hcd_submit_urb) from [<c0391440>] (usb_start_wait_urb+0x50/0x158)
914 [<c0391440>] (usb_start_wait_urb) from [<c03919d8>] (usb_control_msg+0xac/0x110)
915 [<c03919d8>] (usb_control_msg) from [<c0384774>] (set_port_feature+0x44/0x4c)
916 [<c0384774>] (set_port_feature) from [<c03863ec>] (hub_port_reset+0x8c/0x720)
917 [<c03863ec>] (hub_port_reset) from [<c0388d7c>] (hub_port_init+0x424/0xcbc)
918 [<c0388d7c>] (hub_port_init) from [<c038abf4>] (hub_event+0x6f8/0x16e4)
919 [<c038abf4>] (hub_event) from [<c012785c>] (process_one_work+0x1d0/0x438)
920 [<c012785c>] (process_one_work) from [<c0127b04>] (worker_thread+0x40/0x580)
921 [<c0127b04>] (worker_thread) from [<c012c85c>] (kthread+0x10c/0x120)
922 [<c012c85c>] (kthread) from [<c0100170>] (ret_from_fork+0x14/0x24)
参考 文章中的 “枚举过程中的一次 control transfer : set address”
usb_control_msg 用于控制传输 , 对应一次 control transfer
对应 两个阶段(SETUP&STATUS)或三个阶段(SETUP&DATA&STATUS)
SETUP 中的 数据包 是 标准命令请求,对应 struct usb_ctrlrequest
set address 是 两个阶段(SETUP&STATUS),
usb_control_msg 函数过程包括这里两个阶段+ 1个中断
usb_control_msg 总是包括
一次"control transfer"
https://blog.csdn.net/u011011827/article/details/126452348 中的
枚举过程中的一次 control transfer : set address
枚举过程中的一次 control transfer : get device descriptor
和
一次 中断(一个周期(1ms)内ACK来了,下个周期内一开始就会来中断)
因为 usb_control_msg 调用了 usb_start_wait_urb
https://www.cnblogs.com/sky-heaven/p/6296917.html
136 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
137 __u8 requesttype, __u16 value, __u16 index, void *data,
138 __u16 size, int timeout);
usb_control_msg
usb_internal_control_msg
struct urb *urb = usb_alloc_urb(0, GFP_NOIO);
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd ,\ // setup包
data, \ // setup包后面的数据
len, usb_api_blocking_completion, NULL);
usb_start_wait_urb(urb, timeout, &length);
init_completion(&ctx.done);
usb_submit_urb(urb, GFP_NOIO);
wait_for_completion_timeout(&ctx.done, expire); // 与 usb_api_blocking_completion 中的 complete(&ctx->done); 同步
usb_free_urb(urb);
vic_handle_irq
...
usb_hcd_irq (对应一个硬件中断线) // linux-5.11
hcd->driver->irq(hcd) // 即 ohci_irq
usb_hcd_poll_rh_status
usb_hcd_giveback_urb
tasklet_schedule // tasklet_setup(&bh->bh, usb_giveback_urb_bh);
usb_giveback_urb_bh
__usb_hcd_giveback_urb
usb_api_blocking_completion
complete(&ctx->done);
// 在 枚举过程中被调用
// 具体调用时机 参考 https://blog.csdn.net/u011011827/article/details/128092508
hub_set_address
usb_control_msg(udev, usb_sndaddr0pipe(), USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
usb_bulk_msg // drivers/usb/core/message.c
usb_alloc_urb
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, usb_api_blocking_completion, NULL);
usb_start_wait_urb(urb, timeout, actual_length);
init_completion(&ctx.done);
usb_submit_urb(urb, GFP_NOIO);
wait_for_completion_timeout(&ctx.done, expire); // 与 usb_api_blocking_completion 中的 complete(&ctx->done); 同步
usb_free_urb(urb);
drivers/usb/usb-skeleton.c // 接口驱动 demo (基于bulk传输)
中的 skel_do_read_io 中的 usb_fill_bulk_urb&usb_submit_urb
中的 skel_write 中的 usb_alloc_urb & usb_fill_bulk_urb&usb_submit_urb
usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval);
usb_submit_urb
drivers/hid/usbhid/usbmouse.c // 接口驱动 实例(usb) (基于中断传输)
中的 usb_mouse_probe 中的 usb_alloc_urb & usb_fill_int_urb(...,usb_mouse_irq,...);
中的 usb_mouse_irq 中的 usb_submit_urb
中的 usb_mouse_open 中的 usb_submit_urb
usb_submit_urb
usb_hcd_submit_urb
if (is_root_hub(urb->dev)) // 传输对象是 roothub设备
rh_urb_enqueue
if (usb_endpoint_xfer_int(&urb->ep->desc)) rh_queue_status
usb_hcd_link_urb_to_ep
mod_timer(&hcd->rh_timer, jiffies);
if (usb_endpoint_xfer_control(&urb->ep->desc)) rh_call_control
hcd->driver->hub_control/即ohci_hub_control
switch (typeReq) {
case ClearHubFeature:
...
ohci_writel (ohci, RH_HS_OCIC, &ohci->regs->roothub.status);
break;
...
}
else // 传输对象是 非roothub设备
hcd->driver->urb_enqueue/ohci_urb_enqueue
td_submit_urb
switch (urb_priv->ed->type) {
case PIPE_BULK:
ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus);
wmb ();
ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus);
break;
case PIPE_CONTROL:
td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++);
wmb ();
ohci_writel (ohci, OHCI_CLF, &ohci->regs->cmdstatus);
break;
case PIPE_INTERRUPT:
td_fill (ohci, info, data, data_len, urb, cnt);
wmb ();
ohci->hc_control |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
break;
case PIPE_ISOCHRONOUS:
td_fill (ohci, TD_CC | TD_ISO | frame,...);
wmb ();
ohci->hc_control |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
break;
}
__usb_create_hcd
timer_setup(&hcd->rh_timer, rh_timer_func, 0);
rh_timer_func
usb_hcd_poll_rh_status
length = hcd->driver->hub_status_data(hcd, buffer);
memcpy(urb->transfer_buffer, buffer, length);
usb_hcd_unlink_urb_from_ep(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, 0);
__usb_hcd_giveback_urb
urb->complete(urb);