LED驱动总线设备驱动模型
匹配规则
最先比较:platform_device. driver_override和platform_driver.driver.name
可以设置platform_device的driver_override,强制选择某个platform_driver。
然后比较:platform_device. name和platform_driver.id_table[i].name
Platform_driver.id_table是“platform_device_id”指针,表示该drv支持若干个device,它里面列出了各个device的{.name, .driver_data},其中的“name”表示该drv支持的设备的名字,driver_data是些提供给该device的私有数据。
最后比较:platform_device.name和platform_driver.driver.name
platform_driver.id_table可能为空,
这时可以根据platform_driver.driver.name来寻找同名的platform_device。
怎么写程序
分配/设置/注册platform_device结构体 board文件
在里面定义所用资源,指定设备名字。
分配/设置/注册platform_driver结构体
在其中的probe函数里,分配/设置/注册file_operations结构体,
并从platform_device中确实所用硬件资源。
指定platform_driver的名字。
leddrv为驱动上层文件。其实中有几个函数可以导出来,供其他文件使用。只需要包含相应的h文件就好了。
1 #include <linux/module.h> 2 3 #include <linux/fs.h> 4 #include <linux/errno.h> 5 #include <linux/miscdevice.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/mutex.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/stat.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/tty.h> 15 #include <linux/kmod.h> 16 #include <linux/gfp.h> 17 18 #include "led_opr.h" 19 20 21 /* 1. 确定主设备号 */ 22 static int major = 0; 23 static struct class *led_class; 24 struct led_operations *p_led_opr; 25 26 27 #define MIN(a, b) (a < b ? a : b) 28 29 /* 2. 定义自己的file_operations结构体 */ 30 static struct file_operations led_drv = { 31 .owner = THIS_MODULE, 32 .open = led_drv_open, 33 .read = led_drv_read, 34 .write = led_drv_write, 35 .release = led_drv_close, 36 }; 37 /* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */ 38 static int led_drv_open (struct inode *node, struct file *file) 39 { 40 int minor = iminor(node); 41 42 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 43 /* 根据次设备号初始化LED */ 44 p_led_opr->init(minor); 45 46 return 0; 47 } 48 static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 49 { 50 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 51 return 0; 52 } 53 54 /* write(fd, &val, 1); */ 55 static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) 56 { 57 int err; 58 char status; 59 struct inode *inode = file_inode(file); 60 int minor = iminor(inode); 61 62 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 63 err = copy_from_user(&status, buf, 1); 64 65 /* 根据次设备号和status控制LED */ 66 p_led_opr->ctl(minor, status); 67 68 return 1; 69 } 70 static int led_drv_close (struct inode *node, struct file *file) 71 { 72 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 73 return 0; 74 } 75 76 void led_class_create_device(int minor) 77 { 78 device_create(led_class, NULL, MKDEV(major, minor), NULL, "100ask_led%d", minor); /* /dev/100ask_led0,1,... */ 79 } 80 81 void led_class_destroy_device(int minor) 82 { 83 device_destroy(led_class, MKDEV(major, minor)); 84 } 85 86 void register_led_operations(struct led_operations *opr) 87 { 88 p_led_opr = opr; 89 } 90 91 EXPORT_SYMBOL(led_class_create_device); 92 EXPORT_SYMBOL(led_class_destroy_device); 93 EXPORT_SYMBOL(register_led_operations); 94 95 96 /* 4. 把file_operations结构体告诉内核:注册驱动程序 */ 97 /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */ 98 static int __init led_init(void) 99 { 100 int err; 101 102 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 103 major = register_chrdev(0, "100ask_led", &led_drv); /* /dev/led */ 104 105 106 led_class = class_create(THIS_MODULE, "100ask_led_class"); 107 err = PTR_ERR(led_class); 108 if (IS_ERR(led_class)) { 109 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 110 unregister_chrdev(major, "led"); 111 return -1; 112 } 113 114 return 0; 115 } 116 117 /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ 118 static void __exit led_exit(void) 119 { 120 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 121 122 class_destroy(led_class); 123 unregister_chrdev(major, "100ask_led"); 124 } 125 126 127 /* 7. 其他完善:提供设备信息,自动创建设备节点 */ 128 129 module_init(led_init); 130 module_exit(led_exit); 131 132 MODULE_LICENSE("GPL");
1 #ifndef _LEDDRV_H 2 #define _LEDDRV_H 3 4 #include "led_opr.h" 5 6 void led_class_create_device(int minor); 7 void led_class_destroy_device(int minor); 8 void register_led_operations(struct led_operations *opr); 9 10 #endif /* _LEDDRV_H */
接下来我们在board文件中指定资源,并对platform_device进行分配,设置,注册。
1 #include <linux/module.h> 2 3 #include <linux/fs.h> 4 #include <linux/errno.h> 5 #include <linux/miscdevice.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/mutex.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/stat.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/tty.h> 15 #include <linux/kmod.h> 16 #include <linux/gfp.h> 17 #include <linux/platform_device.h> 18 19 #include "led_resource.h" 20 21 22 static void led_dev_release(struct device *dev) 23 { 24 } 25 26 static struct resource resources[] = { 27 { 28 .start = GROUP_PIN(3,1), 29 .flags = IORESOURCE_IRQ, 30 .name = "100ask_led_pin", 31 }, 32 { 33 .start = GROUP_PIN(5,8), 34 .flags = IORESOURCE_IRQ, 35 .name = "100ask_led_pin", 36 }, 37 }; 38 39 40 static struct platform_device board_A_led_dev = { 41 .name = "100ask_led", 42 .num_resources = ARRAY_SIZE(resources), 43 .resource = resources, 44 .dev = { 45 .release = led_dev_release, 46 }, 47 }; 48 49 static int __init led_dev_init(void) 50 { 51 int err; 52 53 err = platform_device_register(&board_A_led_dev); 54 55 return 0; 56 } 57 58 static void __exit led_dev_exit(void) 59 { 60 platform_device_unregister(&board_A_led_dev); 61 } 62 63 module_init(led_dev_init); 64 module_exit(led_dev_exit); 65 66 MODULE_LICENSE("GPL");
接下来我们在芯片相关的文件中提供led的操作方法给上层,并对platform_driver进行分配,设置,注册。
1 #include <linux/module.h> 2 3 #include <linux/fs.h> 4 #include <linux/errno.h> 5 #include <linux/miscdevice.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/mutex.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/stat.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/tty.h> 15 #include <linux/kmod.h> 16 #include <linux/gfp.h> 17 #include <linux/platform_device.h> 18 19 #include "led_opr.h" 20 #include "leddrv.h" 21 #include "led_resource.h" 22 23 static int g_ledpins[100]; 24 static int g_ledcnt = 0; 25 26 static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */ 27 { 28 //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which); 29 30 printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which])); 31 switch(GROUP(g_ledpins[which])) 32 { 33 case 0: 34 { 35 printk("init pin of group 0 ...\n"); 36 break; 37 } 38 case 1: 39 { 40 printk("init pin of group 1 ...\n"); 41 break; 42 } 43 case 2: 44 { 45 printk("init pin of group 2 ...\n"); 46 break; 47 } 48 case 3: 49 { 50 printk("init pin of group 3 ...\n"); 51 break; 52 } 53 } 54 55 return 0; 56 } 57 58 static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */ 59 { 60 //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off"); 61 printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which])); 62 63 switch(GROUP(g_ledpins[which])) 64 { 65 case 0: 66 { 67 printk("set pin of group 0 ...\n"); 68 break; 69 } 70 case 1: 71 { 72 printk("set pin of group 1 ...\n"); 73 break; 74 } 75 case 2: 76 { 77 printk("set pin of group 2 ...\n"); 78 break; 79 } 80 case 3: 81 { 82 printk("set pin of group 3 ...\n"); 83 break; 84 } 85 } 86 87 return 0; 88 } 89 90 static struct led_operations board_demo_led_opr = { 91 .init = board_demo_led_init, 92 .ctl = board_demo_led_ctl, 93 }; 94 95 struct led_operations *get_board_led_opr(void) 96 { 97 return &board_demo_led_opr; 98 } 99 100 static int chip_demo_gpio_probe(struct platform_device *pdev) 101 { 102 struct resource *res; 103 int i = 0; 104 105 while (1) 106 { 107 res = platform_get_resource(pdev, IORESOURCE_IRQ, i++); 108 if (!res) 109 break; 110 111 g_ledpins[g_ledcnt] = res->start; 112 led_class_create_device(g_ledcnt); 113 g_ledcnt++; 114 } 115 return 0; 116 117 } 118 119 static int chip_demo_gpio_remove(struct platform_device *pdev) 120 { 121 struct resource *res; 122 int i = 0; 123 124 while (1) 125 { 126 res = platform_get_resource(pdev, IORESOURCE_IRQ, i); 127 if (!res) 128 break; 129 130 led_class_destroy_device(i); 131 i++; 132 g_ledcnt--; 133 } 134 return 0; 135 } 136 137 138 static struct platform_driver chip_demo_gpio_driver = { 139 .probe = chip_demo_gpio_probe, 140 .remove = chip_demo_gpio_remove, 141 .driver = { 142 .name = "100ask_led", 143 }, 144 }; 145 146 static int __init chip_demo_gpio_drv_init(void) 147 { 148 int err; 149 150 err = platform_driver_register(&chip_demo_gpio_driver); 151 register_led_operations(&board_demo_led_opr); 152 153 return 0; 154 } 155 156 static void __exit lchip_demo_gpio_drv_exit(void) 157 { 158 platform_driver_unregister(&chip_demo_gpio_driver); 159 } 160 161 module_init(chip_demo_gpio_drv_init); 162 module_exit(lchip_demo_gpio_drv_exit); 163 164 MODULE_LICENSE("GPL");
opr文件不变
1 #ifndef _LED_OPR_H 2 #define _LED_OPR_H 3 4 struct led_operations { 5 int (*init) (int which); /* 初始化LED, which-哪个LED */ 6 int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */ 7 }; 8 9 struct led_operations *get_board_led_opr(void); 10 11 12 #endif
资源文件不变
1 #ifndef _LED_RESOURCE_H 2 #define _LED_RESOURCE_H 3 4 /* GPIO3_0 */ 5 /* bit[31:16] = group */ 6 /* bit[15:0] = which pin */ 7 #define GROUP(x) (x>>16) 8 #define PIN(x) (x&0xFFFF) 9 #define GROUP_PIN(g,p) ((g<<16) | (p)) 10 11 12 #endif
文件包含关系图:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异