|
为什么有Platform_driver 前文谈到的总线驱动模型(注这个图是照着bootlin的文档绘制的):
同时,根据代码分析其基础数据结构框架关系如下(UML关系并不严谨,仅为理解方便):
可见驱动程序的模型分层有一层总线基础层,那么对于嵌入式开发领域而言,有很多SOC芯片内置了各种外设,并比如LCD,UART、audio、摄像头口等等,并没有总线。为了统一驱动架构抽象,所以引入了platform bus这个虚拟的总线模型。做过嵌入式开发的人应该都有体会,这类设备在嵌入式系统中非常多,所以在研究具体某类设备的驱动开发之前,有必要研究platform 设备的驱动模型。在强调一下这个是统一在总线驱动模型这个体系内的。 驱动模型的实现定义在./include/linux/platform_device.h中,来梳理一下这些数据结构间的关系:
.init_name = "platform", };- y4 C E5 t1 e0 T9 x
EXPORT_SYMBOL_GPL(__platform_driver_register);) j* v5 m3 ~" L EXPORT_SYMBOL_GPL(__platform_driver_probe); EXPORT_SYMBOL_GPL(platform_get_resource_byname);% y, L$ V1 n1 x5 ^7 X, P7 W EXPORT_SYMBOL_GPL(platform_get_irq_byname);* z& X8 }( t4 m7 y1 ~4 Z6 u# m ....( i1 f$ Q- ^. i, d3 V
设备命令以及绑定
compatible = "ti,omap3-uart";. w0 q" \$ P* D9 i1 ] ti,hwmods = "uart1";/ i1 z9 s2 E7 E4 l$ \7 J clock-frequency = <48000000>;9 Z8 K N2 ^4 n3 c' a reg = <0x44e09000 0x2000>; interrupts = <72>; status = "disabled"; }; g- ~) r- ]% z. i3 g9 `/ ~9 q platform_driver实例 以samsung.c 串口驱动程序为例: /*兼容匹配表*/static const struct platform_device_id s3c24xx_serial_driver_ids[] = {. p% H: n6 \0 i, z- w+ l { .name = "s3c2410-uart", .driver_data = S3C2410_SERIAL_DRV_DATA, }, { .name = "s3c2412-uart",( @; h+ F$ m) u4 o5 S .driver_data = S3C2412_SERIAL_DRV_DATA,# i9 W1 J1 ~& X$ V1 G$ {0 G }, { .name = "s3c2440-uart",' o' W- w' W! c# m7 L .driver_data = S3C2440_SERIAL_DRV_DATA, }, { .name = "s3c6400-uart", .driver_data = S3C6400_SERIAL_DRV_DATA, }, {! S- I" Q9 R6 K/ n5 v# E .name = "s5pv210-uart", .driver_data = S5PV210_SERIAL_DRV_DATA, }, { .name = "exynos4210-uart",& ?/ ~$ o6 I. | .driver_data = EXYNOS4210_SERIAL_DRV_DATA, }, { .name = "exynos5433-uart",4 B4 B1 t5 h- m+ b, X .driver_data = EXYNOS5433_SERIAL_DRV_DATA,- z: Q, l; P1 s- L6 H3 l },- ?4 c e* k) b" V# b" l { }, };, ^- I' b1 G9 Y8 E9 r MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);5 S/ }- k8 J/ R& v5 Q- p #ifdef CONFIG_OF6 i" W, C, w, c+ J% I; E4 \ /*设备树对应解析匹配表*/1 X5 r+ C b& r static const struct of_device_id s3c24xx_uart_dt_match[] = { { .compatible = "samsung,s3c2410-uart",* R+ `, d% ]; j. ^ .data = (void *)S3C2410_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c2412-uart",% n; V: M* B' Y% o( w .data = (void *)S3C2412_SERIAL_DRV_DATA },6 k- w" V& I, s { .compatible = "samsung,s3c2440-uart", .data = (void *)S3C2440_SERIAL_DRV_DATA },' B" W9 K, L; y+ w8 S. d; r { .compatible = "samsung,s3c6400-uart", .data = (void *)S3C6400_SERIAL_DRV_DATA }, { .compatible = "samsung,s5pv210-uart", .data = (void *)S5PV210_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos4210-uart",; {3 s8 d/ R; m; u3 k$ k0 V) { .data = (void *)EXYNOS4210_SERIAL_DRV_DATA },( \# P: q/ O( m1 G4 r' D { .compatible = "samsung,exynos5433-uart", .data = (void *)EXYNOS5433_SERIAL_DRV_DATA },; b( Q5 z Z8 {: R {},: h, N, y3 u! A };; F" i) F5 \9 j+ D! v" J& P MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);2 j- N* C, d4 A* q [ #endif% e$ G' f' C% {/ J /*串口设备驱动实体*/7 A# E. R" t$ v9 _% h' m static struct platform_driver samsung_serial_driver = {: K$ o/ \0 y F* Q0 x .probe = s3c24xx_serial_probe,4 O" q8 s' B. K P0 i .remove = s3c24xx_serial_remove,$ r# c6 X- ~& s/ T2 J .id_table = s3c24xx_serial_driver_ids,( |+ ?6 H% K- H5 k3 { .driver = { .name = "samsung-uart",4 G5 V4 j6 \' v" G .pm = SERIAL_SAMSUNG_PM_OPS, .of_match_table = of_match_ptr(s3c24xx_uart_dt_match),& O) r% @! |* e5 U# o1 T; S }, };4 @* |9 d' m" P8 T) U1 ~ 总结一下
对于做嵌入式Linux驱动开发,个人体会是先对总线驱动模型有一个相对清晰的概念认识会比较好,而平台设备以及平台设备驱动模型同样是衍生于总线驱动模型,这样从体系结构上就变得相对统一了。平台设备及驱动在嵌入式系统里大量应用,很多SOC内置了大量丰富的各类设备接口,这些接口往往都是通过处理器内部总线进行直接寻址的,这类型的设备几乎都是通过平台设备及驱动模型进行抽象实施的,所以深入理解平台设备/平台设备驱动模型,无疑对开发此类设备驱动程序大有助益。 " [6 p7 r( @8 B |
微信公众号
手机版