免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9308 | 回复: 10
打印 上一主题 下一主题

怎么确定驱动加载顺序??? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-09-24 16:11 |只看该作者 |倒序浏览
5可用积分
我碰到一个问题,板子的touch需要使用I2C进行通讯,但touch驱动在I2C驱动前加载了,使用得touch初始化就报错。请问如何设置驱动加载顺序,这些驱动都是编译到内核的里。

最佳答案

查看完整内容

内核启动的时候,各个驱动初始化的工作在文件init/main.c中的do_basic_setup()函数中做.------------------------------------------------------------------------------------------------------static void __init do_basic_setup(void){ /* drivers will send hotplug events */ init_workqueues(); usermodehelper_init(); driver_init();#ifdef CONFIG_SYSCTL sysctl_init();#endif /* Networking initialization needs a pr ...

论坛徽章:
0
2 [报告]
发表于 2007-09-24 16:11 |只看该作者
内核启动的时候,各个驱动初始化的工作在文件init/main.c中的do_basic_setup()函数中做.
------------------------------------------------------------------------------------------------------
static void __init do_basic_setup(void)
{
        /* drivers will send hotplug events */
        init_workqueues();
        usermodehelper_init();
        driver_init();

#ifdef CONFIG_SYSCTL
        sysctl_init();
#endif

        /* Networking initialization needs a process context */
        sock_init();

        do_initcalls();
}
------------------------------------------------------------------------------------------------------       
其中的driver_init()做一些核心的初始化,看看代码就明白了.
相应的驱动程序的初始化在do_initcalls()中做.
------------------------------------------------------------------------------------------------------       
static void __init do_initcalls(void)
{
        initcall_t *call;
        int count = preempt_count();

        for (call = __initcall_start; call < __initcall_end; call++) {
                char *msg;

                if (initcall_debug) {
                        printk(KERN_DEBUG "Calling initcall 0x%p", *call);
                        print_fn_descriptor_symbol(": %s()", (unsigned long) *call);
                        printk("\n");
                }

                (*call)();

                msg = NULL;
                if (preempt_count() != count) {
                        msg = "preemption imbalance";
                        preempt_count() = count;
                }
                if (irqs_disabled()) {
                        msg = "disabled interrupts";
                        local_irq_enable();
                }
                if (msg) {
                        printk(KERN_WARNING "error in initcall at 0x%p: "
                                "returned with %s\n", *call, msg);
                }
        }

        /* Make sure there is no pending stuff from the initcall sequence */
        flush_scheduled_work();
}
------------------------------------------------------------------------------------------------------       
这个__initcall_start是在文件        arch/xxx/kernel/vmlinux.lds.S (其中的xxx 是你的体系结构的名称,例如i386)
这个文件是内核ld的时候使用的.其中定义了各个sectioin,看看就明白了。
在这个文件中有个.initcall.init, 代码如下:
------------------------------------------------------------------------------------------------------       
__initcall_start = .;
  .initcall.init : {
        *(.initcall1.init)
        *(.initcall2.init)
        *(.initcall3.init)
        *(.initcall4.init)
        *(.initcall5.init)
        *(.initcall6.init)
        *(.initcall7.init)
  }
------------------------------------------------------------------------------------------------------       

这里有7个初始化的优先级,内核会按照这个优先级的顺序依次加载.
这些优先级是在文件include/linux/init.h 中定义的. 你注意一下宏 __define_initcall的实现就明白了.
相关代码如下:


#define __define_initcall(level,fn) \
        static initcall_t __initcall_##fn __attribute_used__ \
        __attribute__((__section__(".initcall" level ".init"))) = fn

#define core_initcall(fn)                __define_initcall("1",fn)
#define postcore_initcall(fn)                __define_initcall("2",fn)
#define arch_initcall(fn)                __define_initcall("3",fn)
#define subsys_initcall(fn)                __define_initcall("4",fn)
#define fs_initcall(fn)                        __define_initcall("5",fn)
#define device_initcall(fn)                __define_initcall("6",fn)
#define late_initcall(fn)                __define_initcall("7",fn)


我们可以看到,我们经常写的设备驱动程序中常用的module_init其实就是对应了优先级6:
#define __initcall(fn) device_initcall(fn)

#define module_init(x)        __initcall(x);

____________

不过我怎么觉的你的问题不是由于加载顺序造成的?猜测而已.
我也写过touchscreen 的驱动, 感觉touchscreen 用serio的多一些,也有用i2c的.
你应该在自己的驱动里去封状这些的结构,一个input_dev结构,一个是serio(或着是i2c_driver),然后去控制加载顺序.
module_init 中应该是注册i2c_driver, 然后在attach_adapter的时候再注册input_dev.

论坛徽章:
0
3 [报告]
发表于 2007-09-24 16:44 |只看该作者
modprobe试试

论坛徽章:
0
4 [报告]
发表于 2007-09-24 19:03 |只看该作者
楼主既然编译到内核里了,modprobe还能用吗?

论坛徽章:
0
5 [报告]
发表于 2007-09-24 21:44 |只看该作者
这个问题应该不难吧,,,
改内核初始化驱动的顺序就好了。我的板子uclinux2.6用下面这个函数加载的。
platform_add_devices(devices, ARRAY_SIZE(devices));
一般驱动都在下面的数组里,换下顺序就好了吧!!!
static struct platform_device *devices[] __initdata = {
        &pcmcia_cf_device,
        &hcd_device,
        &.....
}

我想linux都是一样的啦

论坛徽章:
0
6 [报告]
发表于 2007-09-25 15:57 |只看该作者

回复 #4 elvispl 的帖子

我看了,但不行呀!
源码代如:

static struct platform_device *devices[] __initdata = {
        &i2c_device,
        &mhn_pmic_device,
        &mhn_fv_device,
        &pxafb_device,
        &ffuart_device,
        &btuart_device,
        &udc_device,
        &stuart_device,
        &nand_device,
        &camera_device,
        &sibley_device,
        &w1_device,
        &rtc_device,
        &mmc1_device,
        &ohci_hcd_pxa_device,
        &mhn_kp_device,
        &gcu_device,
        &lt_audio_device,
        &lt_ts_device, //此为touch驱动
        &lt_charger_device,
};
并且我还改了相应的设备结构中的ID值:
static struct platform_device lt_ts_device = {
        .name                = "lt_ts",
        .id                = 2, //原来为-1
};
结果还是:
platform bus: touch driver!
[micco i2c]micco_write:g_client is null
[micco i2c]micco_write:g_client is null
[micco i2c]micco_write:g_client is null
[micco i2c]micco_write:g_client is null
此时i2c的驱动还没加载,另外,我特意以kconfig文件中将touch项的depend 加入了i2c

论坛徽章:
0
7 [报告]
发表于 2007-09-26 15:59 |只看该作者
大伙帮下忙呀。。。我试了很多方法都不行,把它编译成模块也不行。提示很多函数没定义

论坛徽章:
0
8 [报告]
发表于 2007-09-26 22:47 |只看该作者
模块内符号没定义是没有问题的,extern就可以了,加载时内核可以动态链接。

[ 本帖最后由 mjdcl 于 2007-9-26 22:48 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2007-09-27 08:57 |只看该作者
我已改成模块方式,但我还是想知道怎么调整驱动加载的顺序。。。

论坛徽章:
3
CU大牛徽章
日期:2013-03-13 15:32:35CU大牛徽章
日期:2013-03-13 15:38:15CU大牛徽章
日期:2013-03-13 15:38:52
10 [报告]
发表于 2007-09-30 23:50 |只看该作者
学习了,
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP