linux设备/驱动的注册
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_SPIFC static 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, }; #endifstruct 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_devicesstatic 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, }; #endifstatic 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 };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; retplatform_driver_register(zx29_i2c_driver); if (ret0) { 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, }; #endif static 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函数