且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

I.MX6 OTG set as slave device hacking

更新时间:2022-08-12 20:41:55

/****************************************************************************** 
 *                   IMX6 OTG set as slave device hacking 
 * 声明:
 *  1. 本代码解析使用了倒序的方式跟踪内核驱动代码,从驱动反推需求;
 *  2. 代码解析的目标是找到OTG设置成Host、Slave设备的宏定义;
 *  3. 根据2中的宏定义,看make menuconfig中是否存在可直接裁剪的选项。
 *
 *                                      2015-8-7 晴 深圳 南山平山村 曾剑锋
 *****************************************************************************/           
                                                                                          
                                                                                          
<kernel path>/drivers/usb/otg/fsl_otg.c                                                   
                                                                                          
    static int __init fsl_usb_otg_init(void)       <----------------------------+         
    {                                                                           |         
        printk(KERN_INFO DRIVER_DESC " loaded, %s\n", DRIVER_VERSION);          |         
        return platform_driver_register(&fsl_otg_driver);                       |         
    }                                             |                             |         
                                                  |                             |         
    static void __exit fsl_usb_otg_exit(void)     +-------------+               |         
    {                                                           |               |         
        platform_driver_unregister(&fsl_otg_driver);            |               |         
        printk(KERN_INFO DRIVER_DESC " unloaded\n");            |               |         
    }                                                           |               |         
                                                                |               |         
    subsys_initcall(fsl_usb_otg_init);      --------------------|---------------+         
    module_exit(fsl_usb_otg_exit);                              |                         
                                                                |                         
    MODULE_DESCRIPTION(DRIVER_INFO);                            |                         
    MODULE_AUTHOR(DRIVER_AUTHOR);                               |                         
    MODULE_LICENSE("GPL");                                      |                         
                                                                |                         
                                                                |                         
    struct platform_driver fsl_otg_driver = {     <-------------+                         
        .probe = fsl_otg_probe,                                                           
        .remove = fsl_otg_remove,                                                         
        .driver = {                                                                       
            .name = driver_name,    --------+                                             
            .owner = THIS_MODULE,           |                                             
        },                                  |                                             
    };                                      |                                             
                                            V                                             
    static const char driver_name[] = "fsl-usb2-otg";    -------------+                   
                                                                      |                   
                                                                      |                   
<kernel path>/arch/arm$ grep fsl-usb2-otg * -R                        |                   
    Binary file boot/Image matches                                    |                   
    mach-mx5/devices.c:    .name = "fsl-usb2-otg",                    |                   
    ......                                                            |                   
    Binary file plat-mxc/devices/built-in.o matches                   V                   
    plat-mxc/devices/platform-fsl-usb2-otg.c:    const char *name = "fsl-usb2-otg";       
    Binary file plat-mxc/built-in.o matches                                    |          
                                                                               |          
                                                                               |          
<kernel path>/arch/arm/plat-mxc/devices/platform-fsl-usb2-otg.c                |          
    #define imx_fsl_usb2_otg_data_entry_single(soc)             \              |          
        {                               \                                      |          
            .iobase = soc ## _USB_OTG_BASE_ADDR,            \                  |          
            .irq = soc ## _INT_USB_OTG,             \                          |          
        }                                                                      |          
                                                                               |          
                                                                               |          
    #ifdef CONFIG_SOC_IMX6Q                                                    |          
    const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst =   |          
        imx_fsl_usb2_otg_data_entry_single(MX6Q);                              |          
    #endif /* ifdef CONFIG_SOC_IMX6Q */                                        |          
                                                                               |          
    struct platform_device *__init imx_add_fsl_usb2_otg(         ----------+   |          
            const struct imx_fsl_usb2_otg_data *data,                      |   |          
            const struct fsl_usb2_platform_data *pdata)                    |   |          
    {                                                                      |   |          
        struct resource res[] = {                                          |   |          
            {                                                              |   |          
                .start = data->iobase,                                     |   |          
                .end = data->iobase + SZ_512 - 1,                          |   |          
                .flags = IORESOURCE_MEM,                                   |   |          
            }, {                                                           |   |          
                .start = data->irq,                                        |   |          
                .end = data->irq,                                          |   |          
                .flags = IORESOURCE_IRQ,                                   |   |          
            },                                                             |   |          
        };                                                                 |   |          
                                                                           |   |          
        int ret = -ENOMEM;                                                 |   |          
        const char *name = "fsl-usb2-otg";       <-------------------------|---+          
        int id = -1;                                                       |              
        unsigned int num_resources = ARRAY_SIZE(res);                      |              
        size_t size_data = sizeof(*pdata);                                 |              
        u64 dmamask = DMA_BIT_MASK(32);                                    |              
        struct platform_device *pdev;                                      |              
                                                                           |              
        pdev = platform_device_alloc(name, id);                            |              
        if (!pdev)                                                         |              
            goto err;                                                      |              
                                                                           |              
        if (dmamask) {                                                     |              
            /*                                                             |              
             * This memory isn't freed when the device is put,             |              
             * I don't have a nice idea for that though.  Conceptually     |              
             * dma_mask in struct device should not be a pointer.          |              
             * See http://thread.gmane.org/gmane.linux.kernel.pci/9081     |              
             */                                                            |              
            pdev->dev.dma_mask =                                           |              
                kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);          |              
            if (!pdev->dev.dma_mask)                                       |              
                /* ret is still -ENOMEM; */                                |              
                goto err;                                                  |              
                                                                           |              
            *pdev->dev.dma_mask = dmamask;                                 |              
            pdev->dev.coherent_dma_mask = dmamask;                         |              
        }                                                                  |              
                                                                           |              
        ret = platform_device_add_resources(pdev, res, num_resources);     |              
        if (ret)                                                           |              
            goto err;                                                      |              
                                                                           |              
        if (data) {                                                        |              
            ret = platform_device_add_data(pdev, pdata, size_data);        |              
            if (ret)                                                       |              
                goto err;                                                  |              
        }                                                                  |              
                                                                           |              
        return pdev;                                                       |              
    err:                                                                   |              
            if (dmamask)                                                   |              
                kfree(pdev->dev.dma_mask);                                 |              
            platform_device_put(pdev);                                     |              
            return ERR_PTR(ret);                                           |              
    }                                                                      |              
    EXPORT_SYMBOL(imx_add_fsl_usb2_otg);                                   |              
                                                                           |              
