Linux boot 时 USB 的初始化过程分析2

现状 OK6410A  linux-5.11
1个 roothub 上面接了2个 port , 无接其他设备
具体过程:

===========================
初始化第1.1阶段
ohci_hcd_s3c2410_probe
	s3c_usb_phy_init // 初始化 PHY
    s3c2410_start_hc // 必须处理好 power 和 clock 的问题,并设置正确,才可以开始usb_add_hcd
    	开启时钟
    调用 usb_add_hcd
		注册 usb bus
		hcd->driver->reset(hcd); // ohci_setup
			// 读写ohci 寄存器 , virt base address : d08ce000
		注册 中断
		hcd->driver->start(hcd); // ohci_start
			// 读写ohci 寄存器 
		获取设备描述符
		获取配置描述符
		选择配置
		get_hub_descriptor
		hub_activate.1
			hub_power_on
			延时调用 第二阶段

===========================
初始化第1.2阶段
	hub_init_func2
		hub_activate.2
			走init2和init3
			kick_hub_wq->queue_work(hub_wq, &hub->events)
===========================
初始化第二阶段
	hub_event
		枚举 roothub 上的 所有port 上的设备(包括hub)
	
	hub_suspend
	
===========================
初始化完成




===========================
运行时流程
host 定时问 hub 有没有中断?还是有没有port 改变(插入,拔出)事件(有的话调用hub_irq)
	usb_hcd_irq
		hcd->driver->irq  // ohci_irq
			...
				urb->complete(urb) // 即 hub_irq / usb_mouse_irq / hid_irq_in 
hub_irq
	kick_hub_wq(hub);

hub_event
	根据 changebit 对 hub 上的 改变事件对应的设备 进行枚举


usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags)
	usb_register_bus(&hcd->self);
		s3c2410-ohci: new USB bus registered, assigned bus number 1
	hcd->driver->reset(hcd);
		s3c2410-ohci: created debug files
	usb_hcd_request_irqs(hcd, irqnum, irqflags);
		s3c2410-ohci: irq 79, io mem 0x74300000
	hcd->driver->start(hcd)
	register_root_hub(hcd);
		usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
		usb_get_device_descriptor
		usb_new_device // only called by register_root_hub & hub_port_connect // 这个并不是new device ,而是 new device 的封装
			usb_enumerate_device
				usb_get_configuration
					usb_get_descriptor
				udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
					[1] usb_get_langid:939: usb usb1: default language 0x0409
				
			[1] usb_new_device:2554: usb usb1: udev 1, busnum 1, minor = 0
			device_add(&udev->dev);  // 注册 USB设备device
			|		[1] usb_probe_device:255: usb usb1: usb_probe_device
			|
			|
			usb_generic_driver_probe //      USB设备driver
				usb_choose_configuration
					[1] usb_choose_configuration:187: usb usb1: configuration #1 chosen from 1 choice
				usb_set_configuration
					[1] usb_set_configuration:2181: usb usb1: adding 1-0:1.0 (config #1, interface 0)

					device_add(&intf->dev); // 注册 USB接口device // 为hub接口
					|
					|	   [1] usb_probe_interface:327: hub 1-0:1.0: usb_probe_interface
					|	   [1] usb_probe_interface:349: hub 1-0:1.0: usb_probe_interface - got id
					hub_probe				// 		USB接口driver
						hub 1-0:1.0: USB hub found
						hub_configure
							get_hub_descriptor(hdev, hub->descriptor);
								[1] ohci_s3c2410_hub_control:194: s3c2410-ohci s3c2410-ohci: s3c2410_hub_control((ptrval),0xa006,0x2900,0x0000,(ptrval),000f)
							
							hub 1-0:1.0: 2 ports detected
							[1] hub_configure:1474: hub 1-0:1.0: standalone hub
							[1] hub_configure:1486: hub 1-0:1.0: no power switching (usb 1.0)
							[1] hub_configure:1495: hub 1-0:1.0: individual port over-current protection
							[1] hub_configure:1570: hub 1-0:1.0: power on to power good time: 4ms
							
							hub_hub_status(hub, &hubstatus, &hubchange);
								[1] ohci_s3c2410_hub_control:194: s3c2410-ohci s3c2410-ohci: s3c2410_hub_control((ptrval),0xa000,0x0000,0x0000,(ptrval),0004)
							
							[1] hub_configure:1628: hub 1-0:1.0: local power source is good

							usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);
								urb->complete = hub_irq;
						 	
						 	hub_activate.1(hub, HUB_INIT);
						 		走 type == HUB_INIT
							 		hub_power_on
							 			[1] hub_power_on:914: hub 1-0:1.0: trying to enable port power on non-switchable hub
							 			set_port_feature
							 			[1] ohci_s3c2410_hub_control:194: s3c2410-ohci s3c2410-ohci: s3c2410_hub_control((ptrval),0x2303,0x0008,0x0001,(ptrval),0000)
							 			[1] ohci_s3c2410_hub_control:194: s3c2410-ohci s3c2410-ohci: s3c2410_hub_control((ptrval),0x2303,0x0008,0x0002,(ptrval),0000)
								
									//此时 hub 还没初始化完,接着让另一段来处理
							 		INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
							 		queue_delayed_work(system_power_efficient_wq, &hub->init_work, msecs_to_jiffies(delay));
							 		return;


