module_init调用过程


内核中很多模块都是通过module_init加载的
在头文件 init.h(<linux/init.h>)中对module_init有如下定义
#define module_init(x)  __initcall(x)
#define __initcall(fn)    device_initcall(fn)
#define device_initcall(fn)  __define_initcall("6",fn,6)
#define __define_initcall(level, fn, id) \
           static initcall_t __initcall_##fn##id__used\
          __attribute__((__section__(".initcall"level".init"))) = fn
根据宏的定义,如果调用module_init(pgio_init),实际上等于
static initcall_t __initcall_gpio_init6__used __attribute__((__section__(".initcall6.init"))) = gpio
initcall_t 为一函数指针类型
typedef int (*initcall_t)(void)
这个函数指针变量比较特殊的地方在于,变量放在了一个名为".initcall6.init"节中。
那又是如何调用起来的呢?结合vmlinux.lds.h中的描述


.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
   __initcall_start = .;
   *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
   __initcall_end = .;
   }
以及do_initcalls:
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++)
do_one_initcall(*call);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
不难理解module_init中的初始化函数何时被调用了。
系统启动过程中  start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()
这里,__initcal_start 指向.initcall.init的节首,而__initcall_end指向.initcall.init的节尾

`module_init()` 是Linux内核中用于注册初始化函数的宏,该函数在内核模块被加载时调用。`dma_init()` 是在 `module_init()` 中指定的初始化函数,它是在内核模块加载时执行的入口点。 如果你想在 `dma_init()` 函数中调用设备,通常需要执行以下几个步骤: 1. 获取设备资源:在 `dma_init()` 中,首先需要通过平台设备或者总线驱动框架获取到设备的资源,这可能包括I/O端口、内存映射、中断号等。 2. 初始化DMA相关结构:根据获取的设备资源,初始化DMA传输相关的数据结构,比如分配并初始化DMA描述符、设置DMA传输参数等。 3. 注册设备:如果需要将设备添加到内核的设备模型中,可能还需要调用 `device_register()` 函数来注册设备。 4. 配置和启用DMA:配置DMA引擎,设置传输方向、缓冲区地址、传输大小等参数,并启动DMA传输。 以下是一个简化的示例代码,展示了如何在 `module_init()` 中调用设备: ```c #include <linux/module.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> static int dma_init(void) { struct platform_device *pdev; struct resource *res; int ret; // 假设你已经通过某种方式得到了平台设备的指针 pdev pdev = platform_device_register_simple("my_dma_device", -1, NULL, 0); if (!pdev) { printk(KERN_ERR "Failed to register platform device\n"); return -ENODEV; } // 获取设备资源,假设DMA相关的资源是第一个资源 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { printk(KERN_ERR "Failed to get memory resource for DMA\n"); ret = -ENODEV; goto err_remove_device; } // 其他初始化代码,包括DMA内存分配、配置等 // 如果需要注册设备到内核设备模型 ret = device_register(&pdev->dev); if (ret) { printk(KERN_ERR "Failed to register device\n"); goto err_remove_device; } // 配置和启用DMA引擎 return 0; err_remove_device: platform_device_unregister(pdev); return ret; } module_init(dma_init); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple DMA initialization example"); ``` 在上述代码中,我们通过 `platform_device_register_simple` 注册了一个简单的平台设备,然后通过 `platform_get_resource` 获取了设备的资源。接着,根据需要执行了设备注册和其他初始化操作。请注意,实际代码会根据具体的硬件和需求有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值