0


linux 驱动——私有数据

文章目录

linux 驱动中的私有数据

前面的程序中,都只申请了一个从设备号,这里使用

alloc_chrdev_region

分配两个设备号,这两个设备共用

ops

方法。

所以需要在

ops

方法中区分两个设备

container_of

参考:linux——宏 list_entry/container_of

驱动程序

数据结构定义

typedefstruct{dev_t dev_id;/* 设备号 */structcdev c_dev;/* cdev */structclass*class;/* 类 */structdevice*device;/* 设备 */int major;/* 主设备号 */int minor;/* 次设备号 */char write_buf[100];char read_buf[100];}new_chrdev_t;staticnew_chrdev_t new_chrdev1;staticnew_chrdev_t new_chrdev2;

这里定义了两个设备,分别为

new_chrdev1

和 ·new_chrdev2·

  • new_chrdev1 - 设备号:通过 alloc_chrdev_region 分配;- 主设备号:major = MAJOR(dev_id);- 次设备号:minor = MINOR(dev_id);
  • new_chrdev2 - 主设备号:major = MAJOR(new_chrdev1.dev_id);- 次设备号:minor = MINOR(new_chrdev1.dev_id) + 1;- 设备号: dev_id = MKDEV(new_chrdev2.major, new_chrdev2.minor);

程序源码

#include"linux/device/class.h"#include"linux/export.h"#include"linux/uaccess.h"#include<linux/types.h>#include<linux/kernel.h>#include<linux/init.h>#include<linux/module.h>#include<linux/fs.h>#include<linux/device.h>#include<linux/cdev.h>#defineCHRDEVBASE_NAME"chrdevbase"/* 设备名 */#defineCHRDEVBASE_NUM2/* 设备数目 */staticchar*string_test ="kernel data this tyustli test";typedefstruct{dev_t dev_id;/* 设备号 */structcdev c_dev;/* cdev */structclass*class;/* 类 */structdevice*device;/* 设备 */int major;/* 主设备号 */int minor;/* 次设备号 */char write_buf[100];char read_buf[100];}new_chrdev_t;staticnew_chrdev_t new_chrdev1;staticnew_chrdev_t new_chrdev2;staticintchrdevbase_open(structinode*inode,structfile*file){
    new_chrdev1.minor =0;
    new_chrdev2.minor =1;

    file->private_data =container_of(inode->i_cdev,new_chrdev_t, c_dev);/* 设置私有数据 */printk("k: chrdevbase open\r\n");return0;}staticssize_tchrdevbase_read(structfile*file,char __user *buf,size_t count,loff_t*ppos){unsignedlong ret =0;new_chrdev_t*dev =(new_chrdev_t*)file->private_data;printk("k: chrdevbase read major %d\r\n", dev->major);memcpy(dev->read_buf, string_test,strlen(string_test));

    ret =copy_to_user(buf, dev->read_buf, count);if(ret ==0){printk("k: read data success\r\n");}else{printk("k: read data failed ret = %ld\r\n", ret);}return ret;}staticssize_tchrdevbase_write(structfile*file,constchar __user *buf,size_t count,loff_t*ppos){unsignedlong ret =0;printk("k: chrdevbase write\r\n");new_chrdev_t*dev =(new_chrdev_t*)file->private_data;printk("k: chrdevbase read minor %d\r\n", dev->minor);

    ret =copy_from_user(dev->write_buf, buf, count);if(ret ==0){printk("k: write data success write data is: %s\r\n", dev->write_buf);}else{printk("k: write data failed ret = %ld\r\n", ret);}return count;}staticintchrdevbase_release(structinode*inode,structfile*file){printk("k: chrdevbase release\r\n");return0;}staticstructfile_operations chrdevbase_fops ={.owner = THIS_MODULE,.open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,};staticint __init chrdevbase_init(void){int err =0;

    err =alloc_chrdev_region(&new_chrdev1.dev_id,0, CHRDEVBASE_NUM,
                              CHRDEVBASE_NAME);if(err <0){printk("k: alloc chrdev region failed err = %d\r\n", err);goto err_chrdev;}/* get major 1 and minor 1 */
    new_chrdev1.major =MAJOR(new_chrdev1.dev_id);
    new_chrdev1.minor =MINOR(new_chrdev1.dev_id);printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev1.major,
           new_chrdev1.minor);

    new_chrdev1.c_dev.owner = THIS_MODULE;cdev_init(&new_chrdev1.c_dev,&chrdevbase_fops);
    err =cdev_add(&new_chrdev1.c_dev, new_chrdev1.dev_id,1);if(err <0){printk("k: cdev add failed err = %d\r\n", err);goto err_cdev_add;}
    new_chrdev1.class =class_create("chr_test1");if(IS_ERR(new_chrdev1.class)){
        err =PTR_ERR(new_chrdev1.class);goto err_class_create;}

    new_chrdev1.device =device_create(new_chrdev1.class,NULL,
                                       new_chrdev1.dev_id,NULL,"chr_test1");if(IS_ERR(new_chrdev1.device)){
        err =PTR_ERR(new_chrdev1.device);goto err_device_create;}/* get major 2 and minor 2 */
    new_chrdev2.major =MAJOR(new_chrdev2.dev_id);
    new_chrdev2.minor =MINOR(new_chrdev2.dev_id)+1;
    new_chrdev2.dev_id =MKDEV(new_chrdev2.major, new_chrdev2.minor);printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev2.major,
           new_chrdev2.minor);

    new_chrdev2.c_dev.owner = THIS_MODULE;cdev_init(&new_chrdev2.c_dev,&chrdevbase_fops);
    err =cdev_add(&new_chrdev2.c_dev, new_chrdev2.dev_id,1);if(err <0){printk("k: cdev add failed err = %d\r\n", err);goto err_cdev_add;}

    new_chrdev2.class =class_create("chr_test2");if(IS_ERR(new_chrdev2.class)){
        err =PTR_ERR(new_chrdev2.class);goto err_class_create;}

    new_chrdev2.device =device_create(
            new_chrdev2.class,NULL, new_chrdev2.dev_id,NULL,"chr_test2");if(IS_ERR(new_chrdev2.device)){
        err =PTR_ERR(new_chrdev2.device);goto err_device_create;}printk("k: base module init\r\n");return0;

