码迷,mamicode.com
首页 > 其他好文 > 详细

二、设备和驱动的注册时序

时间:2014-05-12 01:20:15      阅读:338      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   class   code   tar   

一、引言

      在platform驱动程序框架中,我们了解到,platform设备和驱动最终会挂载在platform总线上,platform总线会对设备和驱动进行匹配。那么设备和驱动是怎么注册到platform框架中去的,其先后顺序又是怎样的?

二、设备和驱动注册

platform_device_register注册设备

bubuko.com,布布扣
 1 /**
 2  * platform_device_register - add a platform-level device
 3  * @pdev: platform device we‘re adding
 4  */
 5 int platform_device_register(struct platform_device *pdev)
 6 {
 7     device_initialize(&pdev->dev);
 8     return platform_device_add(pdev);
 9 }
10 EXPORT_SYMBOL_GPL(platform_device_register);
platform_device_register

platform_driver_register注册驱动

bubuko.com,布布扣
 1 /**
 2  * platform_driver_register
 3  * @drv: platform driver structure
 4  */
 5 int platform_driver_register(struct platform_driver *drv)
 6 {
 7     drv->driver.bus = &platform_bus_type;
 8     if (drv->probe)
 9         drv->driver.probe = platform_drv_probe;
10     if (drv->remove)
11         drv->driver.remove = platform_drv_remove;
12     if (drv->shutdown)
13         drv->driver.shutdown = platform_drv_shutdown;
14 
15     return driver_register(&drv->driver);
16 }
17 EXPORT_SYMBOL_GPL(platform_driver_register);
platform_driver_register

设备注册sample

bubuko.com,布布扣
 1 static struct plat_serial8250_port serial_platform_data[] = {
 2     {
 3         .membase    = OMAP1_IO_ADDRESS(OMAP_UART1_BASE),
 4         .mapbase    = OMAP_UART1_BASE,
 5         .irq        = INT_UART1,
 6         .flags        = UPF_BOOT_AUTOCONF,
 7         .iotype        = UPIO_MEM,
 8         .regshift    = 2,
 9         .uartclk    = OMAP16XX_BASE_BAUD * 16,
10     },
11     {
12         .membase    = OMAP1_IO_ADDRESS(OMAP_UART2_BASE),
13         .mapbase    = OMAP_UART2_BASE,
14         .irq        = INT_UART2,
15         .flags        = UPF_BOOT_AUTOCONF,
16         .iotype        = UPIO_MEM,
17         .regshift    = 2,
18         .uartclk    = OMAP16XX_BASE_BAUD * 16,
19     },
20     {
21         .membase    = OMAP1_IO_ADDRESS(OMAP_UART3_BASE),
22         .mapbase    = OMAP_UART3_BASE,
23         .irq        = INT_UART3,
24         .flags        = UPF_BOOT_AUTOCONF,
25         .iotype        = UPIO_MEM,
26         .regshift    = 2,
27         .uartclk    = OMAP16XX_BASE_BAUD * 16,
28     },
29     { },
30 };
31 
32 static struct platform_device serial_device = {
33     .name            = "serial8250",
34     .id            = PLAT8250_DEV_PLATFORM,
35     .dev            = {
36         .platform_data    = serial_platform_data,
37     },
38 };
39 
40 static int __init omap_init(void)
41 {
42     return platform_device_register(&serial_device);
43 }
44 arch_initcall(omap_init);
device register sample

驱动注册sample

bubuko.com,布布扣
 1 static int __init serial_txx9_init(void)
 2 {
 3     int ret;
 4 
 5      printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
 6 
 7     ret = uart_register_driver(&serial_txx9_reg);
 8     if (ret)
 9         goto out;
10 
11     serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
12     if (!serial_txx9_plat_devs) {
13         ret = -ENOMEM;
14         goto unreg_uart_drv;
15     }
16 
17     ret = platform_device_add(serial_txx9_plat_devs);
18     if (ret)
19         goto put_dev;
20 
21     serial_txx9_register_ports(&serial_txx9_reg,
22                    &serial_txx9_plat_devs->dev);
23 
24     ret = platform_driver_register(&serial_txx9_plat_driver);
25     if (ret)
26         goto del_dev;
27 
28 #ifdef ENABLE_SERIAL_TXX9_PCI
29     ret = pci_register_driver(&serial_txx9_pci_driver);
30 #endif
31     if (ret == 0)
32         goto out;
33 
34  del_dev:
35     platform_device_del(serial_txx9_plat_devs);
36  put_dev:
37     platform_device_put(serial_txx9_plat_devs);
38  unreg_uart_drv:
39     uart_unregister_driver(&serial_txx9_reg);
40  out:
41     return ret;
42 }
43 
44 module_init(serial_txx9_init);
driver register sample

