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
mydev.h
  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");
mydev.c
 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
mydev.c_Makefile
 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
demo.c_Makefile
 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);
devicedemo.c
 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 }
test.c
 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
test.c _Makefile

 

posted @ 2016-12-21 22:05  GreenHand#  阅读(1561)  评论(1编辑  收藏  举报