err_device_create:class_destroy(new_chrdev1.class);class_destroy(new_chrdev2.class);
err_class_create:cdev_del(&new_chrdev1.c_dev);cdev_del(&new_chrdev2.c_dev);
err_cdev_add:unregister_chrdev_region(new_chrdev1.dev_id, CHRDEVBASE_NUM);
err_chrdev:return err;}staticvoid __exit chrdevbase_exit(void){device_destroy(new_chrdev1.class, new_chrdev1.dev_id);device_destroy(new_chrdev2.class, new_chrdev2.dev_id);class_destroy(new_chrdev1.class);class_destroy(new_chrdev2.class);cdev_del(&new_chrdev1.c_dev);cdev_del(&new_chrdev2.c_dev);unregister_chrdev_region(new_chrdev1.dev_id, CHRDEVBASE_NUM);printk("k: base module exit!\r\n");}module_init(chrdevbase_init);module_exit(chrdevbase_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("tyustli");MODULE_INFO(intree,"Y");/* loading out-of-tree module taints kernel */

应用程序

#include"stdio.h"#include"unistd.h"#include"sys/types.h"#include"sys/stat.h"#include"fcntl.h"#include"stdlib.h"#include"string.h"staticchar usrdata[]={"user data!"};intmain(int argc,char*argv[]){int fd, retvalue;char*filename;char readbuf[100], writebuf[100];if(argc !=3){printf("u: error Usage!\r\n");return-1;}

    filename = argv[1];/* 打开驱动文件 */
    fd =open(filename, O_RDWR);if(fd <0){printf("u: can't open file %s\r\n", filename);return-1;}/* 从驱动文件读取数据 */if(atoi(argv[2])==1){
        retvalue =read(fd, readbuf,50);if(retvalue <0){printf("u: read file %s failed!\r\n", filename);}else{/*  读取成功,打印出读取成功的数据 */printf("u: read data:%s\r\n", readbuf);}}/* 向设备驱动写数据 */if(atoi(argv[2])==2){memcpy(writebuf, usrdata,sizeof(usrdata));
        retvalue =write(fd, writebuf,50);if(retvalue <0){printf("u: write file %s failed!\r\n", filename);}}/* 关闭设备 */
    retvalue =close(fd);if(retvalue <0){printf("u: can't close file %s\r\n", filename);return-1;}return0;}

模块使用

模块安装

modprobe my_module

查看设备节点

ls /dev/

在这里插入图片描述

模块使用

#设备1
lib/modules/6.5.7+/my_app /dev/chr_test1  1
lib/modules/6.5.7+/my_app /dev/chr_test1  2
#设备2
lib/modules/6.5.7+/my_app /dev/chr_test2  1
lib/modules/6.5.7+/my_app /dev/chr_test2  2

模块打印日志

~ # lib/modules/6.5.7+/my_app /dev/chr_test1  1
k: chrdevbase open
k: chrdevbase read major 248
k: read data success
u: read data:kernel data this tyustli test
k: chrdevbase release
~ # lib/modules/6.5.7+/my_app /dev/chr_test1  2
k: chrdevbase open
k: chrdevbase write
k: chrdevbase read minor 0
k: write data success write data is: user data!
k: chrdevbase release
~ # lib/modules/6.5.7+/my_app /dev/chr_test2  1
k: chrdevbase open
k: chrdevbase read major 248
k: read data success
u: read data:kernel data this tyustli test
k: chrdevbase release
~ # lib/modules/6.5.7+/my_app /dev/chr_test2 2
k: chrdevbase open
k: chrdevbase write
k: chrdevbase read minor 1
k: write data success write data is: user data!
k: chrdevbase release
~ # 

本文转载自: https://blog.csdn.net/tyustli/article/details/135121849
版权归原作者 tyustli 所有, 如有侵权,请联系我们删除。

“linux 驱动——私有数据”的评论:

还没有评论