在编写Linux内核驱动程序的时候,如果不动态生成设备号的话,需要自己手动分配设备号,有可能你分配的设备号会与已有设备号相同而产生冲突。因此推荐自动分配设备号。使用下面的函数:

int alloc_chrdev_region(dev_t *dev,  unsigned baseminor,  unsigned count,  const char *name)

该函数需要传递给它指定的第一个次设备号baseminor(一般为0)和要分配的设备数count,以及设备名,调用该函数后自动分配得到的设备号保存在dev中。

当使用了alloc_chrdev_region()动态分配设备号之后,需要依次使用:

cdev_init(struct cdev * cdev,const struct file_operations * fops)

cdev_add(struct cdev * p,dev_t dev,unsigned count)

将字符设备注册到内核中。通过上面三个函数就可以动态生成设备号了。

在卸载的时候需要使用:unregister_chrdev_region(dev_t from,unsigned count) 来释放设备编号

动态创建设备号之后,将驱动加载到内核,通过 : cat /proc/devices   命令可以查看设备号

如果上层应用程序需要访问驱动程序,则需要为该驱动创建设备节点。

如果手动创建设备结点需要这样做:(这里假设通过 cat /proc/devices 发现字符设备 CDEV_ZHU的设备号为 254)

$mknod  /dev/CDEV_ZHU c 254 0

如果我们在驱动里面动态创建的话需要这样做:

cdev_class = class_create(owner,name)         // cdev_class 为 struct class 类型

然后使用:

device_create(_cls,_parent,_devt,_device,_fmt)

当动态创建了设备节点之后,在卸载的时候需要使用:

device_destroy(_cls,_device) class_destroy(struct class * cls)

来销毁设备和类。

下面给出一组测试代码:(该组代码实现了应用程序通过打开驱动访问和修改驱动的一个全局变量 “global_var”)

/*驱动部分:globalvar.c */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/device.h>  //下面这三个头文件是由于动态创建需要加的
#include <linux/device.h>
#include <linux/cdev.h>

MODULE_LICENSE("GPL");
 
#define DEVICE_NAME  "CDEV_ZHU"
static struct class *cdev_class;
 
static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);
 
//初始化字符设备驱动的 file_operations 结构体
struct file_operations globalvar_fops = 
{
    read: globalvar_read,
    write: globalvar_write,
};

static int global_var = 0;      //CDEV_ZHU设备的全局变量

dev_t dev = 0;                 //这里是动态分配设备号和动态创建设备结点需要用到的
struct cdev  dev_c;
 
static int __init globalvar_init(void)
{
    int ret,err;
 
    //注册设备驱动
 
    ret = alloc_chrdev_region(&dev, 0, 1,DEVICE_NAME); //动态分配设备号
    if (ret)
    {
        printk("globalvar register failure\n"); 
    unregister_chrdev_region(dev,1);
    return ret;
    }
    else
    {
        printk("globalvar register success\n");
    }

cdev_init(&dev_c, &globalvar_fops);
 
   err = cdev_add(&dev_c, dev, 1);

if(err)
   {
    printk(KERN_NOTICE "error %d adding FC_dev\n",err);
    unregister_chrdev_region(dev, 1);
    return err;
   }
 
 cdev_class = class_create(THIS_MODULE, DEVICE_NAME);//动态创建设备结点
 if(IS_ERR(cdev_class))
 { 
        printk("ERR:cannot create a cdev_class\n");  
    unregister_chrdev_region(dev, 1);
    return -1;
    }
 device_create(cdev_class,NULL, dev, 0, DEVICE_NAME);
 
    return ret;
}
 
static void __exit globalvar_exit(void)
{
 
    //注销设备驱动 
    
 device_destroy(cdev_class, dev);
 class_destroy(cdev_class);
 unregister_chrdev_region(dev,1);
 printk("globalvar_exit \n");
}
 
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
    //将 global_var 从内核空间复制到用户空间
    if(copy_to_user(buf, &global_var, sizeof(int)))
    {
        return    - EFAULT;    
    }  
    return sizeof(int);
}
 
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
    //将用户空间的数据复制到内核空间的 global_var
    if(copy_from_user(&global_var, buf, sizeof(int)))
    {
        return    - EFAULT;
    }  
    return sizeof(int);
}
 
module_init(globalvar_init);
module_exit(globalvar_exit);

/*应用程序: globalvartest.c  */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
    int fd, num;
    //打开"/dev/CDEV_ZHU"
    fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR);
    if (fd != -1 )
    {
      //初次读 global_var
        read(fd, &num, sizeof(int));
        printf("The globalvar is %d\n", num);
 
      //写 global_var
        printf("Please input the num written to globalvar\n");
        scanf("%d", &num);
        write(fd, &num, sizeof(int));
 
      //再次读 global_var
        read(fd, &num, sizeof(int));
        printf("The globalvar is %d\n", num);
 
        //关闭“/dev/CDEV_ZHU”
        close(fd);
    }
    else
    {
        printf("Device open failure\n");
    }

return 0;
}

