前一段时间弄了2个礼拜的OTG驱动调试,感觉精神疲惫啊。主要原因还是自己对OTG功能不了解造成的。
如今最终完毕可是对实质原理还有些模糊。所以自己又一次总结一下。
由于自己是菜鸟,所以用菜鸟的白话方式分析。
高手滤过吧。 所谓OTG功能就是具备该功能的设备就可以当主设备(host)去轮询别人,也能够当从设备(device)去被别人轮~~(双性人?)。
正所谓全部的产品和功能都是由于需求存在的,举个最简单的需求。原来MP3想传送一个歌曲都得通过电脑。如今仅仅要两个MP3链接,当中一个MP3有OTG功能作为主设备(相当于电脑主机),然后另外一个是从设备就能够实现数据的传送了。
那么话说回来,具有OTG功能的设备怎样确定自己是主还是从设备那。原来原来USB接口上有4个管脚。OTG功能有5个。原来4个各自是电 D+ D- 地。
如今添加了一个ID。这个ID线就决定了自己做主设备还是从设备。假设ID线是高则自己是从设备。反之是主设备。
以下開始分析代码。
.id = -1, //仅仅有一个这种设备 .dev = { .release = dr_otg_release, .num_resources = ARRAY_SIZE(otg_resources), 定义platform_device下的struct resource设备资源结构 .end = (u32)(USB_OTGREGS_BASE + 0x1ff), //描写叙述设备实体在cpu总线上的线性结尾物理地址 .flags = IORESOURCE_MEM, }, .flags = IORESOURCE_IRQ, }, 定义平台设备私有数据,以后驱动要使用 static inline void dr_register_otg(void) { dr_otg_device.dev.platform_data = PDATA; //该设备的私有数据赋值。就是上面定义的dr_utmi_config if (platform_device_register(&dr_otg_device)) |
上面几个过程主要是完毕了设备的注冊。这个过程是:
1.定义platform_device结构。
2.定义platform_device下的struct resource设备资源结构
3.定义platform_device下的DEV设备下的平台私有数据(就是该设备私有的数据)
4.调用platform_device_register将platform_device结构
注冊上面4个过程调用结束后,设备的信息就被注冊到系统中。等待驱动的使用
以下分析驱动和设备的链接过程
定义platform_driver结构
|
调用fsl_otg_probe函数。函数參数platform_device *pdev。就是我们上面注冊进系统的platform_device结构。如今由系统赋值调用fsl_otg_probe
static int __init fsl_otg_probe(struct platform_device *pdev)
|
上面函数中调用了fsl_otg_conf。我们来看看他干了什么。
static int fsl_otg_conf(struct platform_device *pdev)
/* allocate space to fsl otg device */ INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event); INIT_LIST_HEAD(&active_timers); /* Set OTG state machine operations */
/* initialize the otg structure */ fsl_otg_dev = fsl_otg_tc; /* Store the otg transceiver */
return 0; |
int usb_otg_start(struct platform_device *pdev)
/* Initialize the state machine structure with default values */ /* We don‘t require predefined MEM/IRQ resource index */
/* We don‘t request_mem_region here to enable resource sharing
/* request irq */
if (pdata->platform_init && pdata->platform_init(pdev) != 0) /* Export DR controller resources */
/* reset the controller */ /* wait reset completed */ /* configure the VBUSHS as IDLE(both host and device) */ /* configure PHY interface */ if (pdata->have_sysif_regs) { /* disable all interrupt and clear all OTGSC status */ /* DBG("initial ID pin=%d\n", p_otg->fsm.id); /* enable OTG ID pin interrupt */ return 0; |
以下分析下 中断例程函数
该函数就是推断ID的高低,也就是自己做主设备还是从设备
/* Only clear otg interrupts */ /*FIXME: ID change not generate when init to 0 */ /* process OTG interrupts */ if (otg->host) if (fsm->id) { /* switch to gadget *///从设备
return IRQ_HANDLED; return IRQ_NONE; |
/* Update a_vbus_vld state as a_vbus_vld int is disabled otg_dev->host_working = 1;
|
VDBG("gadget %s \n", on ? "on" : "off"); if (on) return 0;
|
上面部分就是 OTG功能的 OTG驱动部分。
OTG功能还要有做主设备使用的主设备驱动和做从设备的从设备驱动。
从上面代码分析我们归纳出流程:
分两个大部分:
一 设备的注冊 当中包含
1.定义platform_device结构。
2.定义platform_device下的struct resource设备资源结构
3.定义platform_device下的DEV设备下的平台私有数据(就是该设备私有的数据)
4.调用platform_device_register将platform_device结构
二 OTG驱动的注冊 当中包含
1.struct platform_driver fsl_otg_driver 结构的注冊
2.匹配到有设备存在时调用的PORE函数,对设备进行初始化设置和功能函数的绑定
3.完毕中断函数的绑定和中断例程的注冊。
经过上面的处理后,仅仅要OTG ID的变化就会触发中断,调用中断例程函数。决定是调用主设备还是从设备驱动。 而主设备和从设备驱动和OTG调用的链接是分别在主从设备驱动中完毕的。
后面我们介绍主从设备驱动中会介绍到。
在文章的最后想起来这次调OTG遇见的问题。分享给大家希望大家有帮助。
我调试OTG时,開始将OTG编译到内核中。(Y)。结果插入U盘没有反应。后来发现原来我添加内核后,主设备驱动的先OTG设备驱动被运行,造成主设备函数和OTG功能的链接出现故障。
(应该是OTG先初始化 然后从和主设备驱动链接。
)后来我使用模块方式编译OTG功能。依照先载入OTG后载入从和主设备。
(insmod方式),结果OTG就能够使用了。
后来通过减少主设备的优先级方式,把OTG编译进内核,然后由于主设备优先级低所以最后被调用。 也就是在主设备注冊那使用
late_initcall(ehci_hcd_init);取代//module_init(ehci_hcd_init);。这样主设备的优先级就低于设备驱动的优先级就在驱动载入完载入了。 可是总感觉这样不是非常合理的方式,假设有朋友有更好的办法请不吝赐教。