USB学习之一 代码分析和学习心得之初始化流程以及读写流程

usb_init //USB的第一个初始化入口
	=>bus_register(&usb_bus_type);//设备驱动模型,总线注册
		struct bus_type usb_bus_type = {
			.name =		"usb",
			.match =	usb_device_match,
			.uevent =	usb_uevent,
		};
		usb_device_match 有两个用途,一个是USB设备的match,触发设备的probe,一个是USB intf的match,触发intf的probe
			=>if (is_usb_device(dev))
				return 1;//如果是device, 那么触发device的probe函数,也就是usb_probe_device
			=>if (is_usb_interface(dev))//匹配后,触发intf的probe函数
				intf = to_usb_interface(dev);
				usb_drv = to_usb_driver(drv);
				id = usb_match_id(intf, usb_drv->id_table);
				if (id)
					return 1;
				id = usb_match_dynamic_id(intf, usb_drv);
				if (id)
					return 1;
			
	=>usb_hub_init();
		=>usb_register(&hub_driver)//注册usb hub intf驱动
			static struct usb_driver hub_driver = {
				.name =		"hub",
				.probe =	hub_probe,
				.disconnect =	hub_disconnect,
				.suspend =	hub_suspend,
				.resume =	hub_resume,
				.reset_resume =	hub_reset_resume,
				.pre_reset =	hub_pre_reset,
				.post_reset =	hub_post_reset,
				.unlocked_ioctl = hub_ioctl,
				.id_table =	hub_id_table,
				.supports_autosuspend =	1,
			};
			static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
		=>kthread_run(hub_thread, NULL, "khubd");
			=>hub_thread
				=>do while里面调用hub_events();//循环探测usb hub的插入消息
					=>hub_port_connect_change(hub, i, portstatus, portchange);//探测到有新的usb device插入
						=>usb_alloc_dev(hdev, hdev->bus, port1);
						=>hub_port_init(hub, udev, port1, i);//很重要,里面获取设备描述符
							=>hub_port_reset(hub, port1, udev, delay);
								=>set_port_feature(hub->hdev, port1, USB_PORT_FEAT_RESET);
						=>usb_detect_quirks(udev);
						=>usb_new_device(udev);//USB device注册会触发usb device driver usb_probe_device
	=>usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
		struct usb_device_driver usb_generic_driver = {
			.name =	"usb",
			.probe = generic_probe,
			.disconnect = generic_disconnect,
		#ifdef	CONFIG_PM
			.suspend = generic_suspend,
			.resume = generic_resume,
		#endif
			.supports_autosuspend = 1,
		};
		=>new_udriver->drvwrap.for_devices = 1;
		new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
		new_udriver->drvwrap.driver.bus = &usb_bus_type;
		new_udriver->drvwrap.driver.probe = usb_probe_device;
		new_udriver->drvwrap.driver.remove = usb_unbind_device;
		new_udriver->drvwrap.driver.owner = owner;
		=> driver_register(&new_udriver->drvwrap.driver);//注册linux device driver
		
当USB HUB探测到有新的USB device插入后,走usb_device_match函数,触发usb_probe_device
usb_probe_device
	=>udriver->probe(udev);
		=>generic_probe
			=>usb_choose_configuration(udev);
			=>usb_set_configuration(udev, c);
				=>new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_NOIO);
				=>intf->dev.parent = &dev->dev;
				intf->dev.driver = NULL;
				intf->dev.bus = &usb_bus_type;
				intf->dev.type = &usb_if_device_type;
				intf->dev.groups = usb_interface_groups;
				device_initialize(&intf->dev);
				=>device_add(&intf->dev); //注册usb intf,根据USB 设备驱动模型,将来与usb intf驱动match触发intf的probe函数

假设USB EHCI控制器挂在PCI桥片下
ehci_hcd_init	//控制器的初始化函数
	=>pci_register_driver(&PCI_DRIVER);
		#define	PCI_DRIVER		ehci_pci_driver

		static struct pci_driver ehci_pci_driver = {
			.name =		(char *) hcd_name,
			.id_table =	pci_ids,
		
			.probe =	usb_hcd_pci_probe,
			.remove =	usb_hcd_pci_remove,
			.shutdown = 	usb_hcd_pci_shutdown,
		};
		static const struct pci_device_id pci_ids [] = { {
			/* handle any USB 2.0 EHCI controller */
			PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),
			.driver_data =	(unsigned long) &ehci_pci_hc_driver,
			},
			{ /* end: all zeroes */ }
		};
		
		static const struct hc_driver ehci_pci_hc_driver = {
			.description =		hcd_name,
			.product_desc =		"EHCI Host Controller",
			.hcd_priv_size =	sizeof(struct ehci_hcd),
		
			/*
			 * generic hardware linkage
			 */
			.irq =			ehci_irq,
			.flags =		HCD_MEMORY | HCD_USB2,
		
			/*
			 * basic lifecycle operations
			 */
			.reset =		ehci_pci_setup,
			.start =		ehci_run,
		#ifdef	CONFIG_PM
			.pci_suspend =		ehci_pci_suspend,
			.pci_resume =		ehci_pci_resume,
		#endif
			.stop =			ehci_stop,
			.shutdown =		ehci_shutdown,
		
			/*
			 * managing i/o requests and associated device resources
			 */
			.urb_enqueue =		ehci_urb_enqueue,
			.urb_dequeue =		ehci_urb_dequeue,
			.endpoint_disable =	ehci_endpoint_disable,
			.endpoint_reset =	ehci_endpoint_reset,
		
			/*
			 * scheduling support
			 */
			.get_frame_number =	ehci_get_frame,
		
			/*
			 * root hub support
			 */
			.hub_status_data =	ehci_hub_status_data,
			.hub_control =		ehci_hub_control,
			.bus_suspend =		ehci_bus_suspend,
			.bus_resume =		ehci_bus_resume,
			.relinquish_port =	ehci_relinquish_port,
			.port_handed_over =	ehci_port_handed_over,
		
			/*
			 * call back when device connected and addressed
			 */
			.update_device =	ehci_update_device,
		
			.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
		};

usb_hcd_pci_probe
	=>driver = (struct hc_driver *)id->driver_data;
	=>pci_enable_device(dev)
		=>__pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
			=>do_pci_enable_device(dev, bars);
				=>pcibios_enable_device(dev, bars);
					=>pci_enable_resources(dev, mask);
						=>if (r->flags & IORESOURCE_IO)//写commnd寄存器使能io和Mem空间
							cmd |= PCI_COMMAND_IO;
						if (r->flags & IORESOURCE_MEM)
							cmd |= PCI_COMMAND_MEMORY;
						pci_write_config_word(dev, PCI_COMMAND, cmd);
	=>usb_create_hcd(driver, &dev->dev, pci_name(dev));
		=>usb_create_shared_hcd(driver, dev, bus_name, NULL);
			=>hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);//分配hcd控制器空间
			=>usb_bus_init(&hcd->self);//创建hcd总线并初始化
			hcd->self.controller = dev;
			hcd->self.bus_name = bus_name;
			hcd->self.uses_dma = (dev->dma_mask != NULL);
			=>init_timer(&hcd->rh_timer);//创建timer
			hcd->rh_timer.function = rh_timer_func;
			hcd->rh_timer.data = (unsigned long) hcd;
	=>hcd->rsrc_start = pci_resource_start(dev, 0);//通过pci设备获取基地址大小
	hcd->rsrc_len = pci_resource_len(dev, 0);
	request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)	
	=>hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);//对寄存器空间进行虚实地址映射
	=>pci_set_master(dev);//可以做主
	=>usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);	
		=>hcd_buffer_create(hcd)//申请缓冲池
		=>usb_register_bus(&hcd->self)//总线控制器注册
		=>rhdev = usb_alloc_dev(NULL, &hcd->self, 0)//申请分配root hub
		hcd->self.root_hub = rhdev;
		=>hcd->driver->reset(hcd)
			=>ehci_pci_setup//根据不同的厂商做一些寄存器的设置
		=>usb_hcd_request_irqs(hcd, irqnum, irqflags);
		=>hcd->state = HC_STATE_RUNNING;
		retval = hcd->driver->start(hcd);
			=>ehci_run
				=>ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);//设置同步链表
				ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);//设置异步链表
				=>ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);//使能控制器
				ehci->command |= CMD_RUN;
				ehci_writel(ehci, ehci->command, &ehci->regs->command);
				=>ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
		=>register_root_hub(hcd)//注册root hub
			=>usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
			=>usb_new_device (usb_dev);//注册root hub device