说明:这个程序是我修改了“深入浅出Linux设备编程”这本书的代码的来的,在项目中使用动态创建设备节点和动态生成设备号比较方便,于是就在这里分享了。

使用一个简单的makefile将(驱动) globalvar.c  编译过后 使用 insmod globalvar.ko 将驱动加载到内核,然后就将globalvartest.c 生成的可执行文件运行起来就可以操作驱动中的全局变量了。不用像书上一样还要在命令行去创建设备节点。

我使用的内核版本是2.6.33.4 。

转载于:https://www.cnblogs.com/zhuyp1015/archive/2012/05/22/2514008.html

Linux字符驱动中动态分配设备号与动态生成设备节点相关推荐

  1. 关于linux字符驱动中read函数filp->f_pos 和 loff_t *ppos的关系

    在学习linux 字符驱动的时候会有这样的困惑 比如我们实现一个字符驱动的读函数,如下 static ssize_t globalmem_read(struct file *filp, char __ ...

  2. Linux字符驱动开发学习总结

    linux驱动编写(虚拟字符设备编写) 昨天我们说了一些简单模块编写方法,但是终归没有涉及到设备的编写内容,今天我们就可以了解一下相关方面的内容,并且用一个实例来说明在linux上面设备是如何编写的. ...

  3. Linux字符驱动设备开发

    一.基础知识 参考博客:18 linux字符设备驱动之设备号_jklinux的博客-CSDN博客 创建设备驱动的目的,通常是让用户程序来调用.一般我们使用字符设备文件来提供接口,使用户进程可以访问操作 ...

  4. Linux字符驱动开发

    Linux字符驱动简介 字符设备驱动简介 举个栗子 file_operations 结构体 字符设备驱动开发步骤 驱动模块的加载和卸载 字符设备的注册和注销 添加 LICENSE 和作者信息 Linu ...

  5. 嵌入式linux led驱动有几种写法,嵌入式Linux字符驱动LED灯设计

    一.任务要求 完成一个字符IO口驱动,在开发板上该IO口对应LED灯.该驱动程序通过控制IO口的高低电平来控制亮灭.同时要写一个应用层的测试程序,用来测试驱动程序.我的测试程序为myled_test. ...

  6. [Linux字符驱动] DIDO 74HC595实现遥控遥信功能

    项目中经常会使用YK和YX功能,DI操作,简单来说就是外部输入高电平,软件检测信号就为1:外部信号输入低电平,软件检测信号就为0:依据这样的设计,我们来看一下字符驱动该如何完成. 下面介绍一种有IO控 ...

  7. linux字符驱动之自动创建设备节点

    上一节中,我们是手工创建设备节点,大家肯定也会觉得这样做太麻烦了. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/details/10430270 ...

  8. linux 字符驱动阻塞型 等待队列

    2019独角兽企业重金招聘Python工程师标准>>> 内核等待队列 等待队列 在linux驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程 ...

  9. linux字符驱动之点亮LED

    上一节中,我们讲解了如何自动创建设备节点,这一节我们在上一节的基础上,实现点亮LED. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/detail ...

最新文章

  1. [C++再学习系列] 前置++与后置++
  2. Python3并发检验代理池地址
  3. C++vector容器学习
  4. Facets:评估机器学习数据集质量利器 (来自Google、可交互、可可视化)
  5. 每天十分钟系列:JS数据操作之神奇的map()
  6. node.js应用生成windows server的plugin——winser
  7. 车辆销售系统用例_使用OpenCV和Python构建自己的车辆检测模型
  8. margin-top的兼容问题
  9. 将Ubuntu从Win7的魔爪中拯救出来
  10. 小学steam计算机课程案例,STEAM课程典型案例——桥世界
  11. Android Studio模拟器启动时显示Could not automotically detect an ADB binary
  12. Virtual host / experienced an error on node rabbit@ xx and may be inaccessible Totals问题的解决
  13. [Memcache] 初探Memcache
  14. HFSS15 win10_64位破解
  15. H5项目常见问题及注意事项
  16. JAVA String.format详解
  17. 云端办公后,协同软件也能轻松做好项目管理
  18. 在线客服 上下滚动 qq 简单明了 绝对不会报错 大众的选择 在线客服qq
  19. 50个好用的前端框架,千万收好以留备用!
  20. Delphi 10 Seattle小票打印控件TQ_Printer

热门文章

  1. python程序设计报告-20183122 实验一《Python程序设计》实验报告
  2. python教程书籍推荐-推荐几本对于Python初学者比较好的书籍(内含PDF)
  3. python软件代码示例-python 示例代码1
  4. python中文解释-python注释和2版本的中文乱码
  5. python中文版-Python3.8.2下载
  6. python填写excel-Python|读、写Excel文件(三种模块三种方式)
  7. python编程入门指南pdf-python编程初学者指南
  8. python在日常工作处理中的应用-python在工作中的应用场景介绍
  9. 上海python培训班-上海哪家python培训班比较靠谱?
  10. python培训费用-上海python培训费用多少?