概述
【思路描述】
想要在Linux上使用AR8033需要做2部分工作,一是编写设备驱动并将设备驱动注册到内核,二是创建设备通信要使用的mdio总线并将设备注册到总线上。关于 AR8033 芯片的介绍可以看我的这篇博文《PHY芯片 AR8033学习笔记》。
【代码分析】
a) 驱动注册流程:
文件mdio_gpio.c 是 mdio_gpio 模块的代码所在。在模块加载函数 mdio_gpio_init() 中通过语句 ret = platform_driver_register(&mdio_gpio_driver) 将mdio 驱动注册为“平台设备驱动”,其中mdio_gpio_driver 是一个 platform_driver 结构体,初始化代码如下:
static struct platform_driver mdio_gpio_driver= {
.probe= mdio_gpio_probe,
// 关联设备的probe函数
.remove= __devexit_p(mdio_gpio_remove),
// 关联设备的remove函数
.driver
= {
.name
= "mdio-gpio",
// 驱动名
.owner
= THIS_MODULE,
},
};
而在 platform_driver_register() 这个函数中,则进一步将驱动总线类型设定为 platform_bus_type,以及关联驱动的probe()函数、remove()函数和shutdown()函数。其代码细节如下:
int platform_driver_register(structplatform_driver *drv)
{
drv->driver.bus= &platform_bus_type;
if(drv->probe)
drv->driver.probe = platform_drv_probe;
// 注意,这是drv->driver.probe
if(drv->remove)
drv->driver.remove= platform_drv_remove;
// 关联drv->driver.remove
if(drv->shutdown)
drv->driver.shutdown= platform_drv_shutdown;
// 关联drv->driver.shutdown
return driver_register(&drv->driver);
}
可以看到,对于所有驱动而言初始化到这一步时都会指向probe()、remove()、shutdown()这3个函数,这3个函数分别用来返回“平台设备驱动”的probe()、remove()、shutdown()函数。代码如下:
static int platform_drv_probe(struct device*_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
return drv->probe(dev);
}
而在platform_driver_register()函数结尾的 return 语句中,再调用driver_register(&drv->driver) 进一步对驱动进行注册。通过语句driver_find(drv->name, drv->bus)查找总线上是否已经注册过该驱动,若没有则使用语句bus_add_driver(drv) 将驱动添加到总线中。至此,驱动注册流程结束。代码如下:
int driver_register(struct device_driver*drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
// 打开调试
// 做一些检测
if((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_typemethodsn", drv->name);
other = driver_find(drv->name, drv->bus);
// 在总线中查找是否已经注册该驱动
if(other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...n",drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
// 将驱动添加到总线
if(ret)
return ret;
ret= driver_add_groups(drv, drv->groups);
if(ret)
bus_remove_driver(drv);
return ret;
}
b) 设备注册流程:
驱动注册流程的末尾会调用驱动的 probe() 函数,即 mdio_gpio_probe() 函数。在该函数中,通过语句new_bus = mdio_gpio_bus_init(&pdev->dev, pdata,pdev->id) 初始化一个 mdio 总线设备,在使用语句 mdiobus_register(new_bus)对该设备总线进行注册。代码如下:
static int __devinit mdio_gpio_probe(structplatform_device *pdev)
{
struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
struct mii_bus *new_bus;
intret;
if(!pdata)
return-ENODEV;
new_bus = mdio_gpio_bus_init(&pdev->dev, pdata,pdev->id);
if(!new_bus)
return -ENODEV;
ret = mdiobus_register(new_bus);
if(ret)
mdio_gpio_bus_deinit(&pdev->dev);
return ret;
}
进入函数 mdiobus_register() 查看代码,内容可以分为2部分。一是对 mdio 总线设备进行真正的注册,二是注册成功后,在总线上根据 phy_mask搜索 PHY 设备。代码如下:
int mdiobus_register(struct mii_bus *bus)
{
int i, err;
if(NULL == bus || NULL == bus->name ||
NULL== bus->read ||
NULL== bus->write)
return-EINVAL;
BUG_ON(bus->state!= MDIOBUS_ALLOCATED &&
bus->state != MDIOBUS_UNREGISTERED);
bus->dev.parent= bus->parent;
bus->dev.class= &mdio_bus_class;
bus->dev.groups= NULL;
dev_set_name(&bus->dev,"%s", bus->id);
err = device_register(&bus->dev);
// 注册 mdio总线设备
if(err) {
printk(KERN_ERR "mii_bus %s failed to registern", bus->id);
return -EINVAL;
}
mutex_init(&bus->mdio_lock);
if(bus->reset)
bus->reset(bus);
for(i = 0; i < PHY_MAX_ADDR; i++) {
if((bus->phy_mask & (1 << i)) == 0) {
structphy_device *phydev;
phydev = mdiobus_scan(bus, i);
// 在总线上搜索 phy 设备
if(IS_ERR(phydev)) {
err = PTR_ERR(phydev);
goto error;
}
}
}
bus->state= MDIOBUS_REGISTERED;
…
// 以下省略
}
进入函数 mdiobus_scan() 查看代码,可以看到在该函数中使用 phydev = get_phy_device(bus, addr) 语句从总线设备上获取到 phy 设备,然后通过语句phy_device_register(phydev) 对phy 设备进行注册。至此,设备注册流程结束。代码如下:
struct phy_device *mdiobus_scan(structmii_bus *bus, int addr)
{
struct phy_device *phydev;
struct mdio_board_entry *be;
int err;
phydev = get_phy_device(bus, addr);
// 从总线设备上获取 phy 设备
if(IS_ERR(phydev) || phydev == NULL)
returnphydev;
mutex_lock(&__mdio_board_lock);
list_for_each_entry(be,&__mdio_board_list, list)
mdiobus_setup_phydev_from_boardinfo(bus,phydev,
&be->board_info);
mutex_unlock(&__mdio_board_lock);
err = phy_device_register(phydev);
// 将 phy 设备注册到内核
if(err) {
phy_device_free(phydev);
return NULL;
}
return phydev;
}
最后
以上就是聪慧枫叶为你收集整理的PHY芯片 AR8033驱动代码分析的全部内容,希望文章能够帮你解决PHY芯片 AR8033驱动代码分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复