嵌入式开发记录-day23 字符驱动-- 4 驱动接口实现
1、继上一节的代码继续,完善文件操作的相关函数
2、完善结构体struct cdev中的
struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; // 应用这个类型的参数 unsigned int count; }; 其中的 const struct file_operations *ops; // 由于包含有太多的函数,所以只简单实现下常用的函数 // 读函数 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); // 写函数 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); // 打开函数 int (*open) (struct inode *, struct file *); // 清空缓存 int (*flush) (struct file *, fl_owner_t id); // 关闭 相当于close函数 int (*release) (struct inode *, struct file *); // IO控制函数 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); // 定位函数 loff_t (*llseek) (struct file *, loff_t, int);
3、实现代码chardriver.c
1 #include <linux/init.h> 2 /*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/ 3 #include <linux/module.h> 4 5 #include <linux/fs.h> // 申请设备号函数 6 #include <linux/kdev_t.h> // MKDEV宏定义的相关处理 7 #include <linux/cdev.h> 8 #include <linux/slab.h> 9 #include <linux/device.h> // 创建字符设备类 10 #include <linux/device.h> // 包含class结构体变量 11 12 MODULE_LICENSE("Dual BSD/GPL"); 13 /*声明是开源的,没有内核版本限制*/ 14 MODULE_AUTHOR("iTOPEET_dz"); 15 /*声明作者*/ 16 17 #define DEVICE_NAME "chardevnode" // 注册的设备名称 18 #define DEVICE_MINOR_NUM 2 // 次设备号的个数 19 #define DEV_MAJOR 0 // 预定以主设备号为0,加载的时候在查询 20 #define DEV_MINOR 0 // 预设次设备号为0 cat /proc/devices 21 #define REGDEV_SIZE 3000 // 定义注册设备存储数据的大小 22 23 int numdev_major = DEV_MAJOR; 24 int numdev_minor = DEV_MINOR; 25 26 struct reg_dev 27 { 28 char *data; // 存放数据 29 unsigned long size; // 定义数据长度 30 struct cdev cdev; 31 }; 32 33 struct reg_dev *my_devices; 34 35 static struct class* myclass; 36 37 38 /*输入主设备号*/ 39 module_param(numdev_major,int,S_IRUSR); 40 /*输入次设备号*/ 41 module_param(numdev_minor,int,S_IRUSR); 42 43 static int opencdev_node (struct inode *node, struct file *file) 44 { 45 printk(KERN_EMERG "func opencdev_node is success!\n"); 46 return 0; 47 } 48 49 static int releasecdev_node (struct inode *node, struct file *file) 50 { 51 printk(KERN_EMERG "func releasecdev_node is success!\n"); 52 return 0; 53 } 54 55 // IO控制函数 56 static long ioctlcdev_node (struct file *file, unsigned int cmd, unsigned long arg) 57 { 58 printk(KERN_EMERG "func ioctlcdev_node cmd:%d....arg:%d!\n",cmd,arg); 59 return 0; 60 } 61 // 定位函数 62 loff_t llseekcdev_node(struct file *file, loff_t offset, int ence) 63 { 64 return 0; 65 } 66 // 读函数 67 ssize_t readcdev_node(struct file *file, char __user *buf, size_t count, loff_t *fops) 68 { 69 return 0; 70 } 71 // 写函数 72 ssize_t writecdev_node (struct file *file, const char __user *buf, size_t count, loff_t *fops) 73 { 74 return 0; 75 } 76 77 struct file_operations my_fops={ 78 .owner = THIS_MODULE, 79 .open = opencdev_node, 80 .release = releasecdev_node, 81 .read = readcdev_node, 82 .write = writecdev_node, 83 .unlocked_ioctl = ioctlcdev_node, 84 .llseek = llseekcdev_node, 85 }; 86 87 /// 单个设备初始化 88 static void reg_init_cdev(struct reg_dev* dev,int index) 89 { 90 int ret; 91 int devnum = MKDEV(numdev_major,numdev_minor+index); 92 // cdev_init(struct cdev *, const struct file_operations *) 93 cdev_init(&dev->cdev,&my_fops); 94 dev->cdev.owner = THIS_MODULE, 95 dev->cdev.ops = &my_fops, 96 // int cdev_add(struct cdev *, dev_t, unsigned); 97 ret = cdev_add(&dev->cdev,devnum,1); 98 if(ret){ 99 printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,ret); 100 } 101 else{ 102 printk(KERN_EMERG "cdev_add %d is success!\n",index); 103 } 104 } 105 106 static int scdev_init(void) 107 { 108 int ret = 0,i; 109 dev_t num_dev; 110 111 printk(KERN_EMERG "numdev_major is %d!\n",numdev_major); 112 printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor); 113 114 if(numdev_major){ 115 // 将设备号转换成可以注册的格式 116 num_dev = MKDEV(numdev_major,numdev_minor); 117 // 将主次设备号注册到linux内核中 118 ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME); 119 } 120 else{ // 动态申请设备号 121 // 设备号地址、次设备号、设备号数量、设备号名称 122 ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM,DEVICE_NAME); 123 if(ret < 0){ 124 printk(KERN_EMERG "func alloc_chrdev_region was failed!\n"); 125 } 126 numdev_major = MAJOR(num_dev); 127 printk(KERN_EMERG "adev_region numdev_major req %d !\n",MAJOR(num_dev)); 128 printk(KERN_EMERG "adev_region numdev_minor req %d !\n",MINOR(num_dev)); 129 } 130 if(ret<0){ 131 printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major); 132 } 133 134 myclass = class_create(THIS_MODULE,DEVICE_NAME); // 创建一个设备类 135 136 // 成功申请设备号,开始分配内存; 137 // 分配内存是在获取主设备号以后 138 my_devices = kmalloc(DEVICE_MINOR_NUM* sizeof(struct reg_dev), GFP_KERNEL); 139 if(!my_devices){ 140 ret = -ENOMEM; 141 goto fail; 142 } 143 // 分配内存完成后,清空内存 144 memset(my_devices,0,DEVICE_MINOR_NUM* sizeof(struct reg_dev)); 145 for(i=0;i<DEVICE_MINOR_NUM;i++){ 146 my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL); 147 memset(my_devices[i].data,0,REGDEV_SIZE); 148 149 reg_init_cdev(&my_devices[i],i); 150 // 创建设备结点 151 device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL ,DEVICE_NAME"%d",i); 152 } 153 printk(KERN_EMERG "scdev_init!\n"); 154 /*打印信息,KERN_EMERG表示紧急信息*/ 155 return 0; 156 157 fail: 158 unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 159 printk(KERN_EMERG "kmalloc is fail!\n"); 160 return ret; 161 } 162 163 static void scdev_exit(void) 164 { 165 int i=0; 166 printk(KERN_EMERG "scdev exit...\n"); 167 // 注销注册好的设备号 168 unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 169 for(i=0;i<DEVICE_MINOR_NUM;i++){ 170 cdev_del(&(my_devices[i].cdev)); 171 device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i)); 172 } 173 174 class_destroy(myclass); 175 kfree(my_devices); 176 unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 177 } 178 179 // 模块的入口函数 180 module_init(scdev_init); 181 module_exit(scdev_exit);
4、编译加载
[root@iTOP-4412]# insmod charDriver.ko [ 575.996332] numdev_major is 0! [ 575.997943] numdev_minor is 0! [ 576.009088] adev_region numdev_major req 248 ! [ 576.012251] adev_region numdev_minor req 0 ! [ 576.017273] cdev_add 0 is success! [ 576.028717] cdev_add 1 is success! [ 576.035921] scdev_init! // 需要查看是否成功生成设备结点 [root@iTOP-4412]# ls /dev chardevnode0 chardevnode1
5、生成设备结点表示正常,进一步编谐简单应用测试下模块invoke_chardriver.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> // sleep() #include <sys/ioctl.h> int main(void) { int fd0,fd1; char* hello_node0 = "/dev/chardevnode0"; char* hello_node1 = "/dev/chardevnode1"; fd0 = open(hello_node0,O_RDWR|O_NDELAY); // 非阻塞打开 if(fd0 < 0){ printf("func open app %s failed\n",hello_node0); return -1; }else{ printf("App open %s success\n",hello_node0); ioctl(fd0,1,1); // 应用程序向驱动传值 点亮led } fd1 = open(hello_node1,O_RDWR|O_NDELAY); // 非阻塞打开 if(fd1 < 0){ printf("func open app %s failed\n",hello_node1); return -1; }else{ printf("App open %s success\n",hello_node1); ioctl(fd1,1,1); // 应用程序向驱动传值 点亮led } close(fd0); close(fd1); return 0; }
6、编译应用
[root@iTOP-4412]# ./invoke_chardriver.o [ 622.091320] func opencdev_node is success! App open /dev/cha[ 622.098546] func ioctlcdev_node cmd:1....arg:1! [ 622.103178] func opencdev_node is success! [ 622.107289] func ioctlcdev_node cmd:1....arg:1! [ 622.111828] func releasecdev_node is success! [ 622.116194] func releasecdev_node is success! rdevnode0 success App open /dev/chardevnode1 success

浙公网安备 33010602011771号