平台设备/驱动的注册

Platform_device_register向系统注册设备;
Platform_driver_register向系统注册驱动,过程中在系统寻找注册的设备(根据.name),找到后运行.probe进行初始化。
所以Platform_device_register必须先于Platform_driver_register执行。
1. Platform_device_register执行流程。

1)zx297520v3-device.c中zx29_device_table中定义了所有的设备;

#ifdef CONFIG_MTD_ZXIC_SPIFCstatic struct resource spi_nand_resource[] = {[0] = {.start  = ZX_SPIFC0_BASE,.end    = ZX_SPIFC0_BASE + SZ_4K - 1,.flags  = IORESOURCE_MEM,.name   = "spifc_reg",},[2] = {.start  = SPI_FC0_INT,.end    = SPI_FC0_INT,.flags  = IORESOURCE_IRQ,},};
#endif
#ifdef CONFIG_MTD_ZXIC_SPIFC
struct platform_device zx29_device_spi_nand = {.name       = "spi-nand-dt",.id     = -1,.num_resources  = ARRAY_SIZE(spi_nand_resource),.resource   = spi_nand_resource,
};
#endif
struct platform_device *zx29_device_table[] __initdata={
#ifdef CONFIG_SERIAL_ZX29_UART&zx29_uart0_device,&zx29_uart1_device,&zx29_uart2_device,
#endif
#ifdef CONFIG_MTD_NAND_DENALI&zx29_device_nand,
#endif
#ifdef CONFIG_DWC_OTG_USB&zx29_usb0_device,
#endif
#ifdef CONFIG_USB_DWC_OTG_HCD&zx29_usb1_device,
#endif
#ifdef CONFIG_MTD_ZXIC_SPIFC&zx29_device_spi_nand,
#endif
#ifdef CONFIG_ZX29_DMA&zx29_dma_device,
#endif
......
}

2)board-zx297520v3.c中board_init()函数中调用platform_add_devices;

static void __init board_init(void)
{......platform_add_devices(zx29_device_table, zx29_device_table_num);......
}

3)platform_add_devices中对table进行遍历,调用platform_device_register进行注册;

int platform_add_devices(struct platform_device **devs, int num)
{int i, ret = 0;for (i = 0; i < num; i++) {ret = platform_device_register(devs[i]);if (ret) {while (--i >= 0)platform_device_unregister(devs[i]);break;}}return ret;
}

4)platform_device_register先调用device_initialize,再调用platform_device_add;
device_initialize主要是初始化设备结构体,包括kobject、mutex、spin_lock、list、pm初始化等,方便后面的platform_device_add使用;
platform_device_add中先调用insert_resource(p,r)将platform资源(上面截图的resource)添加进内核,由内核进行统一管理,然后再调用device_add()。

2. Platform_driver_register执行流程。

1)调用Platform_driver_register注册驱动;

static const struct of_device_id spifc_nand_dt_ids[] = {{ .compatible = "spifc,spifc-nand-dt" },{ /* sentinel */ }
};MODULE_DEVICE_TABLE(of, spifc_nand_dt_ids);static struct platform_driver spifc_dt_driver =
{.probe      = spifc_drv_probe,.remove     = spifc_drv_remove,.driver     = {.name   = "spi-nand-dt",.owner  = THIS_MODULE,.of_match_table = spifc_nand_dt_ids,},
};module_platform_driver(spifc_dt_driver);

module_platform_driver(xxx);
最终展开后就是如下形式:
static int __init xxx_init(void)
{
        return platform_driver_register(&xxx);
}
module_init(xxx_init);
static void __exit xxx_init(void)
{
        return platform_driver_unregister(&xxx);
}
module_exit(xxx_exit);

2)platform_driver_register(&xx_driver) 会向系统注册xx_driver这个驱动程序,这个函数会根据 xx_driver中的.name内容,搜索系统注册的device中有没有这个platform_device,如果有,就会执行 platform_driver(也就是xx_driver的类型)中的.probe函数,即上述截图的spifc_drv_probe()函数。

I2C设备/驱动的注册

1. 设备的注册

1)zx297520v3-devices.c中定义了需要添加的I2C设备;

#ifdef CONFIG_MFD_ZX234290_I2C
static struct  zx234290_board zx234290_platform = {.irq_gpio_num       =   PIN_PMU_INT, //EX0_INT,.irq_gpio_func      =   PMU_INT_FUNC_SEL,.pshold_gpio_num    =   PIN_PMU_PSHOLD,.pshold_gpio_func   =   PMU_PSHOLD_FUNC_SEL,.irq_base   =   ENT_ZX234290_IRQ_BASE,
};
#endif
static struct i2c_board_info zx29_i2c0_devices[] = {
#ifdef CONFIG_MFD_ZX234290_I2C[0]={I2C_BOARD_INFO("zx234290", 0x12),.irq        = EX0_INT,.platform_data  = &zx234290_platform,},
#endif};

2)Board-zx297520v3.c中调用i2c_add_devices()函数添加I2C设备;