hub_init_func2
	hub_activate.2
		走init2和init3
		usb_control_msg

		// 此时hub初始化完成,接着让 hub_event 来 干活
		kick_hub_wq->queue_work(hub_wq, &hub->events)


hub_event
	port_event
		hub_port_connect_change
			hub_port_connect
				usb_new_device
					device_add(&udev->dev);
				usb_disconnect
					device_del(&udev->dev);
	

hub_suspend
	hub_event 的连锁反应





枚举过程的 control 信息的收发
	usb_control_msg
		有时候会调用 ohci_s3c2410_hub_control
		有时候不调用 ohci_s3c2410_hub_control



USB 设备的初始化都是 Hub 这边发起的
只要你有 USB 主机控制器,就一定会有 Root Hub,

对于 Hub 来说,当你插入一个设备到 Hub 口里,就会触发一件事件。而第一件事件的发生其实是 Hub 驱动程序本身的初始化




hub的中断
	hub_irq

hub的IN中断传输
	usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);
	这是hub准备的一个 int传输包,用于一次IN传输,让HOST定时访问hub



为什么 hub_probe之后要 kick event
	因为要 hub 干活(枚举hub 所有port 上的设备)
	
	hub_probe 设置了 该 hub的驱动 , 但是 该 hub 上可能接了设备,所以要处理一下


	表现形式为 最后发了一个 消息




hub_event
	port_event
		hub_port_connect_change
			hub_port_connect
				usb_new_device
					device_add(&udev->dev);
				usb_disconnect
					device_del(&udev->dev);



凡是真正的有端口变化事件发生,hub_irq 就会被调用,而 hub_irq()
最终会调用 kick_khubd(),触发 Hub 的 event_list,于是再次调用 hub_events()函数




我们曾经在 hub_configure 中讲过中断传输,当时调用了 usb_fill_int_urb()函数,并且把
hub_irq 作为一个参数传递了进去,最终把 urb->complete 赋值为 hub_irq。

然后,主机控制器会 定期询问 Hub,每当 Hub 端口上有一个设备插入或者拔除时,它就会向主机控制器打小报告。

具体来说,从硬件的角度看,就是 Hub 会向主机控制器返回一些信息,或者说 Data,这个 Data 被称作“Hub and Port Status Change Bitmap”,
而从软件角度来看,主机控制器的驱动程序接下 来会在处理好这个过程的 urb 之后,调用该 urb 的 complete 函数,
对于 Hub 来说,这个函数就 是 hub_irq()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值