在windows系统里面,如果发现新的硬件设备但是系统没有可以用的自带驱动程序,那用户就得自己安装驱动。Linux内核的设计也是一样,下面就以marvel PHY设备的发现和驱动安装(即模块插入)为例说明一般嵌入式里设备的发现和安装过程。
struct device *dev)
假如某个小系统里面,soc上集成了MAC,然后外面通过MDIO BUS接了一个PHY芯片,那么在定制内核的时候肯定会选择libphy以及相应的SOC MDIO BUS驱动,内核启动的时候,MDIO BUS驱动会调用mdiobus_register()来向内核注册bus,注册的过程中会循环调用mdiobus_scan去发现PHY设备,get_phy_device()做的就是就是读取PHY芯片的ID,如果发现MDIO BUS挂了PHY设备,那就为这个PHY设备创建phy_device实例,并且为其分配addr。这样内核里就有为PHY设备初始化了数据结构了,也就是说发现并创建了设备(所有的设备都会有struct device结构)。
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
struct phy_device *phydev;
int err;
phydev = get_phy_device(bus, addr, false);
if (IS_ERR(phydev) || phydev == NULL)
return phydev;
err = phy_device_register(phydev);
if (err) {
phy_device_free(phydev);
return NULL;
}
return phydev;
}
那么接下来就是安装驱动的过程。
我们假设驱动模块是内核起来后加载的,那么来看看驱动的实现。
static struct phy_driver marvell_drivers[] = {
{
.phy_id = MARVELL_PHY_ID_88E1101,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1101",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.driver = { .owner = THIS_MODULE },
},
PHY的驱动模块定义了driver数据结构,一系列API。而驱动模块插入时,调用phy_drivers_register向系统注册此driver,并将其和mdio bus type关联。那如何将这个驱动代码和刚才发现的PHY设备关联起来呢?这里的phy_id和phy_id_mask是关键。
phy_drivers_register最终会调用driver_attach在这个driver关联的bus上面为每个设备match这个driver。主要代码在下面两个函数:
static inline int driver_match_device(struct device_driver *drv,
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
struct phy_device *phydev = to_phy_device(dev);
struct phy_driver *phydrv = to_phy_driver(drv);
if (of_driver_match_device(dev, drv))
return 1;
if (phydrv->match_phy_device)
return phydrv->match_phy_device(phydev);
return ((phydrv->phy_id & phydrv->phy_id_mask) ==
(phydev->phy_id & phydrv->phy_id_mask));
}
前面发现设备的时候设备已经记录了自己的phy_id,这个时候driver又是和这个phy_id匹配,所以驱动就匹配上了PHY设备。这之后phy_device->drv就会指向marvell_drivers。
整个过程的设计十分科学合理。