1.在board-am335xevm.c中有关于musb设备的定义
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_ULPI,
/*
* mode[0:3] = USB0PORT's mode
* mode[4:7] = USB1PORT's mode
* AM335X beta EVM has USB0 in OTG mode and USB1 in host mode.
*/
// .mode = (MUSB_HOST << 4) | MUSB_OTG,
.mode = (MUSB_HOST << 4) | MUSB_HOST,
.power = 500,
.instances = 1,
};
然后对usb设备进行初始化
usb_musb_init(&musb_board_data);
该函数填充了设备名称name = "musb-ti81xx"
并且调用了omap_device_build();
进行USB设备注册
omap_device_buitd-->omap_device_build_ss()->omap_device_register(pdev)
2.ti81xx.c中有关于musb驱动的定义
static struct platform_driver ti81xx_musb_driver = {
.remove = __exit_p(ti81xx_remove),
.driver = {
.name = "musb-ti81xx",
.pm = DEV_PM_OPS,
},
};
以及一个函数指针操作集合
static struct musb_platform_ops ti81xx_ops = {
.fifo_mode = 4,
.flags = MUSB_GLUE_EP_ADDR_FLAT_MAPPING | MUSB_GLUE_DMA_CPPI41,
.init = ti81xx_musb_init,
.exit = ti81xx_musb_exit,
.enable = ti81xx_musb_enable,
.disable = ti81xx_musb_disable,
.try_idle = ti81xx_musb_try_idle,
.set_mode = ti81xx_musb_set_mode,
.read_fifo = ti81xx_musb_read_fifo,
.write_fifo = musb_write_fifo,
.dma_controller_create = cppi41_dma_controller_create,
.dma_controller_destroy = cppi41_dma_controller_destroy,
.simulate_babble_intr = musb_simulate_babble,
#ifdef CONFIG_USB_TI_CPPI41_DMA
.txfifoempty_intr_enable = txfifoempty_intr_enable,
.txfifoempty_intr_disable = txfifoempty_intr_disable,
#endif
.reinit = musb_reinit,
.enable_sof = ti81xx_musb_enable_sof,
.disable_sof = ti81xx_musb_disable_sof
};
在ti81xx_glue_init(void)中填充probe函数到drv中
platform_driver_probe()-->drv->probe = probe-->platform_driver_register(drv)
3.ti81xx_probe()最后会调用ti81xx_create_musb_pdev()
这个函数有俩个变量较为重要
struct musb_hdrc_platform_data *pdata = dev->platform_data;
struct platform_device *musb;
后面会为musb申请内存空间,以及填充内部数据结构需要注意的是操作函数集合的填充,就是上面我们定义的那些操作函数。pdata->platform_ops= &ti81xx_ops;后面会打印dev_info(dev, "musb%d, board_mode=0x%x, plat_mode=0x%xn",id, bdata->mode, pdata->mode);就是我们在内核启动信息中看到的musb-ti81xx musb-ti81xx: musb0, board_mode=0x11, plat_mode=0x1,musb-ti81xx musb-ti81xx: musb1, board_mode=0x11, plat_mode=0x1。
最后调用 platform_device_add(musb)添加musb主控制器设备
4.在musb_core.c中会注册一个驱动
static struct platform_driver musb_driver = {
.driver = {
.name = (char *)musb_driver_name,
.bus = &platform_bus_type,
.owner = THIS_MODULE,
.pm = MUSB_DEV_PM_OPS,
},
.probe = musb_probe,
.remove = __exit_p(musb_remove),
.shutdown = musb_shutdown,
};
static int __init musb_init(void)
{
if (usb_disabled())
return 0;
pr_info("%s: version " MUSB_VERSION ", "
"?dma?"
", "
"otg (peripheral+host)",
musb_driver_name);
return platform_driver_register(&musb_driver);
}
在musb_init中会首先判断usb的使能,然后输出一条打印信息。就是我们在内核打印中看到的
musb-hdrc: version 6.0, ?dma?, otg (peripheral+host),接着调用 platform_driver_register注册驱动程序,在总线上寻找对应的设备,匹配成功后调用对应的probe函数 musb_probe(),在musb_probe函数中首先会对device的部分属性进行判断填充然后会调用musb_init_controller(dev, irq, base)初始化musb主控制器。
musb_init_controller(dev, irq, base)首先是内存申请,以及电源管理的配置,接着填充musb的各项属性,需要关注的是musb->ops = plat->platform_ops这句赋值。这里的的platform_ops就是我们之前在设备初始化那边传进来的static struct musb_platform_ops ti81xx_ops。后面会输出打印信息dev_info (dev, "dma type: %sn", get_dma_name(musb))就是我们在内核打印信息中看到的musb-hdrc musb-hdrc.0: dma type: dma-cppi41。
下面是中断函数的填充musb->isr = generic_interrupt。我们找到该中断函数的定义,通过config配置可以发现这个函数其实指向了NULL。接着是status = musb_platform_init(musb)。我们直接查看该函数的原型
static inline int musb_platform_init(struct musb *musb)
{
if (!musb->ops->init)
return -EINVAL;
return musb->ops->init(musb);
}
该函数调用了设备的操作集合中的初始化函数,而我们知道这个集合就是 ti81xx_ops,在ti81xx_ops里找到init函数ti81xx_musb_init(struct musb *musb)。该函数中前面可以看到pr_info("MUSB%d controller's USBSS revision = %08xn", musb->id, rev),也就是我们在内核打印信息中看到的MUSB0 controller's USBSS revision = 4ea20800。id是驱动传递过来的第一个MUSB传的是0,第二个人传的是1,revision是通过读取SOC寄存器得到的。经过一系列的寄存器设置我们可以看到 musb->isr = ti81xx_interrupt。这里musb的中断函数被正式绑定。接着是data->set_phy_power,我们在usb_musb_init()中设置board_data->set_phy_power = ti81xx_musb_phy_power,这里就会运行
ti81xx_musb_phy_power(),该函数中打印了内核信息host-only。后面musb_platform_set_mode()中会调用ti81xx_musb_set_mode。我们在musb_board_data中定义了俩路usb均为host这里就会被设置为host模式。紧接着是musb->txfifo_intr_enable的判断,我们不深入分析,由内核的打印信息TxFifo Empty intr disabled,可知这里txfifo_intr_enable是有值的。最后是我们的babble_ctrl判断。在 usb_musb_init()我们对这个值进行了赋值。我们不详细研究,只从musb0: Enabled SW babble control打印信息中可以推测出这个值部不为0.
现在我们回到musb_init_controller()中,现在我们知道status = musb_platform_init(musb)执行成功后,它发生的结果中包含了我们向musb绑定了一个中断函数。接着经过一系列设置我们运行了下面这个函数musb_core_init();该函数内打印了一些我们在内核中看到的信息musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, bulk combine, bulk split, HB-ISO Rx, HB-ISO Tx, SoftConn)
musb-hdrc: MHDRC RTL version 2.0
musb-hdrc: setup fifo_mode 4
musb-hdrc: 28/31 max ep, 16384/16384 memory
musb-hdrc.0: bulk split disabled
musb-hdrc.0: bulk combine disabled。
里面主要涉及到的书mbus主控制器核心部分的初始化。
接着回到musb_init_controller()中,if (!is_otg_enabled(musb) && is_host_enabled(musb)),由于我们的设置这里判断条件成立,所以会运行status = usb_add_hcd(musb_to_hcd(musb), -1, 0)。注册我们的USB主机控制器。关于主机控制机hcd部分不详细说明,我们只注意到在这个函数中我们为USB主机控制器申请了数据缓存hcd_buffer_create(hcd),向USB总线驱动注册了USB主机控制器usb_register_bus(&hcd->self),并为USB主机控制器申请了内存usb_alloc_dev(NULL, &hcd->self, 0)。另外在刚进入usb_add_hcd()时,会打印hcd->product_desc。就是内核打印信息中的musb-hdrc musb-hdrc.0: MUSB HDRC host driver。它来自于musb_host.c中的const struct hc_driver musb_hc_driver 结构体中的product_desc,这里不详细说明。在执行usb_register_bus时会打印另一条信息dev_info (bus->controller, "new USB bus registered, assigned bus ""number %dn", bus->busnum);就是我们在内核打印信息中看到的musb-hdrc musb-hdrc.0: new USB bus registered, assigned bus number 1。我们的USB主控制器有俩个所有busnum分别是1和2。这里打印的是第一个USB控制器加载的时候打印的信息。后面会调用retval = register_root_hub(hcd),root_hub的概念可以理解为与usb主机控制器绑定在一起的一种结构。他是该控制器控制的所有usb接口的源头。在register_root_hub中可以看到root_hub设备被真正注册的函数usb_new_device (usb_dev)。
从usb_add_hcd返回后,主机控制器就直接被USB总线识别(这里直接识别的原因还没有做详细分析),出现如下打印信息,这部分打印信息来自hub.c文件
usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb2: Product: MUSB HDRC host driver
usb usb2: Manufacturer: Linux 3.2.0-svn2045 musb-hcd
usb usb2: SerialNumber: musb-hdrc.1
hub 2-0:1.0: USB hub found
hub 2-0:1.0: 1 port detected
musb_init_controller()再往下接着是有关于USB控制器的打印信息
musb-hdrc musb-hdrc.1: USB Host mode controller at d083e800 using DMA, IRQ 19
5.设备如何被识别
usb_hub_init(void)-->hub_thread()-->hub_events()-->if (connect_change)-->hub_port_connect_change()
6.识别后要做那些事情
(1).usb_alloc_dev
(2).usb_set_device_state
这个函数用来设置设备的状态,struct usb_device 结
构体中,有一个成员,enum usb_device_state state,这一刻,会把这个设备的状态设置为
USB_STATE_POWERED,即上电状态.
(3).choose_devnum
为设备选择一个devnum,从1-128之间轮询选择
(4). hub_port_init
端口初始化,主要就是获取设备的描述符。该函数会输出打印信息dev_info(&udev->dev,"%s %s USB device number %d using %sn",(udev->config) ? "reset" : "new", speed,devnum, udev->bus->controller->driver->name);也就是我们插入USB设备后在内核中看到的打印信息usb 2-1.1: new high-speed USB device number 3 using musb-hdrc。
(5).usb_get_status
(6).check_highspeed
如果设备当前是全速状态,但设备描述符中的bcdUSB有0200H(一个设备如果能够进行高速传输,那么它就应该在设备描述符里的bcdUSB 这一项写上0200H),且HUB口支持高速模式时,设备会检查自身是否支持高速运行,并切换到高速运行状态。
(7).usb_new_device
前半部分是和电源管理相关的部分然后是调用函数 usb_enumerate_device(udev)获取描述符枚举设备然后会调用announce_device(udev);打印调试信息,就是在插入USB设备时在内核空间看到的
usb 2-1.1: New USB device found, idVendor=14cd, idProduct=1212,usb 2-1.1: New USB device strings: Mfr=1, Product=3, SerialNumber=2最后调用device_add添加设备。这个函数执行后,系统里就真正有了这个设备,/sysfs 下面也能看到了,而且将会去遍历注册到usb 总线上的所有的驱动程序,如果找到合适的,就去调用该驱动的probe 函数
(8).hub_power_remaining
与电源管理相关的函数
7.关于hub_irq()
8.设备发现机制
原作者:fire贝
|