一.结构体
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 ", 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 ", 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关系图