|
为什么有Platform_driver 前文谈到的总线驱动模型(注这个图是照着bootlin的文档绘制的):
同时,根据代码分析其基础数据结构框架关系如下(UML关系并不严谨,仅为理解方便):
可见驱动程序的模型分层有一层总线基础层,那么对于嵌入式开发领域而言,有很多SOC芯片内置了各种外设,并比如LCD,UART、audio、摄像头口等等,并没有总线。为了统一驱动架构抽象,所以引入了platform bus这个虚拟的总线模型。做过嵌入式开发的人应该都有体会,这类设备在嵌入式系统中非常多,所以在研究具体某类设备的驱动开发之前,有必要研究platform 设备的驱动模型。在强调一下这个是统一在总线驱动模型这个体系内的。 驱动模型的实现定义在./include/linux/platform_device.h中,来梳理一下这些数据结构间的关系:
.init_name = "platform",/ e3 H/ g a! V+ u0 }; {- y P/ A };
EXPORT_SYMBOL_GPL(__platform_driver_register);1 k9 {- K/ u; p1 }" L; y EXPORT_SYMBOL_GPL(__platform_driver_probe); EXPORT_SYMBOL_GPL(platform_get_resource_byname); EXPORT_SYMBOL_GPL(platform_get_irq_byname);. b2 Y1 l) b7 r N, j# i ....
设备命令以及绑定
compatible = "ti,omap3-uart"; ti,hwmods = "uart1"; clock-frequency = <48000000>;( e* u& N: t& t& G; e reg = <0x44e09000 0x2000>;! _. z1 |. N3 A+ H V! C4 b interrupts = <72>;. o8 {# z4 _& y. d status = "disabled"; }; platform_driver实例 以samsung.c 串口驱动程序为例: /*兼容匹配表*/0 N" t. M8 }& d4 b$ |static const struct platform_device_id s3c24xx_serial_driver_ids[] = {" _6 P- C2 c% u0 D, w( W5 Y {6 _( ^! S7 n' P6 x' b/ D4 [ .name = "s3c2410-uart", .driver_data = S3C2410_SERIAL_DRV_DATA, }, { .name = "s3c2412-uart",: x1 C7 i# |: p# k* X4 b; ~ .driver_data = S3C2412_SERIAL_DRV_DATA, }, { .name = "s3c2440-uart",6 c P) N- @5 p/ l+ [, s% J .driver_data = S3C2440_SERIAL_DRV_DATA,4 O8 i) B9 ?5 M% l }, {( J$ O' @! X' ^. q .name = "s3c6400-uart",( {6 w% K, r* C4 W( [' p+ Z A .driver_data = S3C6400_SERIAL_DRV_DATA, }, { .name = "s5pv210-uart",* D& V9 W" ^4 d, T K. n) j5 ? .driver_data = S5PV210_SERIAL_DRV_DATA, }, {) n! ?/ y3 y: }4 E .name = "exynos4210-uart",9 B- f. w5 ]) Y- X .driver_data = EXYNOS4210_SERIAL_DRV_DATA, }, {: h! l+ L$ k9 n/ p5 R .name = "exynos5433-uart",3 ^8 N. y& Y# U. m$ B .driver_data = EXYNOS5433_SERIAL_DRV_DATA,, x" h- o' r% G0 M1 p/ h; i }, { },: p+ U- e9 O7 I0 W }; MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids); - E2 T8 x/ ~; H+ C& ~ #ifdef CONFIG_OF4 w7 [( T1 R& K9 e; |) c A3 M /*设备树对应解析匹配表*/ static const struct of_device_id s3c24xx_uart_dt_match[] = {; z' D& k* B" \: { { .compatible = "samsung,s3c2410-uart", .data = (void *)S3C2410_SERIAL_DRV_DATA },* p0 L4 B1 j8 a3 H! V- q6 w { .compatible = "samsung,s3c2412-uart",1 Z$ s$ W- y* O; J+ r9 F# J .data = (void *)S3C2412_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c2440-uart",5 @4 g) K L" f .data = (void *)S3C2440_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c6400-uart", .data = (void *)S3C6400_SERIAL_DRV_DATA }, { .compatible = "samsung,s5pv210-uart",& H) p+ L! ]7 K% ^. o3 \/ g .data = (void *)S5PV210_SERIAL_DRV_DATA },1 j* p$ ?1 t5 h4 j9 J2 k { .compatible = "samsung,exynos4210-uart",5 s- h H+ k( T( n+ ` .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, D+ z1 n! a# ? { .compatible = "samsung,exynos5433-uart",6 C- f& ?8 `9 K# B .data = (void *)EXYNOS5433_SERIAL_DRV_DATA },% b0 W7 D- a4 d5 l5 D, W {},; |3 z3 Q) B6 q4 A- D V6 H1 d }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);4 X, R" g. |' q+ q# j #endif+ t; ^3 ]4 Y$ l- f1 H. P; z /*串口设备驱动实体*/4 u* e; O# l4 n. E0 p0 D, E2 O static struct platform_driver samsung_serial_driver = { .probe = s3c24xx_serial_probe, .remove = s3c24xx_serial_remove,1 D3 f8 ~3 B3 y. ~* b( D .id_table = s3c24xx_serial_driver_ids, .driver = {/ I4 ?2 J1 t/ h, c$ D# _: b" K) |- | .name = "samsung-uart",' j7 h$ R @% q% F& k .pm = SERIAL_SAMSUNG_PM_OPS, .of_match_table = of_match_ptr(s3c24xx_uart_dt_match),# \3 W0 i. r. m E' Q" S7 p) G8 I }, };% @ [ P" r& R8 N4 M6 R" a8 C 总结一下
对于做嵌入式Linux驱动开发,个人体会是先对总线驱动模型有一个相对清晰的概念认识会比较好,而平台设备以及平台设备驱动模型同样是衍生于总线驱动模型,这样从体系结构上就变得相对统一了。平台设备及驱动在嵌入式系统里大量应用,很多SOC内置了大量丰富的各类设备接口,这些接口往往都是通过处理器内部总线进行直接寻址的,这类型的设备几乎都是通过平台设备及驱动模型进行抽象实施的,所以深入理解平台设备/平台设备驱动模型,无疑对开发此类设备驱动程序大有助益。 / }- t8 C0 D' o2 N q* { e$ N' `" F |
微信公众号
手机版