杂项字符设备:
杂项字符设备特点:
1.关联函数:misc_register()、misc_deregister()
2.主设备号规定为10,只需要分配次设备号minor(杂项设备最多只能分配255个,0~255)
3.设备初始化时,设备节点文件自动创建(与早期字符设备手动创建不一样)
使用案例:
(三个程序案例实现的功能都是一样的,不同之处已用颜色标出(一些函数涉及的结构体差异没有标出),大家可以跳过)
#include <linux/module.h> #include <linux/kernel.h> #include <asm/io.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <asm/uaccess.h> #define GPM4DAT 0x110002e4 //GPIO状态寄存器物理地址 static unsigned long* ledcon = NULL; static unsigned long* leddat = NULL; // 上层关联函数write(int fd, void* buf, int count); //自定义write操作函数 static ssize_t led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offet){ char buf[32] = {0}; int ret = 0; ret = copy_from_user(buf, buff, min(count, sizeof(buf))); //实现用户层与底层链接函数 if(strncmp(buf, "led on", strlen("led on")) == 0) { *leddat &= 0xf0; } else if(strncmp(buf, "led off", strlen("led off")) == 0) { *leddat |= 0x0f; } else { printk("***cmd error!***\n"); } return min(count, sizeof(buf)); } //文件操作集合定义初始化。 给上层应用层留操作接口 static struct file_operations g_tfops = { .owner = THIS_MODULE, .write = led_write, }; //********杂项字符函数结构体*********** static struct miscdevice g_tmiscdev = {.minor = MISC_DYNAMIC_MINOR, //MISC_DYNAMIC_MINOR==255 表示系统自动分配次设备号 .name = "led_misc", .fops = &g_tfops, //自定义write操作函数(上面定义) }; //******主函数入口******* static int __init pyw_module_init(void){ printk("hello module! 你好\n"); ledcon = ioremap(GPM4CON, 4); //地址映射,将物理地址映射成虚拟地址,供内核使用 leddat = ioremap(GPM4DAT, 4); //地址映射,将物理地址映射成虚拟地址,供内核使用 *ledcon &= 0xffff0000; *ledcon |= 0x00001111; *leddat |= 0x0f; misc_register(&g_tmiscdev); return 0; } //******主函数出口******* static void __exit pyw_module_exit(void) { printk("byebye %s\n", "module"); misc_deregister(&g_tmiscdev); *leddat |= 0x0f; iounmap(ledcon); iounmap(leddat); } module_init(pyw_module_init); module_exit(pyw_module_exit); |
早期字符设备:
早期字符设备特点:
1. 与杂项相比,早期字符设备需要自己创建节点文件,但编程上少了一层结构体
2. majoy主设备号:0~255(10外:10号为杂项字符设备专用号) minor:0~255
#include <linux/module.h> #include <linux/kernel.h> #include <asm/io.h> #include <linux/fs.h> #include <asm/uaccess.h> #define GPM4CON 0x110002e0 #define GPM4DAT 0x110002e4 static unsigned long* ledcon = NULL; static unsigned long* leddat = NULL; // write(int fd, void* buf, int count); static ssize_t led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offet) { char buf[32] = {0}; int ret = 0; ret = copy_from_user(buf, buff, min(count, sizeof(buf))); if(strncmp(buf, "led on", strlen("led on")) == 0) { *leddat &= 0xf0; } else if(strncmp(buf, "led off", strlen("led off")) == 0) { *leddat |= 0x0f; } else { printk("***cmd error!***\n"); } return min(count, sizeof(buf)); } //文件操作集合定义初始化。 给上层应用层留操作接口 static struct file_operations g_tfops = { .owner = THIS_MODULE, .write = led_write, }; static int g_major = 0; static int __init pyw_module_init(void) { printk("hello module! 你好\n"); ledcon = ioremap(GPM4CON, 4); leddat = ioremap(GPM4DAT, 4); *ledcon &= 0xffff0000; *ledcon |= 0x00001111; *leddat |= 0x0f; g_major = register_chrdev(0, "led_xxx", &g_tfops); printk("major = %d\n", g_major); return 0; } static void __exit pyw_module_exit(void) { printk("byebye %s\n", "module"); unregister_chrdev(g_major, "led_xxx"); *leddat |= 0x0f; iounmap(ledcon); iounmap(leddat); } module_init(pyw_module_init); module_exit(pyw_module_exit); |
标准字符设备
标准字符串设备特点:
1.标准字符设备使用复杂,较为少用。(杂类和早期都是封装好了标准字符设备相关函数,所以使用简单)
2.模块加载后,需要自己手动创建节点文件
3.majoy主设备号:0~2^12=4K (10是给杂项设备使用的) minor次设备号:0~2^20=1M
#include <linux/module.h> #include <linux/kernel.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <linux/cdev.h> #include <asm/io.h> #include <linux/slab.h> #define BASEMINOR 0 #define DEVCOUNT 4 #define DEVNAME "led_cdev" #define GPM4CON 0x110002e0 #define GPM4DAT 0x110002e4 static unsigned long* ledcon = NULL; static unsigned long* leddat = NULL; static ssize_t led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offet) { char buf[32] = {0}; int ret = 0; ret = copy_from_user(buf, buff, min(count, sizeof(buf))); if(strncmp(buf, "led on", strlen("led on")) == 0) { *leddat &= 0xf0; } else if(strncmp(buf, "led off", strlen("led off")) == 0) { *leddat |= 0x0f; } else { printk("***cmd error!***\n"); } return min(count, sizeof(buf)); } static struct file_operations g_tfops = { .owner = THIS_MODULE, .write = led_write, }; static dev_t g_dev = 0; static struct cdev* g_ptcdev = NULL; static int __init pyw_cdev_init(void) { ledcon = ioremap(GPM4CON, 4); leddat = ioremap(GPM4DAT, 4); *ledcon &= 0xffff0000; *ledcon |= 0x00001111; *leddat |= 0x0f; alloc_chrdev_region(&g_dev, BASEMINOR, DEVCOUNT, DEVNAME); //申请设备号 g_ptcdev = cdev_alloc(); //申请标准字符设备结构体空间 cdev_init(g_ptcdev, &g_tfops); //初始化赋值标准字符设备结构体变量 cdev_add(g_ptcdev, g_dev, DEVCOUNT); //注册标准字符设备到内核总线 printk("major = %d\n", MAJOR(g_dev)); printk("minor = %d\n", MINOR(g_dev)); return 0; } static void __exit pyw_cdev_exit(void) { //****************与注册对应的资源释放*********************** cdev_del(g_ptcdev);kfree(g_ptcdev); unregister_chrdev_region(g_dev, DEVCOUNT); //DEVCOUNT=0 iounmap(ledcon); iounmap(leddat); } module_init(pyw_cdev_init); module_exit(pyw_cdev_exit); |