一,概述
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 结构体