以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,如有侵权,请告知删除。

1、问题描述

  • 使用mknod创建设备文件的缺点;
  • 能否自动生成和删除设备文件;

2、解决方案:udev(嵌入式中用的是mdev),什么是udev?

  • 应用层的一个应用程序;
  • 内核驱动和应用层udev之间有一套信息传输机制(netlink协议);
  • 应用层启用udev,内核驱动中使用相应接口;
  • 驱动注册和注销时信息会被传给udev,由udev在应用层进行设备文件的创建和删除;

3、内核驱动设备类相关函数

  • class_create
  • device_create

4、编程实践

注册字符设备驱动完成后,添加设备类的操作,以让内核帮我们发信息!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  

#include <linux/module.h>      // module_init  module_exit
#include <linux/init.h>           // __init   __exit
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>       // arch/arm/mach-s5pv210/include/mach/gpio-bank.h
#include <linux/string.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
#include <linux/device.h>//#define MYMAJOR        200
#define MYCNT       1
#define MYNAME      "testchar"#define GPJ0CON     S5PV210_GPJ0CON
#define GPJ0DAT     S5PV210_GPJ0DAT#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT    *((volatile unsigned int *)GPJ0DAT)#define GPJ0CON_PA   0xe0200240
#define GPJ0DAT_PA  0xe0200244unsigned int *pGPJ0CON;
unsigned int *pGPJ0DAT;//int mymajor;
static dev_t mydev;
//static struct cdev test_cdev;
static struct cdev *pcdev;
static struct class *test_class;char kbuf[100];         // 内核空间的bufstatic int test_chrdev_open(struct inode *inode, struct file *file)
{// 这个函数中真正应该放置的是打开这个设备的硬件操作代码部分// 但是现在暂时我们写不了这么多,所以用一个printk打印个信息来做代表。printk(KERN_INFO "test_chrdev_open\n");rGPJ0CON = 0x11111111;rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));     // 亮return 0;
}static int test_chrdev_release(struct inode *inode, struct file *file)
{printk(KERN_INFO "test_chrdev_release\n");rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));return 0;
}ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{int ret = -1;printk(KERN_INFO "test_chrdev_read\n");ret = copy_to_user(ubuf, kbuf, count);if (ret){printk(KERN_ERR "copy_to_user fail\n");return -EINVAL;}printk(KERN_INFO "copy_to_user success..\n");return 0;
}// 写函数的本质就是将应用层传递过来的数据先复制到内核中,然后将之以正确的方式写入硬件完成操作。
static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos)
{int ret = -1;printk(KERN_INFO "test_chrdev_write\n");// 使用该函数将应用层传过来的ubuf中的内容拷贝到驱动空间中的一个buf中//memcpy(kbuf, ubuf);       // 不行,因为2个不在一个地址空间中memset(kbuf, 0, sizeof(kbuf));ret = copy_from_user(kbuf, ubuf, count);if (ret){printk(KERN_ERR "copy_from_user fail\n");return -EINVAL;}printk(KERN_INFO "copy_from_user success..\n");if (kbuf[0] == '1'){rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));}else if (kbuf[0] == '0'){rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));}/*// 真正的驱动中,数据从应用层复制到驱动中后,我们就要根据这个数据// 去写硬件完成硬件的操作。所以这下面就应该是操作硬件的代码if (!strcmp(kbuf, "on")){rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));}else if (!strcmp(kbuf, "off")){rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));}
*/return 0;
}// 自定义一个file_operations结构体变量,并且去填充
static const struct file_operations test_fops = {.owner        = THIS_MODULE,             // 惯例,直接写即可.open     = test_chrdev_open,            // 将来应用open打开这个设备时实际调用的.release = test_chrdev_release,     // 就是这个.open对应的函数.write         = test_chrdev_write,.read      = test_chrdev_read,
};// 模块安装函数
static int __init chrdev_init(void)
{   int retval;printk(KERN_INFO "chrdev_init helloworld init\n");// 使用新的cdev接口来注册字符设备驱动// 新的接口注册字符设备驱动需要2步// 第1步:分配主次设备号retval = alloc_chrdev_region(&mydev, 12, MYCNT, MYNAME);if (retval < 0) {printk(KERN_ERR "Unable to alloc minors for %s\n", MYNAME);goto flag1;}printk(KERN_INFO "alloc_chrdev_region success\n");printk(KERN_INFO "major = %d, minor = %d.\n", MAJOR(mydev), MINOR(mydev));// 第2步:注册字符设备驱动pcdev = cdev_alloc();           // 给pcdev分配内存,指针实例化//cdev_init(pcdev, &test_fops);pcdev->owner = THIS_MODULE;pcdev->ops = &test_fops;retval = cdev_add(pcdev, mydev, MYCNT);if (retval) {printk(KERN_ERR "Unable to cdev_add\n");goto flag2;}printk(KERN_INFO "cdev_add success\n");// 注册字符设备驱动完成后,添加设备类的操作,以让内核帮我们发信息!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!// 给udev,让udev自动创建和删除设备文件test_class = class_create(THIS_MODULE, "aston_class");//类名if (IS_ERR(test_class))return -EINVAL;// 最后1个参数字符串,就是我们将来要在/dev目录下创建的设备文件的名字// 所以我们这里要的文件名是/dev/testdevice_create(test_class, NULL, mydev, NULL, "test");// 使用动态映射的方式来操作寄存器if (!request_mem_region(GPJ0CON_PA, 4, "GPJ0CON"))
//      return -EINVAL;goto flag3;if (!request_mem_region(GPJ0DAT_PA, 4, "GPJ0CON"))
//      return -EINVAL;goto flag3;pGPJ0CON = ioremap(GPJ0CON_PA, 4);pGPJ0DAT = ioremap(GPJ0DAT_PA, 4);*pGPJ0CON = 0x11111111;*pGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));      // 亮//goto flag0:return 0;// 如果第4步才出错跳转到这里来 release_mem_region(GPJ0CON_PA, 4);release_mem_region(GPJ0DAT_PA, 4);// 如果第3步才出错跳转到这里来
flag3:cdev_del(pcdev);// 如果第2步才出错跳转到这里来
flag2:// 在这里把第1步做成功的东西给注销掉unregister_chrdev_region(mydev, MYCNT);
// 如果第1步才出错跳转到这里来
flag1:  return -EINVAL;
//flag0:
//  return 0;
}// 模块下载函数
static void __exit chrdev_exit(void)
{printk(KERN_INFO "chrdev_exit helloworld exit\n");*pGPJ0DAT = ((1<<3) | (1<<4) | (1<<5)); // 解除映射iounmap(pGPJ0CON);iounmap(pGPJ0DAT);release_mem_region(GPJ0CON_PA, 4);release_mem_region(GPJ0DAT_PA, 4);/*   // 在module_exit宏调用的函数中去注销字符设备驱动unregister_chrdev(mymajor, MYNAME);
*/  device_destroy(test_class, mydev);class_destroy(test_class);// 使用新的接口来注销字符设备驱动// 注销分2步:// 第一步真正注销字符设备驱动用cdev_delcdev_del(pcdev);// 第二步去注销申请的主次设备号unregister_chrdev_region(mydev, MYCNT);
}module_init(chrdev_init);
module_exit(chrdev_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");                // 描述模块的许可证
MODULE_AUTHOR("aston");               // 描述模块的作者
MODULE_DESCRIPTION("module test");    // 描述模块的介绍信息
MODULE_ALIAS("alias xxx");            // 描述模块的别名信息

字符设备驱动高级篇3——自动创建字符设备驱动的设备文件相关推荐

  1. Linux:驱动之自动创建字符设备的设备文件(未完)

    自动创建字符设备的设备文件 目前尚不是最终版本,还望有心人自己学习的时候,把自己整合的知识点相关的答案也好问题也好,或者实践过程中的一些操作截图,再或者其他的一些想要分享材料发给笔者邮箱:uestc_ ...

  2. 字符设备驱动高级篇4——设备类(自动创建和删除设备文件)相关代码分析

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 主要涉及class_create和device_create函数. 1.sys文件系统简介 (1)sys文件系统的 ...

  3. 字符设备驱动高级篇6——内核提供的读写寄存器接口

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 1.前面访问寄存器的方式 通过定义指向寄存器的指针,然后解引用来对寄存器进行操作. (1)行不行?sure! (2 ...

  4. 字符设备驱动高级篇1——新接口介绍

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.概览 1.新接口与老接口 (1)老接口:register_chrdev() 通过第一个参数是否为0,判断内核是 ...

  5. 龙芯2k按键中断驱动_字符设备驱动-高级篇按键中断程序驱动

    驱动源码: #include "linux/module.h" #include"linux/kernel.h" #include"linux/fs. ...

  6. 字符设备驱动高级篇5——静态映射表、动态映射结构体方式操作寄存器

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.静态映射表建立过程分析 1.建立映射表的三个关键部分 (1)映射表描述 具体物理地址和虚拟地址的值相关的宏定义 ...

  7. 字符设备驱动高级篇2——字符设备驱动注册代码分析

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 1.老接口register_chrdev分析 (1)代码函数调用关系 register_chrdev __regi ...

  8. RK3399平台开发系列讲解(内核驱动外设篇)6.17、VOP驱动解析

    平台 内核版本 安卓版本 RK3399 Linux4.4 Android7.1 文章目录 代码位置: 结构介绍: 寄存器读写: 图层接口: vop接口: 代码位置: kernel/drivers/gp ...

  9. Linux系统aboutyou,Linux字符设备驱动高级

    设备号:主设备号 + 次设备号   也可以叫主次设备号 新接口注册字符设备驱动,其实就是填充这个struct cdev类型的结构体,主要填充的内容就是 file_operations这个结构体变量,让 ...

最新文章

  1. 3.推荐系统(矩阵分解)
  2. 【DataGuard】ORA-16014 and ORA-00312 Messages in Alert.log of Physical Standby
  3. Data Mining Tools
  4. android canvas_Android自定义View之绘制虚线
  5. 标机电脑上安装yarn
  6. supervisord的安装使用
  7. 超详细目标检测,yolo3训练自己的数据集
  8. word光标一直闪动_搞清楚啥是回车符,Word格式问题就解决了92.5%
  9. [react-native]react-native填坑笔记
  10. Oracle如何实现跨库查询
  11. 多维度积分管理系统java_Java毕业设计——超市积分管理系统项目设计
  12. 电脑、手机上那些让人用后欲罢不能的神器(附百度云链接)
  13. PHP 对接阿里云短信
  14. 【AI视野·今日CV 计算机视觉论文速览 第228期】Tue, 29 Jun 2021
  15. 虚拟现实(VR)技术的升级应用|时空克隆 三维视频融合 投影融合 点卯 魔镜系列
  16. [MOT学习笔记]JDE损失函数详解
  17. A-level 课程:最受欢迎和最不受欢迎的学科
  18. python网格搜索优化参数_python - 用于管道的网格搜索参数网格的说明 - SO中文参考 - www.soinside.com...
  19. 去除 csv 文件中的重复行
  20. ESP32使用freeRTOS的消息队列

热门文章

  1. bzoj4950(二分图最大匹配)
  2. IBM SOA[ESB,BPM,Portal等]基础架构图解
  3. 树莓派基金会来号召用键盘生物学家研究企鹅
  4. Python 数据类型--Bytes类型
  5. Linux学习记录-文件、目录与磁盘
  6. 一份从 0 到 1 的 Java 项目实践清单
  7. 根据 设备名(br0/eth0/em0)称获取 当前机器的IP地址与子网掩码信息
  8. QTP提供的编程接口实现对QTP操作
  9. 利用dbstart和dbshut脚本自动启动和停止数据库的问题
  10. centos 7上ambari安装试用