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_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, }; #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; 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, }; #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函数;