am335x 的MUSB控制器解读

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%x\n",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: %s\n", 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 = %08x\n", 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 %d\n", 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 %s\n",(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.设备发现机制

 

 

 

 

 

 

 

你可能感兴趣的:(linux驱动)