linux网络设备—mdio总线

一.结构体

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关系图

linux网络设备—mdio总线_第1张图片

你可能感兴趣的:(linux设备驱动,linux设备驱动)