usb_stor_init//usb storage intf 驱动初始化
	=>usb_stor_init//usb storage intf 驱动注册
		static struct usb_driver usb_storage_driver = {
		.name =		"usb-storage",
		.probe =	storage_probe,
		.disconnect =	usb_stor_disconnect,
		.suspend =	usb_stor_suspend,
		.resume =	usb_stor_resume,
		.reset_resume =	usb_stor_reset_resume,
		.pre_reset =	usb_stor_pre_reset,
		.post_reset =	usb_stor_post_reset,
		.id_table =	usb_storage_usb_ids,
		.supports_autosuspend = 1,
		.soft_unbind =	1,
	};
		=>usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
			=>new_driver->drvwrap.for_devices = 0;
			new_driver->drvwrap.driver.name = (char *) new_driver->name;
			new_driver->drvwrap.driver.bus = &usb_bus_type;
			new_driver->drvwrap.driver.probe = usb_probe_interface;
			new_driver->drvwrap.driver.remove = usb_unbind_interface;
			new_driver->drvwrap.driver.owner = owner;
			new_driver->drvwrap.driver.mod_name = mod_name;	
			=>retval = driver_register(&new_driver->drvwrap.driver);

usb_probe_interface
	=>driver->probe(intf, id);
		=>storage_probe
			=>usb_stor_probe1
				=>scsi_host_alloc(&usb_stor_host_template, sizeof(*us));//分配scsi host控制器
				=>associate_dev(us, intf);
				=>get_transport(us);
				=>get_protocol(us);
	=>usb_stor_probe2(us);
		=>get_pipes(us);
		=>usb_stor_acquire_resources(us);
			=>us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
			=>th = kthread_run(usb_stor_control_thread, us, "usb-storage");
			=>us->ctl_thread = th;
		=>scsi_add_host(us_to_host(us), dev);//注册scsi host控制器	
		=>th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
		=>wake_up_process(th);	
			=>scsi_scan_host(us_to_host(us));

usb_stor_control_thread//for 死循环,用于接受上层scsi发出的命令,该线程会在有命令的时候,调用proto_hander方法,从而调用transport,向usb core发送命令,详见  usb Mass Strorage分析(1)  http://blog.csdn.net/sharecode/article/details/9166077
	=>wait_for_completion_interruptible(&us->cmnd_ready)//被唤醒的地方的地方详见下文
	=>us->proto_handler(us->srb, us);
		=>usb_stor_transparent_scsi_command
			=>usb_stor_invoke_transport(srb, us);
				=>result = us->transport(srb, us);
					=>usb_stor_Bulk_transport//3次创建qtd,分别是CBW,DATA和CSW
						=>usb_stor_bulk_transfer_buf/* set up the command wrapper */
							=>usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
		      usb_stor_blocking_completion, NULL);
							=>usb_stor_msg_common(us, 0);
								=>usb_submit_urb(us->current_urb, GFP_NOIO);
									=>usb_hcd_submit_urb(urb, mem_flags);
										=>status = rh_urb_enqueue(hcd, urb);//如果是root hub
										=>hcd->driver->urb_enqueue(hcd, urb, mem_flags);//非root hub
											=>ehci_urb_enqueue
												=>submit_async(ehci, urb, &qtd_list, mem_flags);
													=>qh_append_tds//将qtd加到qh队列里面
													=>qh_link_async(ehci, qh);//启动ehci控制器,发送命令和数据,等待控制器返回中断
								=>wait_for_completion_interruptible_timeout(
			&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
									=>wait_for_common(x, timeout, TASK_INTERRUPTIBLE);//urb_done的done域urb->context没有设置位的话就堵塞在里面(死循环),置done位或者超时退出,由urb_hcd_irqd sg_complete置done位
							=>interpret_urb_result
						=>if (transfer_length)
							usb_stor_bulk_srb(us, pipe, srb);/* DATA STAGE */
						=>usb_stor_bulk_transfer_buf /* get CSW for device status */
				=>  Handle_Errors://异常处理分支
					result = usb_stor_port_reset(us);
						=>usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
						=>result = usb_reset_composite_device
							=>ret = usb_reset_device(udev);
								=>ep0_reinit(udev);
								=>ret = hub_port_init(parent_hub, udev, port1, i);
									=>retval = hub_port_reset(hub, port1, udev, delay);
										=>result = rc_lock = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);									
										=>status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_RESET);
										=>status = hub_port_wait_reset(hub, port1, udev, delay);
											=>ret = hub_port_status(hub, port1, &portstatus, &portchange);//获取hub端口状态
										=>usb_unlock_device(us->pusb_dev);
								=>re_enumerate://异常处理分支
									hub_port_logical_disconnect(parent_hub, port1);
										=>hub_port_disable(hub, port1, 1);
										=>set_bit(port1, hub->change_bits);
									 	=>kick_khubd(hub); ////唤醒hub_thread
					usb_stor_report_device_reset(us);
					us->transport_reset(us);
	=>us->srb->scsi_done(us->srb); //scsi_done  scsi.c
		=>__scsi_done(cmd);
		=>rq->completion_data = cmd;
		=>blk_complete_request(rq);
			=>raise_softirq_irqoff(BLOCK_SOFTIRQ);
				=>wakeup_softirqd();
					=>disposition = scsi_decide_disposition(cmd);
					=>switch (disposition) {
						case SUCCESS: //成功返回
							scsi_finish_command(cmd);
							break;
						case NEEDS_RETRY:  //异常重传
							scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
							break;
						case ADD_TO_MLQUEUE:
							scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
							break;
						default:
							if (!scsi_eh_scmd_add(cmd, 0))
								scsi_finish_command(cmd);
					}
	