设备注册时定义了该设备用到的一些硬件资源,如中断线,内存地址范围,稳压电源等。

驱动注册时定义了probe、remove等函数,在probe阶段,会做一些初始化动作,如将中断处理函数关联到设备的中断线上。

由此看来,先注册设备再注册驱动。

三、init函数调用时序

device初始化用到了宏arch_initcall,driver初始化用到了宏module_init。

在include\linux\init.h中定义了arch_initcall,其根据level标示,在load阶段会按顺序加载。

bubuko.com,布布扣
 1 /* initcalls are now grouped by functionality into separate 
 2  * subsections. Ordering inside the subsections is determined
 3  * by link order. 
 4  * For backwards compatibility, initcall() puts the call in 
 5  * the device init subsection.
 6  *
 7  * The `id‘ arg to __define_initcall() is needed so that multiple initcalls
 8  * can point at the same handler without causing duplicate-symbol build errors.
 9  */
10 
11 #define __define_initcall(level,fn,id) 12     static initcall_t __initcall_##fn##id __used 13     __attribute__((__section__(".initcall" level ".init"))) = fn
__define_initcall

arch_initcall的调用顺序是3。

bubuko.com,布布扣
 1 #define core_initcall(fn)        __define_initcall("1",fn,1)
 2 #define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)
 3 #define postcore_initcall(fn)        __define_initcall("2",fn,2)
 4 #define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
 5 #define arch_initcall(fn)        __define_initcall("3",fn,3)
 6 #define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)
 7 #define subsys_initcall(fn)        __define_initcall("4",fn,4)
 8 #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
 9 #define fs_initcall(fn)            __define_initcall("5",fn,5)
10 #define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
11 #define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)
12 #define device_initcall(fn)        __define_initcall("6",fn,6)
13 #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
14 #define late_initcall(fn)        __define_initcall("7",fn,7)
15 #define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)
arch_initcall

arch_initcall和module_init宏最终都会扩展成__define_initcall,将函数装载到__initcall段中,其根据level在此段中排序。

vmlinux的load脚本,其中有initcall段定义。

