嵌入式开发记录-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

 

posted @ 2020-07-21 23:12  笑不出花的旦旦  阅读(89)  评论(0)    收藏  举报