void __init i2c_add_devices(void)
{unsigned  devices_num = 0;int ret = 0;/**i2c devices on bus 0*/devices_num = ARRAY_SIZE(zx29_i2c0_devices);if (devices_num){ret = i2c_register_board_info(0,zx29_i2c0_devices, devices_num);if(ret)BUG();}/**i2c devices on bus 1*/devices_num = ARRAY_SIZE(zx29_i2c1_devices);if (devices_num){ret = i2c_register_board_info(1,zx29_i2c1_devices, devices_num);if(ret)BUG();}
}

3)i2c_add_devices里面将各个设备的信息插入到__i2c_board_list的list中;

4)在I2C驱动初始化时,例如i2c-zx29.c中,将I2C的驱动注册进platform驱动;

static struct platform_driver zx29_i2c_driver = {.probe      = zx29_i2c_probe,.remove     = zx29_i2c_remove,
#ifdef CONFIG_PM.suspend    = zx29_i2c_suspend,.resume     = zx29_i2c_resume,
#endif.driver     = {.owner  = THIS_MODULE,.name   = "zx29_i2c",.of_match_table = zx29_i2c_match,},
};static int __init i2c_adap_zx29_init(void)
{int ret;ret=platform_driver_register(&zx29_i2c_driver);if (ret<0) {printk(KERN_INFO "zx29 i2c driver register fail\n");}return ret;
}
subsys_initcall(i2c_adap_zx29_init);

5)在平台驱动的probe函数中,通过调用i2c_add_numbered_adapter()-->i2c_register_adapter()-->i2c_scan_static_board_info()-->i2c_new_device()-->device_register()完成设备的注册的。

2. 驱动的注册

1)通过调用i2c_add_driver添加对应的驱动;

#if 1
static struct i2c_driver zx234290_i2c_driver = {.driver = {.name = "zx234290",.owner = THIS_MODULE,},.probe = zx234290_i2c_probe,.remove = zx234290_i2c_remove,.id_table = zx234290_i2c_id,
};
#endifstatic int __init zx234290_i2c_init(void)
{int ret;ret = i2c_add_driver(&zx234290_i2c_driver);if (ret != 0)pr_err("Failed to register ZX234290 I2C driver: %d\n", ret);return ret;
}
/* init early so consumer devices can complete system boot */
subsys_initcall(zx234290_i2c_init);

2)I2c_add_driver()-->i2c_register_driver()-->driver_register()注册驱动,里面会进行驱动与设备的匹配,匹配成功后,会调用到驱动注册的probe函数。

SPI设备/驱动的注册

  1. 设备的注册

1)zx297520v3-devices.c中定义了需要添加的SPI设备;

static struct spi_board_info zx29_spi_devices[] = {
#ifdef CONFIG_FB_LEADT15DS26{.modalias       = "lead_t15ds26",.bus_num        = 0,.chip_select    = 0,.max_speed_hz   = 13000000,.mode           = SPI_MODE_3,.platform_data  = &lead_lcd_platform,.controller_data = &lead_lcd_chip_info,},
#endif#ifdef CONFIG_TRANSCEIVER_XN297L{.modalias       = "xn297l_tx",.bus_num        = 0,.chip_select    = 0,.max_speed_hz   = 1*1000*1000,.mode           = SPI_MODE_0,.controller_data = 25,},
#endif#ifdef CONFIG_TRANSCEIVER_XN297L{.modalias       = "xn297l_rx",.bus_num        = 1,.chip_select    = 0,.max_speed_hz   = 1*1000*1000,.mode           = SPI_MODE_0,.controller_data = 87,},
#endif
};

2)Board-zx297520v3.c中调用spi_add_devices()函数添加SPI设备;

3)spi_add_devices()中通过调用spi_register_board_info来进行设备的注册;

void __init spi_add_devices(void)
{unsigned  devices_num = ARRAY_SIZE(zx29_spi_devices);int ret = 0;printk("spi_register_board_info success,devices_num=%d\n",devices_num);if (devices_num){ret = spi_register_board_info(zx29_spi_devices, devices_num);printk("spi_register_board_info success,ret=%d\n",ret);if(ret)BUG();}
}

4)spi_register_board_info中遍历spi设备表中的所有设备,并通过spi_match_master_to_boardinfo()-->spi_new_device()-->spi_add_device()-->device_add()来进行设备的注册;

2. 驱动的注册

1)调用spi_register_driver注册spi驱动;

