USB 四种传输方式的通信API

阻塞问题

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将数据传输到总线上)

针对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 的并发 的?

插入后
	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

roothub 控制传输 : hub控制

roothub 协议
构造USB标准请求,来控制
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 );

如何发起一次 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
 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)

针对非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

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);

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);
如何发起一次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

中断传输

中断传输协议

中断传输代码
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_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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值