生成设备节点-格式替换
1、注册驱动、设备将会把驱动的name、设备的name相互比较,系统自动调用platform_match()设备都有主设备号,和次设备号;
设备注册包含的结构体platform_device
struct platform_device { const char * name; // 注册设备名称 int id; // 注册设备的ID号 这两个会用的比频繁 struct device dev; u32 num_resources; struct resource * resource; const struct platform_device_id *id_entry; // MFD cell pointer struct mfd_cell *mfd_cell; // arch specific additions struct pdev_archdata archdata; };
在这里的注册设备都注册平台设备,所以在arch/arm/mach-exynos/mach-itop4412.c文件下注册,注册设备、驱动,都是注册到linux内核中,添加一段链表结点到platform平台的链表上
2、设备注册的一般流程,假设注册一个hello_ctl设备
1、打开文件 vim driver/char/Kconfig,并添加如下代码(可以搜索LEDS,并仿照LEDS的格式),并保存退出
config HELLO_CTL // 设备节点名称 tristate "Enable HELLO config" // 可编译三种选择 不编译、编译模块、编译成节点 default y // 默认编译成节点 help Enable HELLO config // 添加如上代码
2、执行make menuconfig 选择将hello_ctl编译进内核,或者编译成模块
3、打开文件 vim arch/arm/mach-exynos/mach-itop4412.c,添加如下代码,可仿照其他代码格式(可搜索LEDS)
#ifdef CONFIG_HELLO_CTL(仿照其他代码格式) struct platform_device s3c_device_hello_ctl = { .name = "hello_ctl", .id = -1, }; #endif
4、继续搜索,LEDS找到宏定义位置,仿照其格式添加如下代码,保存退出
#ifdef CONFIG_HELLO_CTL &s3c_device_hello_ctl, #endif
5、执行make zImage编译成镜像,使用fastboot烧写到板子里
6、查看注册的设备ls /sys/devices/platform/
3、驱动注册,注册hello_ctl对应的驱动
1、所需的头文件#include <linux/platform_device.h>,在vim include/linux/platform_driver.h
2、注册驱动函数extern int platform_driver_register(struct platform_driver *);
3、卸载驱动函数extern void platform_driver_unregister(struct platform_driver *);
4、注册驱动参数struct platform_driver *
struct platform_driver { int (*probe)(struct platform_device *); // 驱动初始化函数 int (*remove)(struct platform_device *); // 移除驱动 void (*shutdown)(struct platform_device *); // 关机驱动函数 int (*suspend)(struct platform_device *, pm_message_t state); // 驱动挂起 int (*resume)(struct platform_device *); // 挂起的驱动,又恢复运行 struct device_driver driver; // 结构体 const struct platform_device_id *id_table; };
4、驱动注册代码基本实现,hello_ctl驱动注册
// 驱动注册所需头文件 包含结构体,注册和卸载所需的函数 #include <linux/platform_device.h> #include <linux/module.h> #include <linux/init.h> #define DRIVER_NAME "hello_ctl" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET"); // 4、结构体函数完善 // int (*probe)(struct platform_device *); // 初始化相关动作 static int hello_probe(struct platform_device *p) { printk(KERN_EMERG "\t initialized\n"); return 0; } // int (*remove)(struct platform_device *); static int hello_remove(struct platform_device *p) { return 0; } // int (*suspend)(struct platform_device *, pm_message_t state); static int hello_suspend(struct platform_device *p) { return 0; } // int (*resume)(struct platform_device *); static int hello_resume(struct platform_device *p) { return 0; } // void (*shutdown)(struct platform_device *); static void hello_shutdown(struct platform_device *p) { } // 3、结构体数据初始化 // 注册驱动传入的结构体 struct platform_driver hello_driver = { .probe = hello_probe, // 用于初始化模块 .remove = hello_remove, // 移除模块时,执行的动作 .suspend = hello_suspend,// 模块挂起时,执行的动作 .resume = hello_resume, // 挂起的模块,恢复运行执行动作 .shutdown = hello_shutdown, .driver = { .name = DRIVER_NAME, // 驱动名称 .owner = THIS_MODULE,// 驱动所有者,THIS_MODULE宏定义 }, }; // 2、模块初始化相关实现 // 模块的入口函数 加载模块执行动作 static int hello_init(void) { int DriverState; printk(KERN_EMERG "HELLO WORLD enter!\n"); DriverState = platform_driver_register(&hello_driver); // 注册驱动 转而执行初始化动作 printk(KERN_EMERG "\tDriverState is %d\n", DriverState); // 注册驱动执行状态 return 0; } // 模块退出函数 卸载模块所执行 static void hello_exit(void) { printk(KERN_EMERG "HELLO WORLD exit!\n"); platform_driver_unregister(&hello_driver); // 卸载驱动函数 } //1、 入口函数module_nint module_init(hello_init); module_exit(hello_exit);
5、上面注册设备,设备注册需要编译到镜像中,再将镜像烧写进内核中;module方式注册设备则不需要重新编译镜像;
6、以module方式注册设备
#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #define DRIVER_NAME "hello_ctl" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET"); static void leds_release(struct device *dev) { printk("leds_release"); } struct platform_device platform_device_hello = { .name = "my_code_led", .id = -1, .dev = { .release = leds_release, }, }; static int hello_init(void) { printk(KERN_EMERG "HELLO WORLD enter!\n"); platform_device_register(&platform_device_hello); return 0; } static void hello_exit(void) { printk(KERN_EMERG "HELLO WORLD exit!\n"); platform_device_unregister(&platform_device_hello); } //1、 入口函数module_nint module_init(hello_init); module_exit(hello_exit);
7、在调试时候,想要获取注册设备驱动的信息
// 驱动注册所需头文件 包含结构体,注册和卸载所需的函数 #include <linux/platform_device.h> #include <linux/module.h> #include <linux/init.h> #define DRIVER_NAME "my_code_led" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET"); // int (*probe)(struct platform_device *); static int hello_probe(struct platform_device *pdv) { printk(KERN_EMERG "\t initialized\n"); printk("pdv->name is %s\n",pdv->name); printk("pdv->id is %d\n",pdv->id); pdv->dev.release(&pdv->dev); return 0; } // int (*remove)(struct platform_device *); static int hello_remove(struct platform_device *p) { return 0; } // int (*suspend)(struct platform_device *, pm_message_t state); static int hello_suspend(struct platform_device *p) { return 0; } // int (*resume)(struct platform_device *); static int hello_resume(struct platform_device *p) { return 0; } // void (*shutdown)(struct platform_device *); static void hello_shutdown(struct platform_device *p) { } // 注册驱动传入的结构体 struct platform_driver hello_driver = { .probe = hello_probe, .remove = hello_remove, .suspend = hello_suspend, .resume = hello_resume, .shutdown = hello_shutdown, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, }, }; static int hello_init(void) { int DriverState; printk(KERN_EMERG "HELLO WORLD enter!\n"); DriverState = platform_driver_register(&hello_driver); // 注册驱动 转而执行初始化动作 printk(KERN_EMERG "\tDriverState is %d\n", DriverState); return 0; } static void hello_exit(void) { printk(KERN_EMERG "HELLO WORLD exit!\n"); platform_driver_unregister(&hello_driver); // 卸载驱动函数 } //1、 入口函数module_nint module_init(hello_init); module_exit(hello_exit);

浙公网安备 33010602011771号