static int __init xn297l_init(void)
{int ret;int minor = 0;XN_DATA("register char dev for xn297l.");ret = spi_register_driver(&xn297l_spi_tx_driver);if (ret != 0){XN_ERR("failed to register xn297l_tx_spi_driver : %d", ret);return ret;}ret = spi_register_driver(&xn297l_spi_rx_driver);if (ret != 0){XN_ERR("failed to register xn297l_rx_spi_driver : %d", ret);return ret;}}
/*spi driver begin*/
static const struct spi_device_id xn297l_tx_id[] = {{"xn297l_tx", 0 },{ }
};MODULE_DEVICE_TABLE(spi, xn297l_tx_id);static struct spi_driver xn297l_spi_tx_driver = {.driver = {.name = "xn297l_tx",.owner = THIS_MODULE,},.probe = xn297l_tx_probe,.remove = __devexit_p(xn297l_tx_remove),.id_table = xn297l_tx_id,
};static const struct spi_device_id xn297l_rx_id[] = {{"xn297l_rx", 1 },{ }
};MODULE_DEVICE_TABLE(spi, xn297l_rx_id);static struct spi_driver xn297l_spi_rx_driver = {.driver = {.name = "xn297l_rx",.owner = THIS_MODULE,},.probe = xn297l_rx_probe,.remove = __devexit_p(xn297l_rx_remove),.id_table = xn297l_rx_id,
};
/*spi driver end*/

2)spi_register_driver里面会调用driver_register进行驱动的注册,里面会进行驱动与设备的匹配,匹配成功后,会调用到驱动注册的probe函数;

转载于:https://blog.51cto.com/13824435/2135671

linux设备/驱动的注册相关推荐

  1. linux 统一设备模型 pci,Linux设备驱动模型摘抄

    Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄 Linux设备驱动模型摘抄(1) Linux统一设备模型 简介 Li ...

  2. linux设备驱动——总线、设备、驱动

    http://blog.csdn.net/wh_19910525/article/details/7398051 2.6 版本内核是如何管理总线,驱动,设备之间的关系的,关于bus_type.devi ...

  3. LINUX设备驱动之设备模型一--kobject

    http://blog.csdn.net/yangzhu1982/article/details/6186016 Linux设备驱动之设备模型一kobject Eric Fang  2010-01-1 ...

  4. linux设备驱动之总线、设备、驱动

    文章转载至多个地方,网上拼凑的一篇文章,说的好听一些的话那就叫自己总结的文章,只 是多次引用啊,哈哈,哎,不管了,反正这个有利用学习进步就好,这是重要的,文章转载过来要经过一篇大脑才能成为自己的,以后 ...

  5. 【Linux开发】linux设备驱动归纳总结(七):2.内核定时器

    linux设备驱动归纳总结(七):2.内核定时器 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  6. linux设备驱动——andriod平台wlan驱动

    转自 :http://blog.chinaunix.net/space.php?uid=22278460&do=blog&cuid=2186191 linux设备驱动--andriod ...

  7. 【Linux开发】linux设备驱动归纳总结(十二):简单的数码相框

    linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  8. linux设备驱动归纳总结(六):2.分享中断号【转】

    linux设备驱动归纳总结(六):2.分享中断号 转自:http://blog.chinaunix.net/uid-25014876-id-90837.html xxxxxxxxxxxxxxxxxxx ...

  9. 如何学习linux设备驱动

    面对不断升级的内核,如何学习linux设备驱动   面对不断升级的linux内核.GNU开发工具.linux环境下的各种图形库,很多linux应用程序开发人员和linux设备驱动开发人员即兴奋,又烦躁 ...

  10. 【Linux开发】linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet...

    linux设备驱动归纳总结(六):3.中断的上半部和下半部--tasklet xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

最新文章

  1. 计算机类期刊的影响因子
  2. 清理系统垃圾的快捷方法
  3. java正则题_牛客网java编程题整理(不定期更新)
  4. 自底向上伸展树(之字形旋转+一字形旋转)
  5. 设计模式工作笔记-简单工厂场景与实现(针对接口编程的设计思想)
  6. apollo修改配置刷新bean_携程开源的分布式apollo技术整合springboot集成实现动态刷新配置
  7. session实现购物系统的简例和application实现统计页面访问次数的简例
  8. 机器学习算法的Python实现 (1):logistics回归 与 线性判别分析(LDA)
  9. python主函数怎么写_类中的Python主函数
  10. 戴尔笔记本win10系统迁移到新固态硬盘
  11. 增强版唐奇安通道策略
  12. Android开发 ANR异常的解决(应用程序无响应)
  13. EOS的trace_api_plugin插件测试
  14. 国内主流云厂商下一代云主机最大可售卖384核
  15. 无人机飞控平台ArduPilot源码入门教程 — 简介
  16. 水星MW150US完美驱动10.6.X
  17. 华为鸿蒙Matepad 11,你值得拥有的学习、娱乐、办公利器
  18. 1G2G3G4G5G:一部波澜壮阔的移动通信史
  19. 【postgresql】centos7安装postgresql-devel步骤
  20. 51单片机(二).STC89C52单片机的引脚功能

热门文章

  1. 促促促,如何确保系统扛得住 | 《尽在双11》抢鲜预览
  2. 嵌入式系统开发快速体验
  3. 1.7 非平衡数据的处理方法大全
  4. PyTorch:数据读取2 - Dataloader
  5. caffe 利用Python API 做数据输入层
  6. 8086cpu学习笔记(1):系统结构
  7. 查看Django版本号
  8. Java学习之路 之 使用技巧篇
  9. Linux内核使用的字符串转整形数和16进制数
  10. weblogic系列漏洞整理 -- 1. weblogic安装