转自: http://www.tuicool.com/articles/QJfmUr 在用户层上的程序, 建立本地socket后,使用ioctl读取phy芯片的寄存器。 ioctl(sockfd, SIOCGMIIREG, &ifr); 下面是linux的网络设备驱动程序响应用户层的ioctl命令过程间各个阶段的函数调用。 ioclt 系统调用层: fs/ioctl.c SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { ... error = do_vfs_ioctl(filp, fd, cmd, arg); ... } int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg) { switch (cmd) { ... default: ... error = vfs_ioctl(filp, cmd, arg); ... } static long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { ... /*如果文件操作方法--无锁的的ioctl有对应实现函数(函数指针unlock_ioctl有被填充), 则调用unlcok_ioctl的实现函数 */ if (filp->f_op->unlocked_ioctl) { error = filp->f_op->unlocked_ioctl(filp, cmd, arg); ... } unlock_ioctl 的实现层: net/socket.c static const struct file_operations socket_file_ops = { ... .unlocked_ioctl = sock_ioctl, ... } static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { ... switch (cmd) { ... default: err = sock->ops->ioctl(sock, cmd, arg); if (err == -ENOIOCTLCMD) err = dev_ioctl(net, cmd, argp); ... } net/core/dev.c //dev_ioctl : network device ioctl dev_ioctl(){ switch (cmd) { ... case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSIFNAME: ret = dev_ifsioc(net, &ifr, cmd); } static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) { switch (cmd) { ... default: if (ops->ndo_do_ioctl) { if (netif_device_present(dev)) err = ops->ndo_do_ioctl(dev, ifr, cmd); ... } ndo_do_ioctl 的实现层: drivers/net/octeon/octeon_mgmt.c static int __init octeon_mgmt_mod_init(void) { /* Force our mdiobus driver module to be loaded first. */ octeon_mdiobus_force_mod_depencency(); return platform_driver_register(&octeon_mgmt_driver); } static struct platform_driver octeon_mgmt_driver = { .driver = { .name = "octeon_mgmt", .owner = THIS_MODULE, .of_match_table = octeon_mgmt_match, }, .probe = octeon_mgmt_probe, .remove = __exit_p(octeon_mgmt_remove), }; static struct of_device_id octeon_mgmt_match[] = { { .compatible = "cavium,octeon-5750-mix", }, {}, }; MODULE_DEVICE_TABLE(of, octeon_mgmt_match); static int __init octeon_mgmt_probe(struct platform_device *pdev) { ... netdev->netdev_ops = &octeon_mgmt_ops; netdev->ethtool_ops = &octeon_mgmt_ethtool_ops; ... } static const struct net_device_ops octeon_mgmt_ops = { .ndo_open = octeon_mgmt_open, .ndo_stop = octeon_mgmt_stop, .ndo_start_xmit = octeon_mgmt_xmit, .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering, .ndo_set_multicast_list = octeon_mgmt_set_rx_filtering, .ndo_set_mac_address = octeon_mgmt_set_mac_address, .ndo_do_ioctl = octeon_mgmt_ioctl, .ndo_change_mtu = octeon_mgmt_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = octeon_mgmt_poll_controller, #endif }; static int octeon_mgmt_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) { default: if (p->phydev) return phy_mii_ioctl(p->phydev, if_mii(rq), cmd); return -EINVAL; } } drivers/net/phy/phy.c int phy_mii_ioctl(struct phy_device *phydev, struct mii_ioctl_data *mii_data, int cmd) { switch (cmd) { case SIOCGMIIPHY: mii_data->phy_id = phydev->addr; case SIOCGMIIREG: mii_data->val_out = phy_read(phydev, mii_data->reg_num); break; ... } include/linux/phy.h static inline int phy_read(struct phy_device *phydev, u32 regnum) { return mdiobus_read(phydev->bus, phydev->addr, regnum); } drivers/net/phy/mdio_bus.c int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) { retval = bus->read(bus, addr, regnum); ... } bus->read 的实现层: drivers/net/phy/mdio-octeon.c static int __init octeon_mdiobus_mod_init(void) { return platform_driver_register(&octeon_mdiobus_driver); } static struct platform_driver octeon_mdiobus_driver = { .driver = { .name = "mdio-octeon", .owner = THIS_MODULE, .of_match_table = octeon_mdiobus_match, }, .probe = octeon_mdiobus_probe, .remove = __exit_p(octeon_mdiobus_remove), }; static struct of_device_id octeon_mdiobus_match[] = { { .compatible = "cavium,octeon-3860-mdio", }, {}, }; MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); static int __init octeon_mdiobus_probe(struct platform_device *pdev) { ... bus->mii_bus->read = octeon_mdiobus_read; bus->mii_bus->write = octeon_mdiobus_write; ... } octeon_mdiobus_read 是最底层的实现函数。