赞
踩
写在前面,最近在做Intel 的usb gadget驱动的处理,想着重新梳理一遍usb host驱动,用的是非公司的版本,所以本次就梳理一下流程,大体流程基本一致。
1:usb_init:(/driver/usb/core/usb.c)
usb驱动框架的入口函数,简单些,注册usb的子系统,注册一个总线bus_register:bus_type:usb_bus_type,主要接口流程调用usb_hub_init()用来创建hub初始化,注册一个基于usb的urb的usb_driver结构体,usb_driver的open函数hub_probe:
1.1:注册usb总线,创建usb的文件夹属性,通过platform 的id匹配driver和device,此次匹配的一般是usb的interface的驱动,而是usb的设备驱动,里面实际匹配的是interface的id(vendor,product,class)。
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
};
usb_major_init();注册usb的子设备:包含主设备号,从设备号。
usb_hub_init(); usb_hub的初始化,(对于usb流程比较重要),详细分析流程:
https://blog.csdn.net/zuodenghuakai/article/details/83956040?spm=1001.2014.3001.5502
host和hub是不同的东西,hub是一种特殊的usb 的driver设备,它是以usb_driver去做特性适配,从这就可以看出来它是一种特殊功能的usb设备,hc是usb设备的控制器,包含host的寄存器的配置,包括端点的寄存器的配置功能,一般控制器会自带一个HUB,称为root hub(可以根据不同的片子,扩展的usb接口能力也不一样)root hub和hc控制器(可以包括2.0,3.0等不同的接口)是一一对应绑定的,其下可以扩展usb hub。
3.1:简单分析一下xhci驱动
1:module_init(xhci_hcd_init);(添加xhci的初始化信息)(xhci.c函数接口)
retval = xhci_register_pci(); 注册pci的pci接口,主要用来配置寄存器。
retval = xhci_register_plat();注册平台驱动
此次分析的为intel的xhci的驱动器(xhic_pci.c),根据id_table去匹配pci的设备信息,调用pci_driver的probe函数(xhci_pci_probe)。
1.1:下面列出两个基本的结构体xhci_pci_driver、xhci_pci_hc_driver(用来操作hcd的驱动的钩子函数)(所以所驱动结构都比较简单,就是把不同的结构体串联起来)。
static struct pci_driver xhci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
.probe = xhci_pci_probe,
.remove = xhci_pci_remove,
/* suspend and resume implemented later */
};
static const struct hc_driver xhci_pci_hc_driver = { //主要对hcd的操作接口在该函数接口中实现,关于hc的寄存器的配置,在初始化的时候调用该接口函数,包含在usb_submit_urb 函数调用时,最终的寄存器的配置接口就此事从这里来的
.description = hcd_name,
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd *),
/*
* generic hardware linkage
*/
.irq = xhci_irq,
.flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
/*
* basic lifecycle operations
*/
.reset = xhci_pci_setup,
.start = xhci_run,
.stop = xhci_stop,
.shutdown = xhci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = xhci_urb_enqueue, //在提交urb的时候先去分配urb_queue
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.alloc_streams = xhci_alloc_streams,
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.update_hub_device = xhci_update_hub_device,
.reset_device = xhci_discover_or_reset_device,
.get_frame_number = xhci_get_frame,
/* Root hub support */
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
/*
* call back when device connected and addressed
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
};
1.2:xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) xhci的probe函数,probe的主要功能是在不同状态下调用usb_add_hcd函数接口。
retval = usb_hcd_pci_probe(dev, id);//创建ucd,创建地址映射。
xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,pci_name(dev), hcd)主要是注册了 定时器的 hcd->rh_timer.function = rh_timer_func;,这个轮询定时器比较重要,关系到usb插入后,如何通知给hub,最终调用函数usb_hcd_poll_rh_status会一直使用定时器调用自己,如果读取到hub有变化,而且有提交的urb,就返回。,
hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev))创建和填充hcd结构体
usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);添加hcd(函数比较重要,拎出来)。
1.2.1:usb_add_hcd (把里面的重要函数功能放出来,这里把大多数分支流程都删除)
int usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags){
int retval;
struct usb_device *rhdev;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
if ((retval = hcd_buffer_create(hcd)) != 0) {
dev_dbg(hcd->self.controller, "pool alloc failed\n");
return retval;
}
if ((retval = usb_register_bus(&hcd->self)) < 0)
goto err_register_bus;
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
dev_err(hcd->self.controller, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
hcd->self.root_hub = rhdev; //root hub的dev信息是从hcd中读取出来, struct usb_device ,用来分析usb_device结构体的填充过程
switch (hcd->speed) {
case HCD_USB11:
rhdev->speed = USB_SPEED_FULL;
break;
case HCD_USB2:
rhdev->speed = USB_SPEED_HIGH;
break;
case HCD_USB3:
rhdev->speed = USB_SPEED_SUPER;
break;
default:
retval = -EINVAL;
goto err_set_rh_speed;
}
/* wakeup flag init defaults to "everything works" for root hubs,
* but drivers can override it in reset() if needed, along with
* recording the overall controller's system wakeup capability.
*/
device_set_wakeup_capable(&rhdev->dev, 1);
set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
dev_err(hcd->self.controller, "can't setup\n");
goto err_hcd_driver_setup;
}
hcd->rh_pollable = 1;
/* NOTE: root hub and controller capabilities may not be the same */
if (device_can_wakeup(hcd->self.controller)
&& device_can_wakeup(&hcd->self.root_hub->dev))
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
if (usb_hcd_is_primary_hcd(hcd) && irqnum) {
//xHCI规范说我们可以得到一个中断,如果HC在某种情况出现了错误,我们可能会从事件环中获取坏数据。这个中断不是用来探测插入了设备的。申请中断,中断处理函数usb_hcd_irq,实际调用xhci_irq
retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
if (retval)
goto err_request_irq;
}
hcd->state = HC_STATE_RUNNING;
retval = hcd->driver->start(hcd);
if (retval < 0) {
dev_err(hcd->self.controller, "startup error %d\n", retval);
goto err_hcd_driver_start;
}
/* starting here, usbcore will pay attention to this root hub */
if ((retval = register_root_hub(hcd)) != 0)//注册一个root hub
goto err_register_root_hub;
retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
if (retval < 0) {
printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
retval);
goto error_create_attr_group;
}
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
//如果驱动请求roothub中断传输,会用一个定时器轮询;否则由驱动在事件发生时调用
usb_hcd_poll_rh_status(hcd);
/*
* Host controllers don't generate their own wakeup requests;
* they only forward requests from the root hub. Therefore
* controllers should always be enabled for remote wakeup.
*/
device_wakeup_enable(hcd->self.controller);
return retval;
}
1.2.2:usb_hcd_poll_rh_status(hcd);
该函数在大名鼎鼎的函数接口usb_submit_urb 中也会重启启动
void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
{
struct urb *urb;
int length;
unsigned long flags;
char buffer[6]; /* Any root hubs with > 31 ports? */
length = hcd->driver->hub_status_data(hcd, buffer); //通过hcd得到设备驱动的状态
if (length > 0) {
spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (urb) {//如果已经提交了获取状态的urb, 将状态值拷贝进入urb。
clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
hcd->status_urb = NULL;
urb->actual_length = length;
memcpy(urb->transfer_buffer, buffer, length);
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, 0);
spin_lock(&hcd_root_hub_lock);
} else {//若此时没有已经提交的urb,则设置poll_pending标志
length = 0;
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
}
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
(length == 0 && hcd->status_urb != NULL))
mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); //开启轮询定时器
} }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。