一.結構體
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關系圖