• USB 四种传输方式的通信API


    阻塞问题

    A 调用 B
    A 是用户代码, B 是 hub控制,控制传输,bulk传输,中断传输,等时传输
    
    如果B是中断传输代码和等时传输代码
    	A来负责阻塞,B不负责阻塞
    		// A 在用户空间读取数据的时候 加锁
    		// A 利用 complete(来数据时被调用) 调用自己的解锁机制来 解除阻塞
    如果B是其他代码
    	B来负责阻塞,A不负责阻塞
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    传输的物质

    urb
    
    • 1

    传输对象

    roothub设备
    	控制传输 : hub控制
    	中断传输 : hub 状态监测
    	等时传输 : 不存在
    	批量传输 : 不存在
    非roothub设备
    	控制传输
    	中断传输
    	等时传输
    	批量传输
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    
    如果传输对象是 roothub,1.数据(urb) 不过总线
    	2.直接调roothub驱动处理
    如果传输对象是 非roothub(一般hub设备或者function设备),1.数据(urb) 在总线中传送
    	2.直接调用 hcd 驱动处理 (hcd经编程控制后,数据传送给phy,phy将数据传输到总线上)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    针对roothub的传输

    roothub 中断传输 : 状态监测

    第一次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 的并发 的?
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    插入后
    	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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    
    	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));
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    插入时
    
    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   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    
    插入后
    	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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    roothub 控制传输 : hub控制

    roothub 协议
    构造USB标准请求,来控制
    
    • 1
    roothub 控制代码
    但是在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 );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    如何发起一次 hub_control
    // 调用时机 : 枚举过程中
    // 具体调用时机: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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
     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)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    针对非roothub设备的传输

    控制传输

    控制传输协议

    参考 文章中的 “枚举过程中的一次 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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    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);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    如何发起一次控制传输
    // 在 枚举过程中被调用
    // 具体调用时机 参考 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);
    
    • 1
    • 2
    • 3
    • 4

    bulk 传输

    bulk 传输协议
    bulk 传输代码
    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    如何发起一次bulk传输
    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
    
    • 1
    • 2
    • 3

    中断传输

    中断传输协议
    
    
    • 1
    中断传输代码
    usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval);
    usb_submit_urb
    
    • 1
    • 2
    如何发起一次中断传输
    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
    
    • 1
    • 2
    • 3
    • 4

    核心代码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;
    					}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    __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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    手写useState与useEffect
    【数据库查询表结构】
    【一起学数据结构与算法】还不会哈希表吗?一篇让你学会哈希表
    JS的装箱和拆箱
    软件测试如何进行缺陷数据分析及发现更多缺陷的方法
    麻了,代码改成多线程,竟有9大问题
    vue如何实现多页面应用网页
    Pick-a-Pic:An open dataset of user preferences for text-to-image generation
    如何开启Linux的SSH服务?sudo service ssh start和sudo systemctl enable ssh两种不同的开启方式有什么区别?
    linux-vsftp虚拟多用户
  • 原文地址:https://blog.csdn.net/u011011827/article/details/128112882