USB命令下发
queuecommand
	=>queuecommand_lck
		=>srb->scsi_done
		=>us->srb = srb;
		=>complete(&us->cmnd_ready);//唤醒usb_stor_control_thread

usb_hcd_irq
	=>hcd->driver->irq(hcd)
		=>ehci_irq
			=>ehci_work (ehci);
				=>scan_async (ehci);
					=>qh_completions(ehci, qh);
						=>qtd_copy_status(ehci, urb, qtd->length, token);//从token获取错误状态
						=>ehci_urb_done(ehci, last->urb, last_status);
							=>usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
								=>urb->complete (urb);
从USB的插入开始  http://blog.csdn.net/orz415678659/article/details/8449199

关于usb hub的中断传输,其urb的传输方式可以参考 http://blog.chinaunix.net/uid-26849197-id-3608563.html
uhci应该是上述方式。

另外pci ehci控制器应该用的是中断触发方式,不是轮询方式。与轮询方式,有一个前提,hub驱动先准备一个urb候着(在软件层面),当中断触发,解析status寄存器确认有新设备插入后,进行urb传输。
hub_activate
	=>usb_submit_urb(hub->urb, GFP_NOIO);
		=>usb_hcd_submit_urb(urb, mem_flags);
			=>if (is_root_hub(urb->dev))//root hub的传输流程
				status = rh_urb_enqueue(hcd, urb);
					=>if (usb_endpoint_xfer_int(&urb->ep->desc))//中断传输
						return rh_queue_status (hcd, urb);
							=>hcd->status_urb = urb;//urb 候着
							urb->hcpriv = hcd;	/* indicate it's queued */
					if (usb_endpoint_xfer_control(&urb->ep->desc))
						return rh_call_control (hcd, urb);
			else
				status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);

当插入usb设备,会触发中断
usb_hcd_irq
	=>ehci_irq
		=>status = ehci_readl(ehci, &ehci->regs->status); //读取status寄存器
		=>if (status & STS_PCD) { /* port change detect */
			usb_hcd_poll_rh_status
				=>urb = hcd->status_urb; //使用候着的urb准备发送
				=>usb_hcd_giveback_urb
					=>urb->complete (urb);
						=>hub_irq
							=>kick_khubd(hub);
								=>wake_up(&khubd_wait);//唤醒hub_thread
usb设备插入到hub上会触发中断的缘由如下:
查看ehci控制器芯片资料的描述
when this bit is a one, and the Port Change Detect bit in the USBSTS register is a one, the host controller will issue an interrupt. The interrupt is acknowledged by software clearing the Port Change Detect bit.

Linux kernel U盘识别流程
https://blog.csdn.net/encourage2011/article/details/76407232
 
USB组合设备 Interface Association Descriptor (IAD)
https://blog.csdn.net/u013256018/article/details/61947232

你可能感兴趣的:(linux,device,driver,linux内核)