一,概述
usb主机控制器驱动一般以platform的形式将驱动注册进内核,,因此我们需要从前面一篇文章的框图说起。主要分析下图中橙色部分的内容。
二,usb主机控制器相关函数
2.1 usb_create_hcd
我们来看一下usb_create_hcd函数,该函数定义在drivers/usb/core/hcd.c:
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, // 参数1为ohci_s3c2410_hc_driver,参数2为s3c_device_ohci ->dev,参数3位s3c24xx
struct device *dev, const char *bus_name)
{
return __usb_create_hcd(driver, dev, dev, bus_name, NULL);
}
这里调用了__usb_create_hcd函数:
struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
struct device *sysdev, struct device *dev, const char *bus_name,
struct usb_hcd *primary_hcd)
{
struct usb_hcd *hcd;
hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); // 动态申请内存空间,额外申请hcd私有数据大小的内存
timer_setup(&hcd->rh_timer, rh_timer_func, 0); // 初始化定时器,设置定时器超时函数
hcd->driver = driver; // 绑定hc_driver
return hcd;
}
总结一下函数执行流程:
首先分配一个hcd的内存空间,包含私有数据空间;
设置hcd->rh_timer设置定时器超时函数rh_timer_func,主机控制器以轮询的方式查找端口变化状态;
设置 hcd->driver = &_hc_driver等 ;
hc_driver是usb主机控制器的驱动函数,实现了通过主机控制器硬件向外通信的方法。
2.2 rh_timer_func
定时器回调函数定义在drivers/usb/core/hcd.c文件中:
/* timer callback */
static void rh_timer_func (struct timer_list *t)
{
struct usb_hcd *_hcd = from_timer(_hcd, t, rh_timer);
usb_hcd_poll_rh_status(_hcd);
}
2.3 usc_add_hcd
用usb_hcd结构体定义好usb_hdc设备后,用usb_add_hcd函数向linux内核注册usb主机控制器驱动,函数定义在drivers/usb/core/hcd.c:
int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
int retval;
struct usb_device *rhdev;
retval = usb_phy_roothub_set_mode(hcd->phy_roothub,
PHY_MODE_USB_HOST);
retval = usb_register_bus(&hcd->self);
if (retval < 0)
goto err_register_bus;
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
if (rhdev == NULL) {
dev_err(hcd->self.sysdev, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
mutex_lock(&usb_port_peer_mutex);
hcd->self.root_hub = rhdev;
mutex_unlock(&usb_port_peer_mutex);
/* initialize tasklets */
init_giveback_urb_bh(&hcd->high_prio_bh);
init_giveback_urb_bh(&hcd->low_prio_bh);
/* starting here, usbcore will pay attention to this root hub */
retval = register_root_hub(hcd);
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
usb_hcd_poll_rh_status(hcd); // 定时器轮询root hub端口状态
return retval;
}
该函数代码比较长,这里挑重点说:
usb_register_bus(&hcd->self) ,将 hcd->usb_bus 注册到全局链表usb_bus_list;
usb_alloc_dev为根hub分配一个usb_device 结构(内核中,所有的真实的usb设备;比如hub,鼠标等都用usb_device结构来描述);
register_root_hub注册根hub设备到usb_bus_type;
usb_hcd_poll_rh_status定时器函数轮询hub端口状态;
usb主机控制器也只不过是分配了一个usb_hcd结构体,为它的根hub分配了一个usb_device 结构体,注册到usb_bus_type罢了,后边是根hub的注册和设备枚举过程了。
2.4 usb_alloc_dev
usb_alloc_dev函数定义在drivers/usb/core/hcd.c:
struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.groups = usb_device_groups;
dev->state = USB_STATE_ATTACHED;
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
usb_enable_endpoint(dev, &dev->ep0, false);
dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
* string is a path along hub ports, from the root. Each device's
* dev->devpath will be stable until USB is re-cabled, and hubs
* are often labeled with these port numbers. The name isn't
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
if (unlikely(!parent)) {
dev->devpath[0] = '0';
dev->route = 0;
dev->dev.parent = bus->controller;
device_set_of_node_from_dev(&dev->dev, bus->sysdev);
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
}
return dev;
}
该函数主要做了以下事情:
这里实际上就是为根hub,动态分配一个usb_device;
初始化设备基类dev->dev:
dev->dev.bus = &usb_bus_type,设置总线类型
dev->dev.type = &usb_device_type,设置设备类型,用于和usb接口区分;
等等;
初始化dev其它成员;
dev->state = USB_STATE_ATTACHED,设备状态设置位已连接;
usb_enable_endpoint函数使能usb端点0,用于usb通信,usb主机控制器会通过该端点和root hub通信获取设备/配置描述信息;一个 usb 设备有多个配置,每个配置又有多个接口,每个接口有多个端点。但是端点0比较特殊,它是整个usb设备共享的,端点0是直接存储在usb_device->ep0字段中。
等等;
2.5 register_root_hub
register_root_hub函数定义在drivers/usb/core/hcd.c,顾名思义,就是注册root_hub设备,先是对自身初始化,然后获取设备描述符,最后把自己当普通usb设备给注册了。
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
struct usb_device *usb_dev = hcd->self.root_hub; // 根hub设备
const int devnum = 1;
int retval;
usb_dev->devnum = devnum; //根hub设备地址为1
usb_dev->bus->devnum_next = devnum + 1;
set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_set_device_state(usb_dev, USB_STATE_ADDRESS); // 变更状态
mutex_lock(&usb_bus_idr_lock);
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); // 获取设备描述符
retval = usb_new_device (usb_dev);
if (retval) {
dev_err (parent_dev, "can't register root hub for %s, %d\n",
dev_name(&usb_dev->dev), retval);
} else {
spin_lock_irq (&hcd_root_hub_lock);
hcd->rh_registered = 1;
spin_unlock_irq (&hcd_root_hub_lock);
/* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
}
mutex_unlock(&usb_bus_idr_lock);
return retval;
}
这里我们先介绍usb_get_device_descriptor函数,该函数用于获取根hub设备的描述符;
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
{
struct usb_device_descriptor *desc;
desc = kmalloc(sizeof(*desc), GFP_NOIO);
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); // 获取usb设备描述符,request = 0x06,requestType = 0x80、value = 0x100
return ret;
}
2.6 usb_new_device
接下来我们再来看看usb_new_device。
int usb_new_device(struct usb_device *udev)
{
err = usb_enumerate_device(udev); /* Read descriptors */
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* Tell the world! */
announce_device(udev);
if (udev->serial)
add_device_randomness(udev->serial, strlen(udev->serial));
if (udev->product)
add_device_randomness(udev->product, strlen(udev->product));
if (udev->manufacturer)
add_device_randomness(udev->manufacturer,
strlen(udev->manufacturer));
err = device_add(&udev->dev);
return err;
}
usb_new_device函数用于注册usb根hub设备,先是枚举调用usb_enumerate_device获取设备配置描述符信息(这里枚举获取的pid、vid等用于设备驱动匹配的id使用):
static int usb_enumerate_device(struct usb_device *udev)
{
int err;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (udev->config == NULL) {
err = usb_get_configuration(udev); // 获取配置描述符,这里根据设备描述符dev->descriptor.bNumConfiguratios中配置数量,来一一发送USC_DT_CONFIG(value=0x200)命令获取配置描述符,初始化dev->config[num]成员
}
/* read the standard strings and cache them if present */
udev->product = usb_cache_string(udev, udev->descriptor.iProduct); // 从设备描述符获取产品名信息
udev->manufacturer = usb_cache_string(udev, // 从设备描述符获取厂商信息
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); // 从设备描述符获取产品串号信息
err = usb_enumerate_device_otg(udev);
return 0;
}
usb_get_configuration,大致步骤也是调用usb_control_msg函数通过usb主机控制器向root hub发送控制报文,获取配置描述符信息。
然后调用device_add将设备加入到设备链表中,在执行device_add后,将执行总线的匹配函数usb_device_match:
device_add
bus_probe_devic
device_attach
bus_for_each_drv
__device_attach
driver_match_device
drv->bus->match(dev, drv)
usb_device_match
注册根hub设备后,由于在usb子系统初始化函数中注册了usb通用设备驱动usb_generic_driver,这样就会执行usb_generic_driver的probe函数,即generic_probe。这里就和前面一幅图的流程一样了。
2.7 usb_hcd_poll_rh_status
/*
* Root Hub interrupt transfers are polled using a timer if the
* driver requests it; otherwise the driver is responsible for
* calling usb_hcd_poll_rh_status() when an event occurs.
*
* Completions are called in_interrupt(), but they may or may not
* be in_irq().
*/
void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
{
struct urb *urb;
length = hcd->driver->hub_status_data(hcd, buffer);
if (length > 0) {
/* try to complete the status urb */
spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (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);
usb_hcd_giveback_urb(hcd, urb, 0);
} else {
length = 0;
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
}
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
* exceed that limit if HZ is 100. The math is more clunky than
* maybe expected, this is to make sure that all timers for USB devices
* fire at the same time to give the CPU a break in between */
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)); // 修改定时器超时时间,并重新激活定时器
}
usb_hcd_poll_rh_status 调用主机控制器的hub_status_data函数获取端口状态。如果端口的状态有变化,那么length > 0,把获取到的端口状态的数组拷贝到urb->transfer_buffer中,就是前面的hub->buffer中,同时调用usb_hcd_giveback_urb函数。
2.8 usb_hcd_giveback_urb
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
__usb_hcd_giveback_urb(urb);
return;
}
}
static void __usb_hcd_giveback_urb(struct urb *urb)
{
urb->complete(urb);
}
usb_hcd_giveback_urb函数中调用urb->complete (urb),而urb->complete = hub_irq,这样就返回到了hub中 ;
三,usb驱动的probe匹配过程
前面我们分析到调用usb_new_device来进行配置使usb设备可以正常工作,我们现在分析一下具体过程。主要是找到对应的客户驱动程序和该USB设备挂钩。
usb_new_device中调用device_add,将设备添加到设备层次结构中。
大概调用流程:device_add -> bus_probe_device -> device_initial_probe -> __device_attach -> bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
3.1 1. usb_device_match
我们分析一下就是usb_device_match,这个函数只是做一些粗略的匹配, 如果匹配成功则返回1。这个函数只是做一些粗略的匹配, 如果匹配成功则返回1, 然后由driver_probe_device来做进一步的匹配, 如果匹配失败则返回0, 并且driver_probe_device也不会在执行. 这个函数的调用保证了dev, drv 要么都是设备级别的( 即dev 代表usb 设备,drv 代表usb 设备驱动), 要么都是接口级别的( 即dev 代表usb 设备的一个interface,drv 代表usb 接口驱动).
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) {
/* interface drivers never match devices */ //是匹配USB设备的驱动,USB接口的驱动不能匹配
if (!is_usb_device_driver(drv))
return 0;
/* TODO: Add real matching code */
return 1;
} else if (is_usb_interface(dev)) { //如果是USB接口
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* device drivers never match interfaces */
//usb接口在注册driver时将for_devices设置为0,for_devices =1,表示设备驱动,for_devices = 0,表示接口驱动
if (is_usb_device_driver(drv))
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table); //匹配id table
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv); //匹配动态id table
if (id)
return 1;
}
return 0;
}
3.2 driver_probe_device
driver_probe_device主要是调用really_probe -> (drv->probe)
对于usb 来说这个函数的调用有2 种分支, 1: dev,drv 代表的是设备级别的, 2 dev,drv 代表的是接口级别的. 其他情况组合在usb_device_match 中被过滤掉了.
分支1: dev,drv 代表的是设备级别:
此时的drv 肯定是usb_generic_driver. 因为在当前的usb 系统中只有这个driver 是代表整个设备的驱动, 它是在usb_init 中被注册的, 而我们通常写的usb 驱动都是代表一个interface 的.
因此, 此时的drv->probe 将调用generic_probe().再到usb_set_configuration
int usb_set_configuration(struct usb_device *dev, int configuration)
{
for(I = 0; I < nintf; i++) {
struct usb_interface *intf = cp->interface[i];
device_add(&intf->dev); //又会进入匹配
}
该函数比较重要, 但我们只关心probe 过程因此省掉了很多东西. 它为当前配置下的每个interface 调用device_add() 函数, 根据前面的分析可知, 这个过程将会走到接下来我们要分析的分支2.
分支2: dev,drv 代表的是interface 级别:
此时的dev 代表着一个interface, 而drv 就代表了我们自己的usb 驱动. 但是我们应当看到drv是device_driver 类型, 而我们写的usb 驱动的类型一般是usb_driver, 因此这里的probe 和我们自己写的probe 显然不是同一个. 实际上这里的drv 是我们的驱动对象里内嵌的一个子对象( 因为linux 下所以的驱动都必须用device_driver 来代表,). 那这个子对象的probe 函数是在哪里赋值的呢?
这就要看usb_register宏了,实际里面是调用usb_register_driver
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)
{
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface; //这里是probe函数
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
new_driver->drvwrap.driver.dev_groups = new_driver->dev_groups;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver);
if (retval)
goto out;
retval = usb_create_newid_files(new_driver);
if (retval)
goto out_newid;
pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name); //一般log会打印这个
}
跟踪这个函数我们可以看到这里的probe 函数实际上是usb_probe_interface( 所有的usb interface 驱动都是一样的).
static int usb_probe_interface(struct device *dev)
{
struct driver = to_usb_driver(dev->driver); //dev->driver 在really_probe 中设置.
error = driver->probe(intf, id); // 这个就是我们自己写的probe 函数了.
}
driver->probe(intf, id); 这就调用到我们自己写的代码里面了,
3.3 流程图
大概流程图是一样的: