【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    上次我们编写了一个简单的字符设备,但是涉及的内容比较少,只有open和read两个函数。今天,我们打算在此基础上扩充一下内容。基本的思路是这样的:(1)编写字符设备下需要处理的各个函数,包括open、release、read、write、ioctl、lseek函数;(2)编写一个用户侧的程序来验证我们编写的驱动函数是否正确。当然,我们编写的代码部分参考了宋宝华先生的《linux设备驱动开发详解》一书,在此说明一下。
    在开始今天的内容之前,其实有一些题外话可以和大家分享一下。自从工作以来,我个人一直都有一个观点。那就怎么样利用简单的代码来说明开发中的问题,或者是解释软件中的原理,这是一个很高的学问。有些道理看上去云里雾里说不清楚,其实都可以通过编写代码来验证的。os可以、cpu可以、cache可以、编译器可以、网络协议也可以,很多很多的内容完全可以通过几行代码就可以表达得非常清楚,但是事实上我们并没有这么做。我想原因无非是这么几条,一来授业者对相关知识的学习也是停留在概念上而已,二来我们的学习过于死板和教条、太关注知识、不求实践,三就是学习者自身缺少思考的能力、缺少自我反省的能力、对很多东西不求甚解。对于简单的linux设备,我们完全可以通过这几行代码说清楚问题,免得大家还要苦苦追寻,百思而不得入门。
    好了,说了这么多,我们看看现在的驱动代码是怎么修改的把。
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>#define CHRMEM_SIZE 0x1000
#define MEM_CLEAR   0x1static int chr_major;struct chr_dev
{struct cdev cdev;unsigned char mem[CHRMEM_SIZE];
};struct chr_dev* char_devp;int chr_open(struct inode* inode, struct file* filp)
{filp->private_data = char_devp;return 0;
}int chr_release(struct inode* inode, struct file* filp)
{return  0;
}static int chr_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg)
{struct chr_dev* dev = filp->private_data;switch(cmd){case MEM_CLEAR:memset(dev->mem, 0, CHRMEM_SIZE);break;default:return -EINVAL;}return 0;
}static ssize_t chr_read(struct file* filp, char __user* buf, size_t size, loff_t* ppos)
{unsigned long p = *ppos;unsigned int count = size;int ret = 0;struct chr_dev* dev = filp->private_data;if(p >= CHRMEM_SIZE){return 0;}if(count > CHRMEM_SIZE - p){return 0;}if(copy_to_user(buf, (void*)(dev->mem + p), count)){return -EINVAL;}else{*ppos += count;ret = count;}return ret;
}static ssize_t chr_write(struct file* filp, const char __user* buf, ssize_t size, loff_t *ppos)
{unsigned long p = *ppos;unsigned int count = size;int ret = 0;struct chr_dev* dev = filp->private_data;if(p >= CHRMEM_SIZE){return 0;}if(count > CHRMEM_SIZE - p){count = CHRMEM_SIZE - p;}if(copy_from_user(dev->mem + p, buf, count)){ret = -EINVAL;}else{*ppos += count;ret = count;}return ret;
}static loff_t chr_llseek(struct file* filp, loff_t offset, int orig)
{loff_t ret = 0;/* orig can be SEEK_SET, SEEK_CUR, SEEK_END */switch(orig){case 0:if(offset < 0){ret = -EINVAL;break;}if((unsigned int) offset > CHRMEM_SIZE){ret = -EINVAL;break;}filp->f_pos = (unsigned int) offset;ret = filp->f_pos;break;case 1:if((filp->f_pos + offset) > CHRMEM_SIZE){ret = -EINVAL;break;}if((filp->f_pos + offset) < 0){ret = -EINVAL;break;}filp->f_pos += offset;ret = filp->f_pos;break;default:ret = - EINVAL;break;}return ret;
}static const struct file_operations chr_ops =
{.owner    = THIS_MODULE,.llseek   = chr_llseek,.read     = chr_read,.write    = chr_write,.ioctl    = chr_ioctl,.open     = chr_open,.release  = chr_release
};static void chr_setup_cdev(struct chr_dev* dev, int index)
{int err;int devno = MKDEV(chr_major, index);cdev_init(&dev->cdev, &chr_ops);dev->cdev.owner = THIS_MODULE;err = cdev_add(&dev->cdev, devno, 1);if(err){printk(KERN_NOTICE "Error happend!\n");}
}int chr_init(void)
{int result;dev_t ndev;result = alloc_chrdev_region(&ndev, 0, 1, "chr_dev");  if(result < 0 )  {  return result;  }   printk("chr_init(): major = %d, minor = %d\n", MAJOR(ndev), MINOR(ndev));chr_major = MAJOR(ndev);char_devp = kmalloc(sizeof(struct chr_dev), GFP_KERNEL);if(!char_devp){result = -ENOMEM;goto final;}memset(char_devp, 0, sizeof(struct chr_dev));chr_setup_cdev(char_devp, 0);return 0;final:unregister_chrdev_region(ndev, 1);return 0;
}void chr_exit()
{cdev_del(&char_devp->cdev);kfree(char_devp);unregister_chrdev_region(MKDEV(chr_major, 0), 1);
}module_init(chr_init);
module_exit(chr_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("feixiaoxing!163.com");
MODULE_DESCRIPTION("A simple device example!");

不可否认,我们的代码出现了更多的内容,但是基本框架还是一致的。要是说区别,无非就是我们在原来的基础上添加了新的处理函数而已。说起来,我们对于设备的主要操作也就是这么几种,大家如果对此的概念已经非常成熟了,那么后面的学习就会轻松很多。当然和之前的驱动一样,我们也需要make &  insmod char.ko & mknod /dev/chr_dev c 249 0。接下来,为了验证上述的内容是否正确,编写一段简单的测试代码是必不可少的。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>#define MEM_CLEAR 0x01
#define CHAR_DEV_NAME "/dev/chr_dev"int main()
{int ret;int fd;int index;char buf[32];/* open device */fd = open(CHAR_DEV_NAME, O_RDWR | O_NONBLOCK);if(fd < 0){printf("open failed!\n");return -1;}/* set buffer data, which will be stored into device */for(index = 0; index < 32; index ++){buf[index] = index;}/* write data */write(fd, buf, 32);memset(buf, 0, 32);/* read data */lseek(fd, 0, SEEK_SET);read(fd, buf, 32);for(index = 0; index < 32; index ++){printf("data[%d] = %d\n", index, buf[index]);}/* reset all data to zero, read it and check whether it is ok */ioctl(fd, MEM_CLEAR, NULL);lseek(fd, 0, SEEK_SET);read(fd, buf, 32);for(index = 0; index < 32; index ++){printf("data[%d] = %d\n", index, buf[index]);}close(fd);return 0;
}

细心的朋友可能发现了,我们在用户侧代码中使用了很多的处理函数,基本上从open、release、read、write、lseek、ioctl全部包括了。测试代码处理的流程也非常简单,首先打开设备,接着写数据,后面就是读取数据,最后利用ioctl清除数据,程序返回。因为代码中包含了注释的内容,在此我们就不过多赘述了。大家慢慢看代码,应该都会了解和明白的。注意,用户测的代码也要在sudo模式下执行。

    希望以上的这段内容对大家有所帮助。

linux驱动编写(字符设备编写框架)相关推荐

  1. 【linux驱动之字符设备驱动基础】

    linux驱动之字符设备驱动基础 文章目录 linux驱动之字符设备驱动基础 前言 一.开启驱动学习之路 二.驱动预备知识 三.什么是驱动? 3.1 驱动概念 3.2 linux 体系架构 3.3 模 ...

  2. Linux驱动之字符设备驱动

    系列文章目录 第一章 Linux入门之驱动框架 第二章 Linux驱动之字符设备驱动 文章目录 系列文章目录 前言 一.认识字符设备驱动 1.基本概念 2.基本概念 二.字符设备旧框架 1.注册和注销 ...

  3. linux驱动之字符设备

    linux驱动之字符设备 linux驱动设备分类 linux驱动分为了三种驱动: 字符设备: 字符设备和应用程序之间是以字节进行进行数据交换的.在进行数据交换的时候数据是以一定顺序进行传输的,传输是实 ...

  4. 嵌入式linux驱动之———字符设备驱动(一)

    一.简介: 在Linux内核驱动中,字符设备是最基本的设备驱动.字符设备是能够像字节流(比如文件)一样被访问的设备,就是说对它的读写是以子为单位的.比如串口在进行收发数据时就是一个字节一个字节进行的. ...

  5. linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架

    还是老规矩先上代码 demo.c #include #include#include#include#include int demo_major = 250;int demo_minor = 0;i ...

  6. Linux驱动之 字符设备 ioctl接口使用

    字符设备ioctl接口使用: Linux驱动编写除了对设备进行读写数据之外,通常还希望可以对设备进行控制. 从应用层传递一些命令参数,并在驱动层实现相应设备操作,这时候就用到了 ioctl函数: 应用 ...

  7. 【Linux驱动】字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面 ...

  8. linux驱动学习——字符设备号

    字符设备号本质就是一个32位的无符号整型值.高12位为主设备号:低20位为次设备号. 查看设备号 cat /proc/devices 4.1.构造设备号 源码路径: include/linux/kde ...

  9. Linux驱动笔记-字符设备,块设备,网络设备

      在Linux设备驱动开发中,粗略的将设备分为三种类型:字符设备,块设备和网络设备. 1.字符设备:指能够像字节流串行顺序依次进行访问的设备,对它的读写是以字节为单位.字符设备的上层没有磁盘文件系统 ...

  10. linux 驱动开发 --- 字符设备与混杂设备区别

    2019独角兽企业重金招聘Python工程师标准>>> 一.主设备号的生成方式不同 1.所有的混杂设备都被分配一个主设备号10,次设备号系统自动生成 2.字符设备,的主设备号,开发驱 ...

最新文章

  1. 能做pc网页吗_梦幻西游网页版:如今还能抽金伙伴吗?玩家亲自验证,感觉还行...
  2. 大厂都拿捏的缓存方案,平台级分布式缓存,什么业务才合适?
  3. 基于Java的RDMA高性能通信库(四):DaRPC
  4. Android 使用jarsigner给apk签名的方法详细介绍
  5. MariaDb数据库管理系统的学习(一)安装示意图
  6. [家里蹲大学数学杂志]第041期中山大学数计学院 2008 级数学与应用数学专业《泛函分析》期末考试试题 A...
  7. 如何评价周志华深度森林模型
  8. 地温梯度 河南_河南省地热(温泉)分布规律
  9. css阿拉伯数字,css 古文排版(含阿拉伯数字)
  10. vtigerCRM 是作为一种开源CRM软件
  11. 4根网线水晶头接法(8根只接4根即可通讯)
  12. java中的进制转换(十进制和二进制)
  13. 计算机国际会议 2017,2017计算机辅助设计与图形学国际会议(CAD/Graphics 2017)在张家界召开...
  14. coalesce()函数详解
  15. web前端从入门到放弃
  16. Matrix Profile介绍
  17. Python Selenium 抖音直播平台实现自动发送评论
  18. 『无为则无心』Python函数 — 32、递归
  19. python提取word文件中的图片,并上传阿里云OSS,返回html图片标签
  20. 会员管理系统源码 php语言开发 可用于美容店,理发店,服装店

热门文章

  1. Android:如何从堆栈中还原ProGuard混淆后的代码
  2. Android github上的好的开源项目汇总
  3. 对Chrome自动发送邮件插件的改进
  4. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图
  5. Android开发之TextView的滚动显示
  6. OBIEE 11g 启动与停止包含服务器重启
  7. struts验证框架失效
  8. Android设备上使用WiFinspect抓取网络通讯包
  9. 使用asp.net mvc开发应用程序,页面中的page.IsPostback还有用处吗?
  10. 对话框响应WM_KEYDOWN消息