完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
字符设备驱动框架
① 确定主设备号,可也已让内核分配。 ② 定义自己的file_operations结构体。 ③ 实现对应的drv_open/ drv_read/ drv_write等函数,填入file_operations结构体。 ④ 把file_operations连接进内核(register_chrdev)。 ⑤ 谁来注册驱动程序啊?得有一个入口函数,安装驱动程序时,就会去调用这个入口函数。 ⑥ 有入口函数就有出口函数,出口函数调用(unregister_chrdev)。 ⑦ 其他玩善:提供设备信息,自动创建设备节点:class_create,device_create 自己理解: ① 先写驱动设备基础框架,module_init和module_exit。 ② 然后再写file_operations结构体,编写对应需要的open、read、write函数。 ③ 通过register_chrdev1把设备号,设备名称,设备操作符和内核注册。 ④ 再Module_exit中补充unregister_chrdev函数。 ⑤ 完善其他:提供设备信息,自动创建设备节点:class_create,device_create2 对于LED驱动,我们想要什么样的接口
这样写基本可以了,但是我们遇到如果要写不同板子的驱动程序的时候该怎么办呢?从设计模式的角度讲,我们需要把共同的部分提炼出来一个.h头文件。然后把不同的部分在各自的.c中实现。 在led驱动中,我们可以提炼出一个led_operations,它有初始化,和控制两个程序。在不同的板子上用不同的方法实现led的接口。 struct led_operations { int (*init)(int which); /* 初始化哪个LED */ int (*ctl)(int which, int status); /* 控制LED,亮灭 */ }
自己的理解: 利用抽象和分层,实现改动的最小化。具体分为:用户层、驱动层、设备层。
相关代码: Makefile: KERN_DIR = /home/book/Documents/100ask_firefly-rk3288/linux-4.4 all: make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o led_app led_app.c -Wno-error=unused-but-set-variable clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order rm -f hello_drv_test myled_drv-y:=led_drv.o board_demoo.o obj-m += myled_drv.o led_drv.c: #include #include #include #include #include #include #include #include #include #include "led_ops.h" static int major = 0; static struct class *led_class; struct led_operations *p_led_ops; static int led_drv_open(struct inode *node, struct file *file) { int minor = iminor(node); printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); p_led_ops->init(minor); return 0; } static ssize_t led_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { int err; char status; struct inode *inode = file_inode(file); int minor = iminor(inode); printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); err = copy_from_user(&status, buf, 1); printk("write status:%x n", status); p_led_ops->ctl(minor, status); return 1; } static int led_drv_close(struct inode *node, struct file *file) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } static struct file_operations led_drv = { .owner = THIS_MODULE, .open = led_drv_open, .read = led_drv_read, .write = led_drv_write, .release = led_drv_close, }; static int __init led_drv_init(void) { int err; major = register_chrdev(0, "myled", &led_drv); led_class = class_create(THIS_MODULE, "led_class"); err = PTR_ERR(led_class); if(IS_ERR(led_class)) { unregister_chrdev(major, "myled"); printk(KERN_WARNING "class creatge failed %dn", err); return -1; } device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); p_led_ops = get_board_led_ops(); printk("%s %sled_drv_initn", __FILE__, __FUNCTION__); return 0; } static void __exit led_drv_exit(void) { printk("%s %sled_drv_exitn", __FILE__, __FUNCTION__); device_destroy(led_class, MKDEV(major, 0)); class_destroy(led_class); unregister_chrdev(major, "myled"); } module_init(led_drv_init); module_exit(led_drv_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("chen"); board_demoo.c: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "led_ops.h" static int board_demoo_led_init(int which) { printk("%s %s line %d, led %dn", __FILE__, __FUNCTION__, __LINE__, which); return 0; } static int board_demoo_led_ctl(int which, char status) { printk("%s %s line %d, led %d, %sn", __FILE__, __FUNCTION__, __LINE__, which, status?"on":"off"); return 0; } static struct led_operations board_demoo_led_ops = { .init = board_demoo_led_init, .ctl = board_demoo_led_ctl, }; struct led_operations *get_board_led_ops(void) { return &board_demoo_led_ops; } led_ops.h: #ifndef __LED_OPS_H_ #define __LED_OPS_H_ struct led_operations { int (*init)(int which); /* init led, which:led num */ int (*ctl)(int which, char status); /* control led, whic:led num,status:0-On 1-Off */ }; struct led_operations *get_board_led_ops(void); #endif led_app.c: #include #include #include #include #include #include void showUsage(void) { printf("app [dev_path] [on,off]n"); } int main(int argc, char *argv[]) { char status; if(argc < 3) { showUsage(); return -1; } int fd = open(argv[1], O_RDWR); if(fd < 0) { printf("app open device failed path:%s", argv[1]); return -1; } if(0 == strcmp(argv[2], "on")) { status = 1; int ret = write(fd, &status, 1); if(ret <= 0) { printf("app write device fialed %s",argv[2]); return -1; } else { printf("app write device %x", status); } } else if(0 == strcmp(argv[2], "off")) { status = 0; int ret = write(fd, &status, 1); if(ret <= 0) { printf("app write device fialed %s",argv[2]); return -1; } else { printf("app write device %x", status); } } return 0; } |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1906 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2382 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5175 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 07:01 , Processed in 0.715655 second(s), Total 73, Slave 56 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号