一.結構體
struct mii_bus {
const char *name; //總線名
char id[MII_BUS_ID_SIZE]; //id
void *priv; //私有數據
int (*read)(struct mii_bus *bus, int phy_id, int regnum); //讀方法
int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val); //寫方法
int (*reset)(struct mii_bus *bus); //復位
struct mutex mdio_lock;
struct device *parent; //父設備
enum {
MDIOBUS_ALLOCATED = 1,
MDIOBUS_REGISTERED,
MDIOBUS_UNREGISTERED,
MDIOBUS_RELEASED,
} state; //總線狀態
struct device dev; //設備文件
struct phy_device *phy_map[PHY_MAX_ADDR]; //PHY設備數組
u32 phy_mask;
int *irq; //中斷
};
二.初始化過程
在phy_init函數中調用了mdio_bus_init初始化mdio總線
int __init mdio_bus_init(void)
{
int ret;
ret = class_register(&mdio_bus_class); //注冊設備類
if (!ret) {
ret = bus_register(&mdio_bus_type); //注冊mdio總線
if (ret)
class_unregister(&mdio_bus_class);
}
return ret;
}
設備類"/sys/class/mdio_bus"
static struct class mdio_bus_class = {
.name = "mdio_bus",
.dev_release = mdiobus_release,
};
總線類型"/sys/bus/mdio"
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match, //匹配方法
.pm = MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);
三.mdio總線注冊
1.調用mdiobus_alloc函數分配內存
struct mii_bus *mdiobus_alloc(void)
{
struct mii_bus *bus;
bus = kzalloc(sizeof(*bus), GFP_KERNEL); //分配內存
if (bus != NULL)
bus->state = MDIOBUS_ALLOCATED;
return bus;
}
EXPORT_SYMBOL(mdiobus_alloc);
2.填充mii_bus的結構體成員
mii_bus->name = ; mii_bus->read = ; mii_bus->write = ; mii_bus->reset = ; mii_bus->parent = ; mii_bus->priv = ; mii_bus->id = ;
3.注冊mii_bus
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; //總線設備類"/sys/bus/mdio_bus"
bus->dev.groups = NULL;
dev_set_name(&bus->dev, "%s", bus->id); //設置總線設備名
err = device_register(&bus->dev); //注冊設備文件
if (err) {
printk(KERN_ERR "mii_bus %s failed to register\n", 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) {
struct phy_device *phydev;
phydev = mdiobus_scan(bus, i); //掃描phy設備
if (IS_ERR(phydev)) {
err = PTR_ERR(phydev);
goto error;
}
}
}
bus->state = MDIOBUS_REGISTERED; //狀態設置為已注冊
pr_info("%s: probed\n", bus->name);
return 0;
error:
while (--i >= 0) {
if (bus->phy_map[i])
device_unregister(&bus->phy_map[i]->dev);
}
device_del(&bus->dev);
return err;
}
EXPORT_SYMBOL(mdiobus_register);
調用了mdiobus_scan函數
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
struct phy_device *phydev;
int err;
phydev = get_phy_device(bus, addr); //獲取創建phy設備
if (IS_ERR(phydev) || phydev == NULL)
return phydev;
err = phy_device_register(phydev); //注冊phy設備
if (err) {
phy_device_free(phydev);
return NULL;
}
return phydev;
}
EXPORT_SYMBOL(mdiobus_scan);
動態地創建了PHY設備
四.mii、mdio、phy、mac關系圖