bubuko.com,布布扣
  1 /* ld script to make ARM Linux kernel
  2  * taken from the i386 version by Russell King
  3  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  4  */
  5 
  6 #include <asm-generic/vmlinux.lds.h>
  7 #include <asm/thread_info.h>
  8 #include <asm/memory.h>
  9 #include <asm/page.h>
 10     
 11 OUTPUT_ARCH(arm)
 12 ENTRY(stext)
 13 
 14 #ifndef __ARMEB__
 15 jiffies = jiffies_64;
 16 #else
 17 jiffies = jiffies_64 + 4;
 18 #endif
 19 
 20 SECTIONS
 21 {
 22 #ifdef CONFIG_XIP_KERNEL
 23     . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
 24 #else
 25     . = PAGE_OFFSET + TEXT_OFFSET;
 26 #endif
 27     .text.head : {
 28         _stext = .;
 29         _sinittext = .;
 30         *(.text.head)
 31     }
 32 
 33     .init : {            /* Init code and data        */
 34             INIT_TEXT
 35         _einittext = .;
 36         __proc_info_begin = .;
 37             *(.proc.info.init)
 38         __proc_info_end = .;
 39         __arch_info_begin = .;
 40             *(.arch.info.init)
 41         __arch_info_end = .;
 42         __tagtable_begin = .;
 43             *(.taglist.init)
 44         __tagtable_end = .;
 45         . = ALIGN(16);
 46         __setup_start = .;
 47             *(.init.setup)
 48         __setup_end = .;
 49         __early_begin = .;
 50             *(.early_param.init)
 51         __early_end = .;
 52         __initcall_start = .;
 53             INITCALLS
 54         __initcall_end = .;
 55         __con_initcall_start = .;
 56             *(.con_initcall.init)
 57         __con_initcall_end = .;
 58         __security_initcall_start = .;
 59             *(.security_initcall.init)
 60         __security_initcall_end = .;
 61 #ifdef CONFIG_BLK_DEV_INITRD
 62         . = ALIGN(32);
 63         __initramfs_start = .;
 64             usr/built-in.o(.init.ramfs)
 65         __initramfs_end = .;
 66 #endif
 67         . = ALIGN(PAGE_SIZE);
 68         __per_cpu_load = .;
 69         __per_cpu_start = .;
 70             *(.data.percpu.page_aligned)
 71             *(.data.percpu)
 72             *(.data.percpu.shared_aligned)
 73         __per_cpu_end = .;
 74 #ifndef CONFIG_XIP_KERNEL
 75         __init_begin = _stext;
 76         INIT_DATA
 77         . = ALIGN(PAGE_SIZE);
 78         __init_end = .;
 79 #endif
 80     }
 81 
 82     /DISCARD/ : {            /* Exit code and data        */
 83         EXIT_TEXT
 84         EXIT_DATA
 85         *(.exitcall.exit)
 86         *(.discard)
 87         *(.ARM.exidx.exit.text)
 88         *(.ARM.extab.exit.text)
 89 #ifndef CONFIG_HOTPLUG_CPU
 90         *(.ARM.exidx.cpuexit.text)
 91         *(.ARM.extab.cpuexit.text)
 92 #endif
 93 #ifndef CONFIG_HOTPLUG
 94         *(.ARM.exidx.devexit.text)
 95         *(.ARM.extab.devexit.text)
 96 #endif
 97 #ifndef CONFIG_MMU
 98         *(.fixup)
 99         *(__ex_table)
100 #endif
101     }
102 
103     .text : {            /* Real text segment        */
104         _text = .;        /* Text and read-only data    */
105             __exception_text_start = .;
106             *(.exception.text)
107             __exception_text_end = .;
108             TEXT_TEXT
109             SCHED_TEXT
110             LOCK_TEXT
111             KPROBES_TEXT
112 #ifdef CONFIG_MMU
113             *(.fixup)
114 #endif
115             *(.gnu.warning)
116             *(.rodata)
117             *(.rodata.*)
118             *(.glue_7)
119             *(.glue_7t)
120         *(.got)            /* Global offset table        */
121     }
122 
123     RO_DATA(PAGE_SIZE)
124 
125     _etext = .;            /* End of text and rodata section */
126 
127 #ifdef CONFIG_ARM_UNWIND
128     /*
129      * Stack unwinding tables
130      */
131     . = ALIGN(8);
132     .ARM.unwind_idx : {
133         __start_unwind_idx = .;
134         *(.ARM.exidx*)
135         __stop_unwind_idx = .;
136     }
137     .ARM.unwind_tab : {
138         __start_unwind_tab = .;
139         *(.ARM.extab*)
140         __stop_unwind_tab = .;
141     }
142 #endif
143 
144 #ifdef CONFIG_XIP_KERNEL
145     __data_loc = ALIGN(4);        /* location in binary */
146     . = PAGE_OFFSET + TEXT_OFFSET;
147 #else
148     . = ALIGN(THREAD_SIZE);
149     __data_loc = .;
150 #endif
151 
152     .data : AT(__data_loc) {
153         _data = .;        /* address in memory */
154         _sdata = .;
155 
156         /*
157          * first, the init task union, aligned
158          * to an 8192 byte boundary.
159          */
160         *(.data.init_task)
161 
162 #ifdef CONFIG_XIP_KERNEL
163         . = ALIGN(PAGE_SIZE);
164         __init_begin = .;
165         INIT_DATA
166         . = ALIGN(PAGE_SIZE);
167         __init_end = .;
168 #endif
169 
170         . = ALIGN(PAGE_SIZE);
171         __nosave_begin = .;
172         *(.data.nosave)
173         . = ALIGN(PAGE_SIZE);
174         __nosave_end = .;
175 
176         /*
177          * then the cacheline aligned data
178          */
179         . = ALIGN(32);
180         *(.data.cacheline_aligned)
181 
182         /*
183          * The exception fixup table (might need resorting at runtime)
184          */
185         . = ALIGN(32);
186         __start___ex_table = .;
187 #ifdef CONFIG_MMU
188         *(__ex_table)
189 #endif
190         __stop___ex_table = .;
191 
192         /*
193          * and the usual data section
194          */
195         DATA_DATA
196         CONSTRUCTORS
197 
198         _edata = .;
199     }
200     _edata_loc = __data_loc + SIZEOF(.data);
201 
202 #ifdef CONFIG_HAVE_TCM
203         /*
204      * We align everything to a page boundary so we can
205      * free it after init has commenced and TCM contents have
206      * been copied to its destination.
207      */
208     .tcm_start : {
209         . = ALIGN(PAGE_SIZE);
210         __tcm_start = .;
211         __itcm_start = .;
212     }
213 
214     /*
215      * Link these to the ITCM RAM
216      * Put VMA to the TCM address and LMA to the common RAM
217      * and we‘ll upload the contents from RAM to TCM and free
218      * the used RAM after that.
219      */
220     .text_itcm ITCM_OFFSET : AT(__itcm_start)
221     {
222         __sitcm_text = .;
223         *(.tcm.text)
224         *(.tcm.rodata)
225         . = ALIGN(4);
226         __eitcm_text = .;
227     }
228 
229     /*
230      * Reset the dot pointer, this is needed to create the
231      * relative __dtcm_start below (to be used as extern in code).
232      */
233     . = ADDR(.tcm_start) + SIZEOF(.tcm_start) + SIZEOF(.text_itcm);
234 
235     .dtcm_start : {
236         __dtcm_start = .;
237     }
238 
239     /* TODO: add remainder of ITCM as well, that can be used for data! */
240     .data_dtcm DTCM_OFFSET : AT(__dtcm_start)
241     {
242         . = ALIGN(4);
243         __sdtcm_data = .;
244         *(.tcm.data)
245         . = ALIGN(4);
246         __edtcm_data = .;
247     }
248 
249     /* Reset the dot pointer or the linker gets confused */
250     . = ADDR(.dtcm_start) + SIZEOF(.data_dtcm);
251 
252     /* End marker for freeing TCM copy in linked object */
253     .tcm_end : AT(ADDR(.dtcm_start) + SIZEOF(.data_dtcm)){
254         . = ALIGN(PAGE_SIZE);
255         __tcm_end = .;
256     }
257 #endif
258 
259     .bss : {
260         __bss_start = .;    /* BSS                */
261         *(.bss)
262         *(COMMON)
263         __bss_stop = .;
264         _end = .;
265     }
266                     /* Stabs debugging sections.    */
267     .stab 0 : { *(.stab) }
268     .stabstr 0 : { *(.stabstr) }
269     .stab.excl 0 : { *(.stab.excl) }
270     .stab.exclstr 0 : { *(.stab.exclstr) }
271     .stab.index 0 : { *(.stab.index) }
272     .stab.indexstr 0 : { *(.stab.indexstr) }
273     .comment 0 : { *(.comment) }
274 }
275 
276 /*
277  * These must never be empty
278  * If you have to comment these two assert statements out, your
279  * binutils is too old (for other reasons as well)
280  */
281 ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
282 ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
vmlinux.lds

在do_initcalls中会从initcall段的函数地址开始,依次调用此段中的函数,设备和驱动的初始化即在此被调用。

调用顺序:

start_kernel->reset_init->kernel_init->do_basic_setup->do_initcalls

bubuko.com,布布扣
 1 extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
 2 
 3 static void __init do_initcalls(void)
 4 {
 5     initcall_t *call;
 6 
 7     for (call = __early_initcall_end; call < __initcall_end; call++)
 8         do_one_initcall(*call);
 9 
10     /* Make sure there is no pending stuff from the initcall sequence */
11     flush_scheduled_work();
12 }
do_initcalls

 

 

 

 

 

 

 

 

 

 

 

二、设备和驱动的注册时序,布布扣,bubuko.com

二、设备和驱动的注册时序

标签:des   style   blog   class   code   tar   

原文地址:http://www.cnblogs.com/connectfuture/p/3721352.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!