<kernel path>/arch/arm$ grep imx_add_fsl_usb2_otg * -R       <-------------+              
    Binary file boot/Image matches                                                        
    mach-mx6/devices-imx6q.h:    imx_add_fsl_usb2_otg(&imx6q_fsl_usb2_otg_data, pdata)   ----------+
    ......                                                                                         |
    plat-mxc/devices/platform-fsl-usb2-otg.c:struct platform_device *__init imx_add_fsl_usb2_otg(  |
    plat-mxc/devices/platform-fsl-usb2-otg.c:EXPORT_SYMBOL(imx_add_fsl_usb2_otg);                  |
    Binary file plat-mxc/built-in.o matches                                                        |
                                                                                                   |
<kernel path>/arch/arm/mach-mx6/devices-imx6q.h                                                    |
    extern const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst;                 |
    #define imx6q_add_fsl_usb2_otg(pdata)   \                            -------------------+      |
        imx_add_fsl_usb2_otg(&imx6q_fsl_usb2_otg_data, pdata)            <------------------*------+
                                                                                            |
<kernel path>/arch/arm$ grep imx6q_add_fsl_usb2_otg * -R                                    |
    Binary file mach-mx6/.usb_dr.c.swp matches                                              |
    mach-mx6/devices-imx6q.h:#define imx6q_add_fsl_usb2_otg(pdata)    \                     |
    mach-mx6/devices-imx6q.h:#define imx6q_add_fsl_usb2_otg_wakeup(pdata)    \              |
    mach-mx6/usb_dr.c:    pdev[i] = imx6q_add_fsl_usb2_otg(&dr_utmi_config);                |
    mach-mx6/usb_dr.c:    pdev_wakeup = imx6q_add_fsl_usb2_otg_wakeup(&dr_wakeup_config);   |
                                                                                            |
<kernel path>/arch/arm/mach-mx6/usb_dr.c                                                    |
    static int  __init mx6_usb_dr_init(void)                                                |
    {                                                                                       |
        int i = 0;                                                                          |
        void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR);                  |
        struct imx_fsl_usb2_wakeup_data imx6q_fsl_otg_wakeup_data =                         |
            imx_fsl_usb2_wakeup_data_entry_single(MX6Q, 0, OTG);                            |
        struct imx_mxc_ehci_data __maybe_unused imx6q_mxc_ehci_otg_data =                   |
            imx_mxc_ehci_data_entry_single(MX6Q, 0, OTG);                                   |
        struct imx_fsl_usb2_udc_data __maybe_unused imx6q_fsl_usb2_udc_data =               |
            imx_fsl_usb2_udc_data_entry_single(MX6Q);                                       |
        struct imx_fsl_usb2_otg_data __maybe_unused imx6q_fsl_usb2_otg_data  =              |
            imx_fsl_usb2_otg_data_entry_single(MX6Q);                                       |
                                                                                            |
        /* Some phy and power's special controls for otg                                    |
         * 1. The external charger detector needs to be disabled                            |
         * or the signal at DP will be poor                                                 |
         * 2. The EN_USB_CLKS is always enabled.                                            |
         * The PLL's power is controlled by usb and others who                              |
         * use pll3 too.                                                                    |
         */                                                                                 |
        __raw_writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B  \                                     |
                | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B,  \                                 |
                anatop_base_addr + HW_ANADIG_USB1_CHRG_DETECT);                             |
        __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS,                               |
                anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET);                        |
        mx6_get_otghost_vbus_func(&mx6_set_usb_otg_vbus);                                   |
        dr_utmi_config.platform_driver_vbus = mx6_set_usb_otg_vbus;                         |
                                                                                            |
    #ifdef CONFIG_USB_OTG                                                                   |
        /* wake_up_enable is useless, just for usb_register_remote_wakeup execution*/       |
        dr_utmi_config.wake_up_enable = _device_wakeup_enable;                              |
        dr_utmi_config.operating_mode = FSL_USB2_DR_OTG;                                    |
        dr_utmi_config.wakeup_pdata = &dr_wakeup_config;                                    |
        pdev[i] = imx6q_add_fsl_usb2_otg(&dr_utmi_config);         <------------------------+
        dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data;                          
        i++;                                                                              
    #endif                                                                                
    #ifdef CONFIG_USB_EHCI_ARC_OTG                                 -------------------------+
        dr_utmi_config.operating_mode = DR_HOST_MODE;                                       |
        dr_utmi_config.wake_up_enable = _host_wakeup_enable;                                |
        if (usb_icbug_swfix_need()) {                                                       |
            dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend_swfix;           |
            dr_utmi_config.platform_rh_resume  = _host_platform_rh_resume_swfix;            |
        } else {                                                                            |
            dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend;                 |
            dr_utmi_config.platform_rh_resume  = _host_platform_rh_resume;                  |
        }                                                                                   |
        dr_utmi_config.platform_set_disconnect_det = fsl_platform_otg_set_usb_phy_dis;      |
        dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend;                   |
        dr_utmi_config.is_wakeup_event = _is_host_wakeup;                                   |
        dr_utmi_config.wakeup_pdata = &dr_wakeup_config;                                    |
        dr_utmi_config.wakeup_handler = host_wakeup_handler;                                |
        dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on;                    |
        pdev[i] = imx6q_add_fsl_ehci_otg(&dr_utmi_config);                                  |
        dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data;                         |
        i++;                                                                                |
    #endif                                                                                  |
    #ifdef CONFIG_USB_GADGET_ARC                                                            |
        dr_utmi_config.operating_mode = DR_UDC_MODE;                                        |
        dr_utmi_config.wake_up_enable = _device_wakeup_enable;                              |
        dr_utmi_config.platform_rh_suspend = NULL;                                          |
        dr_utmi_config.platform_rh_resume  = NULL;                                          |
        dr_utmi_config.platform_set_disconnect_det = NULL;                                  |
        dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend;                 |
        dr_utmi_config.is_wakeup_event = _is_device_wakeup;                                 |
        dr_utmi_config.wakeup_pdata = &dr_wakeup_config;                                    |
        dr_utmi_config.wakeup_handler = device_wakeup_handler;                              |
        dr_utmi_config.charger_base_addr = anatop_base_addr;                                |
        dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on;                    |
        pdev[i] = imx6q_add_fsl_usb2_udc(&dr_utmi_config);                                  |
        dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data;                         |
        i++;                                                                                |
    #endif                                                                                  |
        devnum = i;                                                                         |
        /* register wakeup device */                                                        |
        pdev_wakeup = imx6q_add_fsl_usb2_otg_wakeup(&dr_wakeup_config);                     |
        for (i = 0; i < devnum; i++) {                                                      |
            platform_device_add(pdev[i]);                                                   |
            ((struct fsl_usb2_platform_data *)(pdev[i]->dev.platform_data))->wakeup_pdata = | 
                (struct fsl_usb2_wakeup_platform_data *)(pdev_wakeup->dev.platform_data);   |
        }                                                                                   |
                                                                                            |
        return 0;                                                                           |
    }                                                                                       |
    module_init(mx6_usb_dr_init);                                                           |
                                                                                            |
<kernel path>$ make menuconfig                                                              |
  | Symbol: USB_EHCI_ARC_OTG [=n]     <--------------------------------*--------------------+
  │ Type  : boolean                                                    |                     
  │ Prompt: Support for DR host port on Freescale controller           |                     
  │   Defined at drivers/usb/host/Kconfig:80                           |                     
  │   Depends on: USB_SUPPORT [=y] && USB_EHCI_ARC [=y]                |                      
  │   Location:                                                        |-> Device Drivers                                              |-> USB support (USB_SUPPORT [=y])                            |-> Support for Freescale controller (USB_EHCI_ARC [=y])    |