• usb peripheral 驱动 - 枚举


    当手机设备连接PC 电脑时,手机作为peripheral 模式,其开机被枚举的过程大概分为三步:
    一次完整的开机 ipc log 如下:

    // (1)检测usb cable 插入;
    [ 5.862865121] FF extcon idx                   0 ?	
    [ 5.868430850] dwc3_msm_vbus_notifier: edev:c440000.qcom,spmi:qcom,pm8150b@2:qcom,usb-pdphy@1700
    [ 5.879845642] dwc3_resume_work: resume_work: ext_idx:0
    [ 5.879848403] dwc3_resume_work: edev:c440000.qcom,spmi:qcom,pm8150b@2:qcom,usb-pdphy@1700
    [ 5.879853142] FF ss_flag                      8 ?	
    [ 5.879855798] dwc3_resume_work: max_speed:6 hw_supp_speed:6 override_speed:0
    [ 5.879857882] FF speed                        6 ?	
    [ 5.879863246] dwc3_ext_event_notify: enter: mdwc->inputs:1 hs_phy_flags:0
    [ 5.879865121] dwc3_ext_event_notify: XCVR: ID set
    [ 5.879866528] dwc3_ext_event_notify: XCVR: BSV set
    [ 5.879867725] dwc3_ext_event_notify: XCVR: SUSP clear
    [ 5.879868871] dwc3_ext_event_notify: eud: state:0 active:0 hs_phy_flags:0x0
    [ 5.879870642] dwc3_ext_event_notify: exit: mdwc->inputs:3
    [ 5.891133663] FF undefined                    0 ?	
    [ 5.891135850] FF Exit UNDEF                   0 ?	
    [ 5.920572673] FF RT Res                       0 ?	
    [ 5.920576684] FF bus_vote_start               1 ?	
    [ 5.920902361] FF bus_vote_end                 1 ?	
    [ 5.933785955] FF ss_flag                      8 ?	
    [ 6.020502518] FF Ctl Res                      0 ?	
    [ 6.020506788] FF BIDLE gsync                  1 ?	
    [ 6.020508872] FF StrtGdgt gsync               2 ?	
    [ 6.021841059] FF VbusSess                     1 ?	
    [ 6.021857205] FF StopGdgt psync               1 ?	
    [ 6.021862778] FF peripheral                   0 ?	
    // (2)开启UDC;
    [14.053613792] FF Gadgetstart                  0 ?	
    [14.053622230] FF Pullup gsync                 1 ?	
    [14.232620824] FF EP0 is not in SETUP phase    0 ?	
    [14.246319209] FF run_stop                     1 ?	
    [14.276135251] FF __Gadgetstart                0 ?	
    [14.280788480] FF UnmaskINT                    0 ?	
    [14.287081970] FF Pullup put                   0 ?	
    // (3)接收主机的枚举消息,并回应。
    [14.313223949] FF BUS RESET                    0 ?	
    [14.335765460] FF currentDraw                100 ?	
    [14.360327439] FF CONNECT DONE                 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    1. 开机枚举

    1.1 底层 peripheral

    底层识别到 usb cable 插入,产生通知事件到mdwc,mdwc 开启peripheral 模式:

    # cat /sys/kernel/debug/ipc_logging/a600000.dwc3/log
    [    21.782829232/        0x21faefc3] FF extcon idx                   0 ?	
    [    21.782832305/        0x21faeffe] dwc3_msm_vbus_notifier: edev:c440000.qcom,spmi:qcom,pm8150b@2:qcom,usb-pdphy@1700	//pdphy(qcom,usb-pdphy@1700) 挂在pm(qcom,pm8150b@2)下,pm 挂在spmi(c440000.qcom,spmi)下
    [    21.782944857/        0x21faf870] dwc3_resume_work: edev:c440000.qcom,spmi:qcom,pm8150b@2:qcom,usb-pdphy@1700
    [    21.783028295/        0x21fafeb2] FF speed                        6 ?	
    [    21.783039284/        0x21faff84] FF cc_state                     2 ?	
    [    21.784039961/        0x21fb4a92] FF undefined                    0 ?	
    [    21.784050795/        0x21fb4b61] FF Exit UNDEF                   0 ?	
    [    21.784074388/        0x21fb4d27] FF RT Res                       0 ?	
    [    21.784093503/        0x21fb4e95] FF bus_vote_start               1 ?	
    [    21.784613555/        0x21fb7597] FF bus_vote_end                 1 ?	
    [    21.860795639/        0x2211c73f] FF Ctl Res                      0 ?	
    [    21.860818451/        0x2211c8f4] FF BIDLE gsync                  1 ?	
    [    21.860829493/        0x2211c9c8] FF StrtGdgt gsync               2 ?	
    [    21.862160534/        0x22122d9d] FF VbusSess                     1 ?	
    [    21.862372826/        0x22123d89] FF StopGdgt psync               1 ?	
    [    21.862392409/        0x22123f01] FF peripheral                   0 ?	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1.1.1 usbpd

    \drivers\usb\pd\qpnp-pdphy.c 、policy_engine.c
    pmic 子系统发生 psy change 事件,会 notify 各个子系统,包括 usbpd:

    == pd->psy_nb.notifier_call = psy_changed;		power_supply_reg_notifier(&pd->psy_nb);
    	== psy_changed();		//发生了power supply changed notify
    		== queue_work(pd->wq, &pd->psy_chg_work);
    		== psy_changed_notifier_work();
    			== usbpd_process_typec_mode(pd, typec_mode);
    			== kick_sm(pd, 0);
    				== queue_work(pd->wq, &pd->sm_work);
    				== usbpd_sm();
    					== state_handlers[pd->current_state].handle_state(pd, rx_msg);
    					== enter_state_snk_startup();
    						== start_usb_peripheral(pd);
    							== extcon_set_state_sync(pd->extcon, EXTCON_USB, 1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在 usbpd 中,会创建一个extcon(依赖于一个设备节点),然后其他子系统可以引用该设备节点,并使用该 extcon。

    	/*
    	 * associate extcon with the parent dev as it could have a DT
    	 * node which will be useful for extcon_get_edev_by_phandle()
    	 */
    	pd->extcon = devm_extcon_dev_allocate(parent, usbpd_extcon_cable);
    	if (IS_ERR(pd->extcon)) {
    		usbpd_err(&pd->dev, "failed to allocate extcon device\n");
    		ret = PTR_ERR(pd->extcon);
    		goto put_psy;
    	}
    
    	ret = devm_extcon_dev_register(parent, pd->extcon);
    	if (ret) {
    		usbpd_err(&pd->dev, "failed to register extcon device\n");
    		goto put_psy;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    1.1.2 dwc3 & gadget device

    == dwc3_msm_vbus_notifier();			dbg_event(0xFF, "extcon idx", enb->idx);
    	== queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
    	== dwc3_resume_work();
    		== dwc3_msm_resume();
    		== dwc3_ext_event_notify();
    			== queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0);
    				== dwc3_otg_sm_work(struct work_struct *w);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    == dwc3_otg_sm_work(struct work_struct *w);
    	== dwc3_otg_start_peripheral(mdwc, 1);
    		== dwc3_override_vbus_status(mdwc, true);
    		== usb_phy_notify_connect(mdwc->hs_phy[0], USB_SPEED_HIGH);
    		== usb_gadget_vbus_connect(&dwc->gadget);
    			== gadget->ops->vbus_session(gadget, 1);
    			== dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active);
    				== dwc3_gadget_run_stop_util(dwc);
    					== dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend);
    						== __dwc3_gadget_start(struct dwc3 *dwc);
    							== dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
    							== __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.2 上层 configfs

    上层 init 进程启动,并开启UDC。

    echo "a600000.dwc3" > UDC
    
    • 1
    [    39.641421266/        0x366af229] FF Gadgetstart                  0 ?	
    [    39.641428349/        0x366af2b1] FF Pullup gsync                 1 ?	
    [    39.696342724/        0x367b0946] FF EP0 is not in SETUP phase    0 ?	
    [    39.696351162/        0x367b09e7] FF run_stop                     1 ?	
    [    39.696385433/        0x367b0c79] FF __Gadgetstart                0 ?	
    [    39.701054443/        0x367c6aa6] FF UnmaskINT                    0 ?	
    [    39.701113610/        0x367c6f16] FF Pullup put                   0 ?	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (1)绑定gadget 设备与驱动;
    (2)start gadget;
    (3)pullup gadget。

    == gadget_dev_desc_UDC_store();			// \drivers\usb\gadget\configfs.c
    	== usb_gadget_probe_driver()	 	// \drivers\usb\gadget\udc\core.c
    		== udc_bind_to_driver();		
    			== driver->bind(udc->gadget, driver);	
    				== configfs_composite_bind();		//绑定usb_gadget 与usb_gadget_driver 
    					== usb_add_function(c, f);		//添加function,执行function 的函数
    			== usb_gadget_udc_start(udc);
    				== udc->gadget->ops->udc_start(udc->gadget, udc->driver);
    					== dwc3_gadget_start();
    						== request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, IRQF_SHARED, "dwc3", dwc->ev_buf);
    						//注册dwc3中断,当host发消息过来时,触发中断函数
    			== usb_udc_connect_control(struct usb_udc *udc)
    				== usb_gadget_connect(struct usb_gadget *gadget)
    					== gadget->ops->pullup(gadget, 1);
    					== dwc3_gadget_pullup(struct usb_gadget *g, int is_on);
    						== dwc3_gadget_run_stop_util();
    							== dwc3_gadget_run_stop(dwc, true, false);
    								== __dwc3_gadget_start(dwc);		//enable端点传输
    									== __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)		// initializes a hw endpoint
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1.3 setup (gadget driver 操作函数)

    接收到host 发来的消息,正式开始枚举。

    [    39.759129391/        0x368d6e47] FF BUS RESET                    0 ?	
    [    39.759165954/        0x368d7104] FF currentDraw                100 ?	
    [    39.759205954/        0x368d7403] dwc3_stop_active_transfers: START
    [    39.759213141/        0x368d748d] dwc3_stop_active_transfers: DONE
    [    39.764147829/        0x368ee6a7] FF CONNECT DONE 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    当端点 enable 之后,即可进行数据传输。
    (1)对端点的处理中断;
    (2)对设备的处理中断。

    	== dwc3_thread_interrupt();					//中断产生(host发消息过来),调用回调函数
    		== dwc3_process_event_buf();			//处理中断事件buf(dwc3_event_buffer )
    			== dwc3_process_event_entry();		trace_dwc3_event(event->raw, dwc);
    				== dwc3_endpoint_interrupt();	//对端点处理的中断
    					== dwc3_ep0_interrupt();	//控制传输if (epnum == 0 || epnum == 1) 
    						== dwc3_ep0_xfer_complete();		//event->endpoint_event = DWC3_DEPEVT_XFERCOMPLETE
    							== dwc3_ep0_inspect_setup();	//dwc->ep0state = EP0_SETUP_PHASE
    								//dwc3_ep0_std_request() == dwc3_ep0_set_config()
    								== dwc3_ep0_delegate_req();
    									== dwc->gadget_driver->setup(&dwc->gadget, ctrl);
    									== configfs_composite_setup();	
    										== composite_setup();		//setup 包括获取描述符,配置,地址等操作
    											== set_config();		//ctrl->bRequest = USB_REQ_SET_CONFIGURATION
    					== dwc3_gadget_endpoint_transfer_complete();		//传输完成,返回给function(interface)
    						== dwc3_gadget_endpoint_trbs_complete();
    							== dwc3_gadget_ep_cleanup_completed_requests()
    								== dwc3_gadget_giveback();				//数据返回
    									== dwc3_gadget_del_and_unmap_request();		trace_dwc3_gadget_giveback(req);
    									== usb_gadget_giveback_request()			trace_usb_gadget_giveback_request(ep, req, 0);// give the request back to the gadget layer
    										== req->complete(ep, req);
    										== ffs_ep0_complete()	// function的完成函数
    				== dwc3_gadget_interrupt(dwc, &event->devt);	//对gadget设备的中断
    					== dwc3_gadget_reset_interrupt();				dbg_event(0xFF, "BUS RESET", dwc->gadget.speed);
    						== usb_gadget_vbus_draw(&dwc->gadget, 2);	trace_usb_gadget_vbus_draw(gadget, ret);
    							== gadget->ops->vbus_draw(gadget, mA);
    							== dwc3_gadget_vbus_draw();				dbg_event(0xFF, "currentDraw", mA);
    								== dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, 0);		
    					== dwc3_gadget_conndone_interrupt();			dbg_event(0xFF, "CONNECT DONE", speed);
    
    
    • 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

    其中,对端点的处理中断:
    \drivers\usb\dwc3\ep0.c

    static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
    			const struct dwc3_event_depevt *event)
    {
    	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
    
    	switch (dwc->ep0state) {		//判断ep0 的state
    	case EP0_SETUP_PHASE:
    		dwc3_ep0_inspect_setup(dwc, event);
    		break;
    
    	case EP0_DATA_PHASE:
    		dwc3_ep0_complete_data(dwc, event);
    		break;
    
    	case EP0_STATUS_PHASE:
    		dwc3_ep0_complete_status(dwc, event);
    		break;
    	default:
    		WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    setup 阶段,会响应 host 的各种 req:

    == configfs_composite_setup();	
    	== composite_setup();		//setup 包括获取描述符,配置,地址等操作
    		== set_config();		//ctrl->bRequest = USB_REQ_SET_CONFIGURATION
    /*
     * Standard requests, for the bRequest field of a SETUP packet.
     *
     * These are qualified by the bRequestType field, so that for example
     * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
     * by a GET_STATUS request.
     */
    #define USB_REQ_GET_STATUS		0x00
    #define USB_REQ_CLEAR_FEATURE		0x01
    #define USB_REQ_SET_FEATURE		0x03
    #define USB_REQ_SET_ADDRESS		0x05
    #define USB_REQ_GET_DESCRIPTOR		0x06
    #define USB_REQ_SET_DESCRIPTOR		0x07
    #define USB_REQ_GET_CONFIGURATION	0x08
    #define USB_REQ_SET_CONFIGURATION	0x09
    #define USB_REQ_GET_INTERFACE		0x0A
    #define USB_REQ_SET_INTERFACE		0x0B
    #define USB_REQ_SYNCH_FRAME		0x0C
    #define USB_REQ_SET_SEL			0x30
    #define USB_REQ_SET_ISOCH_DELAY		0x31
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    #【软件STM32cubeIDE下F103配置uart3+uart1+DMA收发+简单数据解析-基础样例-进阶】
    FTX:这个加密货币冬天与以前的冬天非常相似
    9 种方法使用 Amazon CodeWhisperer 快速构建应用
    pgbench 性能测试工具的使用
    阿里P8大佬内部亲授Redis笔记,深入挖掘其原理
    小米6/6X/米8/米9手机刷入鸿蒙HarmonyOS.4.0系统-刷机包下载-遥遥领先
    devServer.proxy 实现分环境部署???
    2022国赛D题气象报文信息卫星通信传输参考代码及思路
    Redis Key-Value数据库 【实战】
    关于Ubuntu18.04安装后没有gcc、make、网卡驱动的问题总结以及解决办法
  • 原文地址:https://blog.csdn.net/weixin_42129680/article/details/125430364