前一段时间弄了2个礼拜的OTG驱动调试,感觉精神疲惫啊。主要原因还是自己对OTG功能不了解造成的。现在终于完成但是对实质原理还有些模糊。所以自己重新总结一下。因为自己是菜鸟,所以用菜鸟的白话方式分析。高手滤过吧。所谓OTG功能就是具备该功能的设备即可当主设备(host)去轮询别人,也可以当从设备(device)去被别人轮~~(双性人?)。正所谓所有的产品和功能都是因为需求存在的,举个最简单的需求,原来MP3想传送一个歌曲都得通过电脑。现在只要两个MP3链接,其中一个MP3有OTG功能作为主设备(相当于电脑主机),然后另外一个是从设备就可以实现数据的传送了。那么话说回来,具有OTG功能的设备如何确定自己是主还是从设备那。原来原来USB接口上有4个管脚,OTG功能有5个。原来4个分别是电D+ D-地。现在增加了一个ID。这个ID线就决定了自己做主设备还是从设备。如果ID线是高则自己是从设备,反之是主设备。
下面开始分析代码。
向平时一样定义platform_device资源等信息。
定义platform_device结构
static struct platform_device __maybe_unused dr_otg_device =
{ .name = "fsl-usb2-otg", //设备的名称 日后匹配用
.id = -1, //只有一个这样的设备
.dev = { .release = dr_otg_release,
.dma_mask = &dr_otg_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.resource = otg_resources, //设备的资源 看下面
.num_resources = ARRAY_SIZE(otg_resources),
};
定义platform_device下的struct resource设备资源结构static struct resource otg_resources[] = {
[0] = {
.start = (u32)(USB_OTGREGS_BASE), //描述设备实体在cpu总线上的线性起始物理地址
.end = (u32)(USB_OTGREGS_BASE + 0x1ff), //描述设备实体在cpu总线上的线性结尾物理地址
.flags = IORESOURCE_MEM, },
[1] = {
.start = MXC_INT_USB_OTG, //中断号
.flags = IORESOURCE_IRQ, },
};定义平台设备私有数据,以后驱动要使用
static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
.name = "DR",
.platform_init = usbotg_init,
.platform_uninit = usbotg_uninit,
.phy_mode = FSL_USB2_PHY_UTMI_WIDE,
.power_budget = 500, /* via RT9706 */
.gpio_usb_active = gpio_usbotg_utmi_active,
.gpio_usb_inactive = gpio_usbotg_utmi_inactive,
.transceiver = "utmi",
.wake_up_enable = _wake_up_enable,
};
#define PDATA (&dr_utmi_config) 定义platform_device下的DEV设备下的平台私有数据(就是该设备私有的数据)
static inline void dr_register_otg(void) {
PDATA->operating_mode = FSL_USB2_DR_OTG; //将模式更改(上面定义的时候定义的是FSL_USB2_PHY_UTMI_WIDE,不知道为什么开始不定义这个,可能是为了兼容)
dr_otg_device.dev.platform_data = PDATA; //该设备的私有数据赋值,就是上面定义的dr_utmi_config
if (platform_device_register(&dr_otg_device))
printk(KERN_ERR "usb: can't register otg device\n");
else
printk(KERN_INFO "usb: DR OTG registered\n");
}
上面几个过程主要是完成了设备的注册。这个过程是:
1.定义platform_device结构。
2.定义platform_device下的struct resource设备资源结构
3.定义platform_device下的DEV设备下的平台私有数据(就是该设备私有的数据)
4.调用platform_device_register将platform_device结构
注册上面4个过程调用结束后,设备的信息就被注册到系统中,等待驱动的使用
下面分析驱动和设备的链接过程
定义platform_driver结构
struct platform_driver fsl_otg_driver = {
.probe = fsl_otg_probe, //定义处理函数,该函数在设备名字匹配到后调用,也就是发现该驱动对应的设备在系统中注册过。
.remove = fsl_otg_remove,
.driver = {
.name = "fsl-usb2-otg", //通过该名字匹配开始注册进系统的设备
.owner = THIS_MODULE,
},
};
将platform_driver结构注册进系统,系统通过注册名字匹配该设备是否已经在系统中,如果在调用注册的probe = fsl_otg_probe函数
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);
}
调用fsl_otg_probe函数,函数参数platform_device *pdev,就是我们上面注册进系统的platform_device结构,现在由系统赋值调用fsl_otg_probe
static int __init fsl_otg_probe(struct platform_device *pdev)
{
int status;
struct fsl_usb2_platform_data *pdata;
DBG("pdev=0x%p\n", pdev);
if (!pdev)
return -ENODEV;
/*判断是否有设备自己的数据,就是检查我们上面定义的3的过程*/
if (!pdev->dev.platform_data)