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
  • 相关阅读:
    鲍尔默称微软将投入数十亿美元打造数据中心业务(转)
    程序流程的辅助控制
    获取程序所在目录
    越界赋值
    长字串与宽字串
    长字串与短字串
    指针的运算
    Windows API 的数据类型与 Delphi 数据类型对照表
    给动态数组添加一个元素
    Delphi 与 C/C++ 数据类型对照表
  • 原文地址:https://www.cnblogs.com/chen-farsight/p/6154937.html
Copyright © 2011-2022 走看看