zoukankan      html  css  js  c++  java
  • 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
    ", minor);
     49 
     50     //匹配字符设备
     51     mydev = find_mydev(minor);
     52     if(NULL == mydev){
     53         printk(KERN_ERR "find_mydev ERR.
    ");
     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.
    ");
     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
    ");
    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.
    ");
    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.
    ");
    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.
    ");
    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.
    ");
    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.
    ");
    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
    ", 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.
    ");
    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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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.
    ");
    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.
    ");
    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
    ", 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
    ", fd, ret);
    23     ret = read(fd, buf, MAX);
    24     if(0 > ret){
    25         perror("read");
    26     }
    27     printf("read done. fd=%d, ret=%d
    ", fd, ret);
    28     getchar();
    29 
    30     close(fd);
    31     printf("close done.
    ");
    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
  • 相关阅读:
    Hadoop集群(三) Hbase搭建
    Hadoop集群(二) HDFS搭建
    Hadoop集群(一) Zookeeper搭建
    Redis Cluster 添加/删除 完整折腾步骤
    Redis Cluster在线迁移
    Hadoop分布式HA的安装部署
    Describe the difference between repeater, bridge and router.
    what is the “handover” and "soft handover" in mobile communication system?
    The main roles of LTE eNodeB.
    The architecture of LTE network.
  • 原文地址:https://www.cnblogs.com/chen-farsight/p/6154937.html
Copyright © 2011-2022 走看看