Linux驱动开发cdev驱动分层设计
1 #ifndef MYDEV_H 2 #define MYDEV_H 3 4 #define DYNAMIC_MINOR 256 5 6 struct mydev{ 7 const char *name; 8 const struct file_operations *fops; 9 10 int minor; 11 //private 设备文件 和互斥锁 12 struct device *thisdev; 13 struct mutex lock; 14 }; 15 16 extern int add_mydev(struct mydev *); 17 extern int del_mydev(struct mydev *); 18 19 #endif
1 /* 2 * 分层分工设计演示 3 * cdev为接口层 4 * write by panzhh 5 */ 6 7 #include <linux/module.h> 8 #include <linux/kernel.h> 9 #include <linux/init.h> 10 #include <linux/fs.h> 11 #include <linux/errno.h> 12 #include <linux/slab.h> 13 #include <linux/types.h> 14 #include <linux/cdev.h> 15 #include <linux/device.h> 16 17 #include "../include/mydev.h" 18 19 //用来存放设备文件目录指针 20 static struct class *mydevclass = NULL; 21 22 //最多为64个字符设备的数组 23 #define MYDEVMAX 64 24 static struct mydev *mydevarr[MYDEVMAX]; 25 26 //存放主设备号 27 static int mydev_major = 0; 28 //设备名 29 static const char mydevname[] = "mydev"; 30 31 //静态分配字符设备对象 32 static struct cdev cdev; 33 34 //自己定义的字符设备匹配方法(通过次设备号) 35 static struct mydev *find_mydev(int minor); 36 37 //open方法 38 static int mydev_open(struct inode *inode, struct file *filp) 39 { 40 int err = 0; 41 42 //定义两个操作方法集指针用于保存新旧操作方法, 43 const struct file_operations *old_f, *new_f = NULL; 44 45 struct mydev *mydev = NULL; 46 47 int minor = iminor(inode); 48 printk(KERN_INFO "[%d]mydev_open\n", minor); 49 50 //匹配字符设备 51 mydev = find_mydev(minor); 52 if(NULL == mydev){ 53 printk(KERN_ERR "find_mydev ERR.\n"); 54 return -ENXIO; 55 } 56 57 err = 0; 58 new_f = fops_get(mydev->fops); 59 old_f = filp->f_op; 60 filp->f_op = new_f; 61 if (filp->f_op->open) { 62 filp->private_data = mydev; 63 err=filp->f_op->open(inode,filp); 64 if (err) { 65 fops_put(filp->f_op); 66 filp->f_op = fops_get(old_f); 67 } 68 } 69 fops_put(old_f); 70 71 return err; 72 } 73 74 static struct file_operations mydevfops = { 75 .owner = THIS_MODULE, 76 .open = mydev_open, 77 }; 78 79 ///////////////////////////////////////////////////////////////////////////////////通用字符设备 init 框架 80 alloc_chrdev_region 分配设备号 81 82 static int __init mydev_init(void) 83 { 84 int ret; 85 dev_t dev; 86 87 ret = alloc_chrdev_region(&dev, 0, MYDEVMAX, mydevname); 88 if (ret < 0) { 89 printk(KERN_ERR "alloc_chrdev_region error.\n"); 90 return ret; 91 } 92 mydev_major = MAJOR(dev); 93 94 cdev_init(&cdev, &mydevfops); 95 ret = cdev_add(&cdev, dev, MYDEVMAX); 96 if (ret) { 97 printk(KERN_ERR "Error %d adding %s", ret, mydevname); 98 goto ERR_STEP_0; 99 } 100 101 //sys/class/xxx 102 mydevclass = class_create(THIS_MODULE, mydevname); 103 if (IS_ERR(mydevclass)) { 104 printk(KERN_ERR "Unable create sysfs class for demo\n"); 105 ret = PTR_ERR(mydevclass); 106 goto ERR_STEP_1; 107 } 108 109 //初始化cdev对象指针数组为空,具体的对象在设备加载时得到 struct mydev 110 for(ret = 0; ret < MYDEVMAX; ret++){ 111 mydevarr[ret] = NULL; 112 } 113 114 printk(KERN_INFO "mydev_init done.\n"); 115 116 return 0; 117 118 ERR_STEP_1: 119 cdev_del(&cdev); 120 121 ERR_STEP_0: 122 unregister_chrdev_region(dev, MYDEVMAX); 123 124 return ret; 125 } 126 127 static void __exit mydev_exit(void) 128 { 129 dev_t dev; 130 dev = MKDEV(mydev_major, 0); 131 132 cdev_del(&cdev); 133 unregister_chrdev_region(dev, MYDEVMAX); 134 135 class_destroy(mydevclass); 136 137 printk(KERN_INFO "mydev_exit done.\n"); 138 } 139 140 module_init(mydev_init); 141 module_exit(mydev_exit); 142 143 //////////////////////////////////////////////////////////////////// 144 145 static struct mydev *find_mydev(int minor) 146 { 147 if(minor >= MYDEVMAX){ 148 printk(KERN_ERR "a invalid minor.\n"); 149 return NULL; 150 } 151 152 return mydevarr[minor]; 153 } 154 155 int add_mydev(struct mydev *obj) 156 { 157 int i; 158 159 //先判断次设备号是否为自动分配(这里定义255位自动分配) 160 if(DYNAMIC_MINOR == obj->minor){ 161 //遍历找到最小未用的次设备号 162 for(i = 0; i < MYDEVMAX; i++){ 163 if(NULL == mydevarr[i]) 164 break; 165 } 166 167 //若设备已满返回错误(这里定义64个设备时就不能再添加了) 168 if(MYDEVMAX == i){ 169 printk(KERN_ERR "[add_mydev]: Cann't alloc minor.\n"); 170 return -EBUSY; 171 } 172 //保存分配到的次设备号 173 obj->minor = i; 174 } else { 175 176 //指定的设备号已被用,返回错误 177 if(NULL != find_mydev(obj->minor)){ 178 printk(KERN_ERR "[add_mydev]: a invalid minor.\n"); 179 return -EINVAL; 180 } 181 } 182 183 //sys/class/xxx/xxx0/dev 创建一个对应设备文件 父目录class指针 父对象 设备号 设备私有数据 设备名 184 obj->thisdev = device_create(mydevclass, \ 185 NULL, \ 186 MKDEV(mydev_major, obj->minor), \ 187 obj, \ 188 "%s%d", obj->name, obj->minor); 189 if (IS_ERR(obj->thisdev)) { 190 return PTR_ERR(obj->thisdev); 191 } 192 193 mydevarr[obj->minor] = obj; 194 printk(KERN_INFO "[add_mydev]: major=%d, minor=%d\n", mydev_major, obj->minor); 195 196 return 0; 197 } 198 199 int del_mydev(struct mydev *obj) 200 { 201 if(NULL == find_mydev(obj->minor)){ 202 printk(KERN_ERR "[del_mydev]: a invalid minor.\n"); 203 return -EINVAL; 204 } 205 206 mydevarr[obj->minor] = NULL; 207 208 //销毁设备文件 209 device_destroy(mydevclass, MKDEV(mydev_major, obj->minor)); 210 printk(KERN_INFO "[del_mydev]: major=%d, minor=%d\n", mydev_major, obj->minor); 211 212 return 0; 213 } 214 215 EXPORT_SYMBOL(add_mydev); 216 EXPORT_SYMBOL(del_mydev); 217 218 MODULE_LICENSE("Dual BSD/GPL"); 219 MODULE_AUTHOR ("panzhh"); 220 MODULE_DESCRIPTION ("Driver for mydev"); 221 MODULE_SUPPORTED_DEVICE ("mydev");
1 ifneq ($(KERNELRELEASE),) 2 obj-m := mydev.o 3 else 4 KERNELDIR := /lib/modules/$(shell uname -r)/build 5 PWD := $(shell pwd) 6 modules: 7 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 8 cp -a Module.symvers $(TOPDIR)/device 9 mv *.ko $(TOPDIR)/modules/ 10 endif 11 12 clean: 13 rm -rf *.o *.symvers *.order *.ko *.mod.c *.markers .tmp_versions .*.cmd
1 ifneq ($(KERNELRELEASE),) 2 obj-m := demoa.o 3 obj-m += demob.o 4 else 5 KERNELDIR := /lib/modules/$(shell uname -r)/build 6 PWD := $(shell pwd) 7 modules: 8 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 9 mv *.ko $(TOPDIR)/modules/ 10 endif 11 12 clean: 13 rm -rf *.o *.symvers *.order *.ko *.mod.c *.markers .tmp_versions .*.cmd
1 /* 2 * 自定义设备框架 3 * write by panzhh 4 * 设备具体驱动 5 */ 6 7 #include <linux/module.h> 8 #include <linux/kernel.h> 9 #include <linux/init.h> 10 #include <linux/fs.h> 11 #include <linux/errno.h> 12 #include <linux/slab.h> 13 #include <linux/types.h> 14 15 #include "../include/mydev.h" 16 17 static int minor = 0; 18 19 //设备的具体操作方法(驱动) 20 static int demo_open(struct inode *inode, struct file *filep) 21 { 22 minor = iminor(inode); 23 24 printk(KERN_INFO "[%d]demo_open, inode=%p\n", minor, inode); 25 return 0; 26 } 27 28 static int demo_release(struct inode *inode, struct file *filp) 29 { 30 printk(KERN_INFO "[%d]demo_release\n", minor); 31 return 0; 32 } 33 34 static ssize_t demo_read(struct file *filep, char __user *buf, size_t count, loff_t *fpos) 35 { 36 printk(KERN_INFO "[%d]demo_read, inode=%p\n", minor, filep->f_path.dentry->d_inode); 37 return 0; 38 } 39 40 static ssize_t demo_write(struct file *filep, const char __user *buf, size_t count, loff_t *fpos) 41 { 42 printk(KERN_INFO "[%d]demo_write, inode=%p\n", minor, filep->f_path.dentry->d_inode); 43 return 0; 44 } 45 46 static struct file_operations fops = { 47 .owner = THIS_MODULE, 48 .read = demo_read, 49 .write = demo_write, 50 .open = demo_open, 51 .release = demo_release, 52 }; 53 54 //每个设备的mydev空间在此次分配,并在 init 函数中交由 add_mydev() 进行处理 55 struct mydev mydev = { 56 .minor = DYNAMIC_MINOR, 57 .name = "demo", 58 .fops = &fops, 59 }; 60 61 static int __init demo_init(void) 62 { 63 printk(KERN_INFO "demo_init.\n"); 64 return add_mydev(&mydev); 65 } 66 67 static void __exit demo_exit(void) 68 { 69 del_mydev(&mydev); 70 printk(KERN_INFO "demob_exit done.\n"); 71 } 72 73 MODULE_LICENSE("Dual BSD/GPL"); 74 MODULE_AUTHOR ("panzhh"); 75 MODULE_DESCRIPTION ("Driver for demo"); 76 MODULE_SUPPORTED_DEVICE ("demo"); 77 78 module_init(demo_init); 79 module_exit(demo_exit);
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 7 int demofunc(char *devname) 8 { 9 int fd = open(devname, O_RDWR); 10 if(0 > fd){ 11 perror("open"); 12 return -1; 13 } 14 printf("open done. fd=%d\n", fd); 15 16 #define MAX 64 17 char buf[MAX]={}; 18 int ret = write(fd, buf, MAX); 19 if(0 > ret){ 20 perror("write"); 21 } 22 printf("write done. fd=%d, ret=%d\n", fd, ret); 23 ret = read(fd, buf, MAX); 24 if(0 > ret){ 25 perror("read"); 26 } 27 printf("read done. fd=%d, ret=%d\n", fd, ret); 28 getchar(); 29 30 close(fd); 31 printf("close done.\n"); 32 return 0; 33 } 34 35 int main() 36 { 37 demofunc("/dev/demo0"); 38 demofunc("/dev/demo1"); 39 }
1 CC = gcc 2 CFLAGS = -Wall -O2 -g -std=gnu99 3 LDFLAGS = 4 5 APP = app 6 OBJS = $(patsubst %.c, %.o, $(wildcard *.c)) 7 8 $(APP) : $(OBJS) 9 $(CC) -o $@ $^ $(LDFLAGS) 10 11 clean: 12 rm -f $(OBJS) $(APP) *.o