Linux内核必备知识点 platform_driver( 二 )


2. 如何注册向注册平台驱动的步骤
1)注册设备平台_设备_寄存器
/** * platform_device_register - add a platform-level device * @pdev: platform device we re adding */int platform_device_register(struct platform_device *pdev){ device_initialize( pdev- dev); arch_setup_pdev_archdata(pdev); return platform_device_add(pdev);}2)注册驱动程序平台_驱动程序_寄存器
#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE)三、举例1. 开发步骤平台总线下驱动程序的开发步骤如下:
设备要实现的结构是:platform_device 。
1)初始化资源结构变量
2)初始化平台设备结构变量
3)向系统注册设备:platform_device_register 。
以上三个步骤必须在设备驱动加载之前,也就是platform_driver_register()执行之前完成,因为驱动注册需要匹配内核中所有注册的设备名称 。
将platform_driver_register()中的设备添加到内核最终调用的device_add函数中 。
Platform_device_add和device_add的主要区别是多了一步insert_resource(p,r),即平台资源被添加到内核中,由内核管理 。
驱动在驱动注册中,要实现的结构是:platform_driver 。
在驱动程序的初始化函数中,调用platform_driver_register()来注册platform_driver 。
需要注意的是,platform_driver和platform_device中的name变量的值必须相同[不考虑设备树,我们稍后会写一篇关于设备树的新文章] 。
这样,当注册platform_driver_register()时,当前注册的platform_driver中的name变量值将与所有注册的platform_devices中的name变量值进行比较 。只有找到同名的platform _ device才能注册成功 。
注册成功后,将调用platform_driver结构元素的探测函数指针 。
实例1这个例子比较简单,只用来测试platform_driver和platform_device能否匹配成功 。

左边是platform_device结构注册的代码,右边是platform_driver结构注册的代码 。
Platform_driver定义和注册:
1 #includelinux/init.h2 #includelinux/module.h3 #includelinux/platform_device.h4 #includelinux/ioport.h56 static int hello_probe(struct platform_device *pdev) 7 { 8 printk( match ok \n9 return 0; 10 } 11 static int hello_remove(struct platform_device *pdev) 12 { 13 printk( hello_remove \n14 return 0; 15 } 16 static struct platform_driver hello_driver = 17 { 18 .probe = hello_probe, 19 .driver.name =duang , 20 .remove = hello_remove,21 }; 22 static int hello_init(void) 23 { 24 printk( hello_init \n25 return platform_driver_register( hello_driver); 26 } 27 static void hello_exit(void) 28 { 29 printk( hello_exit \n30 platform_driver_unregister( hello_driver); 31 return; 32 } 33 MODULE_LICENSE( GPL34 module_init(hello_init); 35 module_exit(hello_exit);Platform _设备定义和注册:
1 #includelinux/init.h2 #includelinux/module.h3 #includelinux/platform_device.h4 #includelinux/ioport.h56 static void hello_release(struct device *dev) 7 { 8 return; 9 } 10 static struct platform_device hello_device = 11 { 12 .name =duang , 13 .id = -1, 14 .dev.release = hello_release, 15 }; 161718 static int hello_init(void) 19 { 20 printk( hello_init \n21 return platform_device_register( hello_device); 2223 } 24 static void hello_exit(void) 25 { 26 printk( hello_exit \n27 platform_device_unregister( hello_device); 28 return; 29 } 30 MODULE_LICENSE( GPL31 module_init(hello_init); 32 module_exit(hello_exit);本程序仅用于测试平台框架是否能成功匹配 。StructPlatform _ Device hello _ Device未设置任何硬件信息 。
Makfile
1 ifneq ($(KERNELRELEASE),)2 obj-m:=device.o driver.o 3 else 4 KDIR :=/lib/modules/$(shell uname -r)/build 5 PWD :=$(shell pwd) 6 all: 7 make -C $(KDIR) M=$(PWD) modules 8 clean: 9 rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order 10 endifmakefile可以同时将两个C文件编译成ko文件 。
编译:
编制
生成的文件:
【Linux内核必备知识点 platform_driver】
输入程序片
清空log信息sudo dmesg -c
匹配成功
实例2将硬件信息添加到platform_device结构中,可以在内核中读出 。本示例将以下信息添加到hello_device结构中:
基址寄存器0x139d0000的地址是介于空之间的0x4 。
中断号199【注意】在实际内核中,会根据HW id计算出一个新的中断号(通常当soc厂商的设备为soc时,会为每个中断源定义一个唯一的id),这个中断号会被cpu识别出来 。
设备c
struct resource res[]={ [0] ={ .start = 0x139d0000, .end = 0x139d0000 + 0x3, .flags = IORESOURCE_MEM, }, [1] ={ .start = 199, .end = 199, .flags = IORESOURCE_IRQ, }, };static struct platform_device hello_device = { .name =duang , .id = -1, .dev.release = hello_release,.num_resources = ARRAY_SIZE(res), .resource = res,};driver.c
static int hello_probe(struct platform_device *pdev) printk( match ok \nprintk( mem = %x \n ,pdev- resource[0].start); printk( irq = %d \n ,pdev- resource[1].start); //注册中断、申请内存 return 0;}再次编译,卸载第一个示例的模块,并清除日志:

推荐阅读