linux驱动文件操作简单介绍

1、设备号

主设备号标识设备对应的驱动程序,次设备号由内核使用,用于确定设备文件所指的设备。

通过次设备号获得一个指向内核设备的直接指针,也可将此设备号当作设备本地数组的索引。

设备编号用dev_t表示(Linux/types.h  32位,其中12位表示主设备号,20位表示次设备号)。

dev_t获得主设备号或次设备号:MAJOR(dev_t dev); MINOR(dev_t dev)

已知主设备号和次设备号来获取dev_t类型:MKDEV(int  major,  int  minor)

获取一个或多个设备编号int  register_chrdev_region(dev_t first,  unsigned int  count,  char  *name);(静态分配,事先已知道设备号)

动态分配设备编号int  alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);调用成功后dev会保存已分配的第一个编号。

释放设备编号:void unregister_chrdev_region(dev_t first, unsigned int count);

接下来,驱动程序需要将设备编号和内部函数连接起来。

注:(下一步可尝试采用动态分配设备号

 

动态分配设备号缺点:不能预先创建设备节点(因为分配的设备号不能保证始终一致)。

2、文件操作file_operations:

这些操作将与设备编号连接起来。

__user:用于文档,表明该指针是一个用户空间地址。

主要成员:open,  ioctl,  read,  write,  llseek

3struct file结构  linux/fs.h文件描述符

每打开一个文件,内核就会创建一个对应的file结构,在open()时创建,同时会传递给在该文件上进行操作的所有函数(因为file结构中包含file_operations结构,而该结构包含了所有驱动操作的函数)。

内核中用filp作为执行file结构的指针。

主要成员:

Mode_t  f_mode;  loff_t  f_pos;   struct file_operations *f_pos;  void  private_data; 

4inode结构

对单个文件只有一个inode,而可能有多个file(由于forkdup操作)

主要成员:

dev_t  i_rdev; 对表示设备文件的inode结构,该字段包含真正的设备编号。

struct cdev *i_cdev;   该结构表示字符设备的内核的内部结构,当inode指向一个字符设备文件时,该字段包含指向struct cdev结构的指针。

inode中获取设备号: iminor(struct inode *inode);  imajor(inode);

5、字符设备注册  /linux/cdev.h

内核使用struct cdev结构表示字符设备,所以在内核调用该设备操作之前,需要分配并注册一个或者多个该结构。

注册有两种方式:

新方法:

1)定义字节的结构:

struct my_dev {

         struct  cdev  cdev; //此处如果定义的是指针类型,则需要申请分配内存

}my_dev;

//my_dev ->cdev = cdev_alloc();  //如果cdev是指针则需要这一步

my_dev->cdev.ops = &my_fops;

my_dev->cdev.owner = THIS_MODULE;

2)再调用cdev_init(struct cdev *cdev,  struct file_operations *fops);

3)调用cdev_add(struct cdev *dev,  dev_t num,  unsigned int count);

上面每一步都要判断函数调用是否出错。

旧办法(老接口):

注册:int register_chrdev();移除:int unregister_chrdev()

 

6、各操作函数实现

1open   int (*open) (struct  inode  *inode,  struct  file  *filp)

完成以下工作:传入一个inode,创建一个file结构

n  检查设备特定错误(如未就绪);

n  如果设备首次打开,则进行初始化;

n  必要时更新f_op指针;

n  分配并填写filp->private_data

注:inode结构是传入的参数,对应一个特定的设备(这就是为什么要在/devmknodde原因),而file结构的filp是要修改的参数(传出),对应该设备的一个文件描述符,也就是一个inode可能有多个file描述符,而每个描述符需要保存inode的信息,即存放在filp->private_data中。

2release  int (*release) (struct inode *inode,  struct file *filp)

完成工作:传入一个inode,释放这个file结构

n  释放由open分配的、保存在filp->private_data中的内容;

n  在最后一次close时关闭设备

dup fork都会在不调用open时创建新的file结构(对应同一个inode)。

注:并不是每个close调用都会调用release;只有真正释放设备数据结构的close调用才会调用release。内核对每个file结构维护其被使用次数的计数器,无论是fork还是dup,都不会创建新的数据结构(只会有open创建),它们只是增加已有结构中的计数器而已。只有在file结构的计数为0时,close才会调用release

3read  ssize_t  read(struct  file  *filp,  char __user *buf,  count,  loff_t *offp)

完成工作:传入file,将count个字节数据写入用户地址buf,修改loff_t

copy_to_user()实现
返回值说明:

n  等于count:所请求的字节数读取成功;

n  返回值为正,但小于count:只读取了部分数据;

n  0:已经达到文件尾;

n  负值:出错

4write  ssize_t  write(struct  file  *filp,  char  __user *buf,  count,  offp);

copy_from_user()实现

返回值同上。

 

[cpp] view plaincopy
  1. 1)驱动代码  
  2. Demo.h  
  3. #ifndef _DEMO_H_  
  4. #define _DEMO_H_  
  5. #include <linux/ioctl.h>  
  6. /*Macros to help debuging*/  
  7. #undef PDEBUG  
  8. #ifdef DEMO_DEBUG  
  9.     #ifdef __KERNEL__  
  10.         #define PDEBUG(fmt, args...) printk(KERN_DEBUG "DEMO:" fmt,## args)   
  11.     #else  
  12.         #define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)  
  13.     #endif  
  14. #else  
  15. #define PDEBUG(fmt, args...)   
  16. #endif  
  17.   
  18. #define DEMO_MAJOR 224  
  19. #define DEMO_MINOR 0  
  20. #define COMMAND1 1  
  21. #define COMMAND2 2  
  22.   
  23. struct demo_dev {  
  24.     struct cdev cdev;  
  25. };  
  26.   
  27. ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);  
  28. ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);  
  29. loff_t demo_llseek(struct file *filp, loff_t off, int whence);  
  30. int demo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);  
  31.   
  32. #endif  
  33. demo.c  
  34. #include <linux/module.h>  
  35. #include <linux/kernel.h>  
  36. #include <linux/fs.h>  
  37. #include <linux/errno.h>  
  38. #include <linux/types.h>  
  39. #include <linux/fcntl.h>  
  40. #include <linux/cdev.h>  
  41. #include <linux/version.h>  
  42. #include <linux/vmalloc.h>  
  43. #include <linux/ctype.h>  
  44. #include <linux/pagemap.h>  
  45. #include "demo.h"  
  46.   
  47. MODULE_AUTHOR("Yangjin");  
  48. MODULE_LICENSE("Dual BSD/GPL");  
  49.   
  50. struct demo_dev *demo_devices;  
  51.   
  52. static unsigned char demo_inc = 0;//全局变量,每次只能打开一个设备  
  53.   
  54. static u8 demo_buffer[256];  
  55.   
  56. int demo_open(struct inode *inode, struct file *filp)  
  57. {  
  58.     struct demo_dev *dev;  
  59.       
  60.     if (demo_inc > 0) return -ERESTARTSYS;  
  61.     demo_inc++;  
  62.     dev = container_of(inode->i_cdev, struct demo_dev, cdev);  
  63.     filp->private_data = dev;  
  64.   
  65.     return 0;  
  66. }  
  67.   
  68. int demo_release(struct inode *inode, struct file *filp)  
  69. {     
  70.     demo_inc--;  
  71.     return 0;  
  72. }  
  73.   
  74. ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)  
  75. {  
  76.     int result;  
  77.     loff_t pos = *f_pos; //pos: offset  
  78.   
  79.     if (pos >= 256) {  
  80.         result = 0;  
  81.         goto out;                                                                                                
  82.     }  
  83.     if (count > (256 - pos))  
  84.         count = 256 - pos;  
  85.     pos += count;  
  86.   
  87.     if (copy_to_user(buf, demo_buffer+*f_pos, count)) {  
  88.         count = -EFAULT;  
  89.         goto out;     
  90.     }  
  91.       
  92.     *f_pos = pos;  
  93. out:  
  94.     return count;  
  95. }  
  96.   
  97. ssize_t  demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)  
  98. {  
  99.     ssize_t retval = -ENOMEM;  
  100.     loff_t pos = *f_pos;  
  101.   
  102.     if (pos > 256)  
  103.         goto out;  
  104.     if (count > (256 - pos))   
  105.         count = 256 - pos;    
  106.     pos += count;  
  107.     if (copy_from_user(demo_buffer+*f_pos, buf, count)) {  
  108.         retval = -EFAULT;  
  109.         goto out;     
  110.     }  
  111.       
  112.     *f_pos = pos;  
  113.     retval = count;  
  114. out:  
  115.     return retval;  
  116. }  
  117.   
  118. int  demo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
  119. {  
  120.     if (cmd == COMMAND1) {  
  121.         printk("ioctl command 1 successfully\n");  
  122.         return 0;     
  123.     }  
  124.     if (cmd == COMMAND2) {  
  125.         printk("ioctl command 2 successfully\n");  
  126.         return 0;     
  127.     }  
  128.     printk("ioctl error\n");  
  129.     return -EFAULT;  
  130. }  
  131.   
  132. loff_t demo_llseek(struct file *filp, loff_t off, int whence)  
  133. {  
  134.     loff_t pos;  
  135.       
  136.     pos = filp->f_pos;  
  137.     switch (whence) {  
  138.     case 0:  
  139.         pos = off;  
  140.         break;  
  141.     case 1:  
  142.         pos += off;  
  143.         break;  
  144.     case 2:  
  145.     default:  
  146.         return -EINVAL;   
  147.     }  
  148.       
  149.     if ((pos > 256) || (pos < 0))  
  150.         return -EINVAL;  
  151.       
  152.     return filp->f_pos = pos;  
  153. }  
  154.   
  155. struct file_operations demo_fops = {  
  156.     .owner = THIS_MODULE,  
  157.     .llseek = demo_llseek,  
  158.     .read = demo_read,  
  159.     .write = demo_write,  
  160.     .ioctl = demo_ioctl,  
  161.     .open = demo_open,  
  162.     .release = demo_release,  
  163. };  
  164.   
  165. void demo_cleanup_module(void)  
  166. {  
  167.     dev_t devno = MKDEV(DEMO_MAJOR, DEMO_MINOR);  
  168.       
  169.     if (demo_devices) {  
  170.         cdev_del(&demo_devices->cdev);  
  171.         kfree(demo_devices);  
  172.     }  
  173.     unregister_chrdev_region(devno, 1);  
  174. }  
  175.   
  176. Init module流程:  
  177. 1)注册设备号MKDEV;  
  178. 2)注册设备驱动程序,即初始化cdev结构(嵌入到demo_devices结构中)  
  179. int demo_init_module(void)  
  180. {  
  181.     int result;  
  182.     dev_t dev = 0;  
  183.       
  184.     dev = MKDEV(DEMO_MAJOR, DEMO_MINOR);  
  185.     result = register_chrdev_region(dev, 1, "DEMO");  
  186.     if (result < 0) {  
  187.         printk(KERN_WARNING "DEMO: can't get major %d\n", DEMO_MAJOR);  
  188.         return result;  
  189.     }  
  190.     demo_devices = kmalloc(sizeof(struct demo_dev), GFP_KERNEL);  
  191.     if (!demo_devices) {  
  192.         result = -ENOMEM;  
  193.         goto fail;  
  194.     }  
  195.     memset(demo_devices, 0, sizeof(struct demo_dev));  
  196.     cdev_init(&demo_devices->cdev, &demo_fops);    
  197. demo_devices->cdev.owner = THIS_MODULE;  
  198.     demo_devices->cdev.ops = &demo_fops; //将创建的字符设备与file_operations中各函数操作连接起来  
  199.   
  200.     result = cdev_add(&demo_devices->cdev, dev, 1);  
  201.     if (result) {  
  202.         printk(KERN_NOTICE "error %d adding demo\n", result);  
  203.         goto fail;  
  204.     }  
  205.     return 0;  
  206. fail:  
  207.     demo_cleanup_module();  
  208.     return result;  
  209. }  
  210.   
  211. module_init(demo_init_module);  
  212. module_exit(demo_cleanup_module);  


 

2)加载驱动insmod demo.ko,再使用lsmodcat /proc/modules查看驱动是否安装;

3)创建设备节点:mknod  /dev/yangjin c 224 0;注意:此处的节点设备号要与驱动程序中的注册的设备号相同。

4)再编写应用程序测试代码:

用户测试代码:

[cpp] view plaincopy
  1. #include <sys/types.h>  
  2. #include <unistd.h>  
  3. #include <fcntl.h>  
  4. #include <linux/rtc.h>  
  5. #include <linux/ioctl.h>  
  6. #include <stdio.h>  
  7. #include <stdlib.h>  
  8.   
  9. #define COMMAND1 1  
  10. #define COMMAND2 2  
  11.   
  12. int main()  
  13. {  
  14.     int fd;  
  15.     int i;  
  16.     char data[256] = {0};  
  17.     int retval;  
  18.       
  19.     fd = open("/dev/yangjin", O_RDWR);  
  20.     if (fd == 1) {  
  21.         perror("open error\n");  
  22.         exit(-1);  
  23.     }  
  24.     printf("open /dev/yangjin successfully\n");  
  25.     retval = ioctl(fd, COMMAND1, 0);  
  26.     if (retval == -1) {  
  27.         perror("ioctl error\n");  
  28.         exit(-1);  
  29.     }  
  30.     printf("ioctl command 1 successfully\n");  
  31.     retval = write(fd, "yangjin", 7);  
  32.     if (retval == -1) {  
  33.         perror("write error\n");  
  34.         exit(-1);  
  35.     }  
  36.     retval = lseek(fd, 0, 0);  
  37.     if (retval == -1) {  
  38.         perror("lseek error\n");  
  39.         exit(-1);  
  40.     }  
  41.     retval = read(fd, data, 10);  
  42.     if (retval == -1) {  
  43.         perror("read error\n");  
  44.         exit(-1);  
  45.     }  
  46.     printf("read successfully: %s\n", data);  
  47.     close(fd);  
  48.     return 0;  
  49. }  


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/457901.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php学习笔记细节部分。

<?phpclass Car{public function Car()//构造函数 {//codeing 当实例化类的时候会调用这里面的方法}public function _destruct()//析构函数 {//codeing 对象的所有引用被删除&#xff0c;或者对象被显式的销毁时会执行的函数。 }} l转载于:https://www.cnblogs.com/OnlyL…

ctypes python_[python学习之路]ctypes,Python

ctypes 基本用法 ctypes 是一个方便 Python 调用本地已经编译好的外部库的模块。 from ctypes import util, CDLL 标准 C 库 使用 util 来找到标准 C 库&#xff1a; libc_name util.find_library(c) # on WINDOWS print libc_name msvcr90.dll 使用 CDLL 来加载 C 库&#xf…

oracle创建表空间和用户授权

确定数据文件的存储地址&#xff0c;有两种情况&#xff0c;一个是明确存储地址&#xff0c;一个是跟其他表空间存在一个地方&#xff0c;但是不知道地址&#xff0c;这时候可以根据如下SQL进行查找&#xff1a;select t.* from sys.dba_data_files t where t.tablespace_name…

linux驱动 cdev,inode结构体

前面我们学习了字符设备结构体cdev Linux 字符设备驱动开发 &#xff08;一&#xff09;—— 字符设备驱动结构&#xff08;上&#xff09; 下面继续学习字符设备另外几个重要的 数据结构。 先看下面这张图&#xff0c;这是Linux 中虚拟文件系统、一般的设备文件与设备驱动程…

如何在VS和CB中配置MySQL环境

这里&#xff0c;由于我的MySQL安装在D盘 MY SQL\MySQL Server 5.6该路径下&#xff0c;所以后面的路径均以D:\MY SQL\MySQL Server 5.6开头 在VS中配置MySQL环境 包含目录&#xff1a; D:\MY SQL\MySQL Server 5.6\include 库目录&#xff1a;D:\MY SQL\MySQL Server 5.…

点乘和叉乘的区别_关于延时和混响的区别与专用延时器与混响器的调控技巧

关于延时和混响的区别与专用延时器与混响器的调控技巧延时器与混响器是模拟室内声场声音信号特性的专用设备。在录音节目制作中&#xff0c;延时器和混响器可以在模拟的艺术声场中传递时间、空间、方位、距离等重要信息&#xff0c;并且可以制作某些特殊效果。延时器与混响器工…

zabbix监控工具

实验环境网关 classroom 172.25.8.254workstation 172.25.8.9server a-jeth0 172.25.8.10-外网eth1 192.168.0.x内网eth2 192.168.1.x备用servera:webservere:server--------------------------------------------需求&#xff1a;监控设计&#xff1a;原理&#xff1a;硬件&…

linux驱动 自旋锁

最近在内核频繁使用了自旋锁&#xff0c;自旋锁如果使用不当&#xff0c;极易引起死锁&#xff0c;在此总结一下。 自旋锁是一个互斥设备&#xff0c;它只有两个值&#xff1a;“锁定”和“解锁”。它通常实现为某个整数值中的某个位。希望获得某个特定锁得代码测试相关的位。…

百度输入法

[用户界面]&#xff1a;界面美观&#xff0c;有不同画风的ui界面&#xff0c;适合不同消费群体的需求。 [记住用户选择]&#xff1a;会默认记住用户以往的输入习惯&#xff0c;只需输入首拼音字母就会出现过去使用的高频词。 [短期刺激]&#xff1a;美化的用户界面让人眼前一新…

rs232读取智能电表_三相电表怎么看度数 怎么计算总电量

现在的三相电表一般都是在屏幕上面直接看&#xff0c;屏幕上面是有文字提示显示的&#xff0c;三相电表的总度数&#xff0c;上面的文字提醒一般是“正向有功总电量”&#xff0c;三相电表一般屏幕旁边都会上翻键和下翻键&#xff0c;可以上下翻开电表里面的数据。如下图所示&a…

android 学习随笔十六(广播 )

1、广播接收者 BroadcastReceiver接收系统发出的广播现实中的广播&#xff1a;电台为了传达一些消息&#xff0c;而发送的广播&#xff0c;通过广播携带要传达的消息&#xff0c;群众只要买一个收音机&#xff0c;就可以收到广播了 Android中的广播&#xff1a;系统在运行过程中…

驱动面试题总结

1、字符型驱动设备你是怎么创建设备文件的&#xff0c;就是/dev/下面的设备文件&#xff0c;供上层应用程序打开使用的文件&#xff1f; 答&#xff1a;mknod命令结合设备的主设备号和次设备号&#xff0c;可创建一个设备文件。 评&#xff1a;这只是其中一种方式&#xff0…

python程序写诗_将Python诗歌与D结合起来

在与docker一起使用poetry时&#xff0c;需要记住以下几点。 安装 安装poetry的正式方法是通过&#xff1a;curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python 这种方式允许poetry及其依赖项与依赖项分离。但是&#xff0c;在我看来…

Azure运维系列 4:安装和使用Azure PowerShell管理云

前面讲到了很多的管理方式&#xff0c;包括Azure中国最近更新的预览版管理门户和Azure云助理&#xff0c;都是非常不错的管理Azure的方式&#xff0c;今天我们再来介绍一种更加高效的管理方式Azure PowerShell。熟悉命令行的朋友都知道&#xff0c;Linux之所以那么好用是因为其…

[转]char * 和字符数组

[转]char * 和字符数组 原文地址&#xff1a;http://www.cnblogs.com/jeakon/archive/2012/05/27/2816809.html 代码中的int * i就是我们关注的焦点。它是一个指向int指针。也就是说&#xff1a;i指向一个内存地址&#xff0c;从这个地址开始存储了一个数据。int * i中的int标明…

设备模型1

作为开头篇&#xff0c;我不想写HELLLOWORLD驱动&#xff0c;甚至字符设备驱动的开发&#xff0c;这样文章充斥在各大网站上的博客上&#xff0c;随便搜搜&#xff0c;就可以找到几百篇。这是最基本的东西&#xff0c;通过这些内容的学习&#xff0c;我们要掌握LINUX驱动的基本…

如何使用Android Studio把自己的Android library分享到jCenter和Maven Central

第一部分&#xff1a;在bintray上创建package首先&#xff0c;你需要在bintray上创建一个package。为此&#xff0c;你需要一个bintray账号&#xff0c;并在网站上创建一个package。第一步&#xff1a;在bintray.com上注册一个账号。&#xff08;注册过程很简单&#xff0c;自己…

python2编码_Python2字符编码

我们通常见到的字符串编码主要是三种GB2312/GBK、Unicode、UTF-8。GB2312/GBK是多字节(multibytes)编码的一种&#xff0c;属于“ASCII的加强版”&#xff0c;与之平行的由Big5、ShiftJIS之类的编码各自为政&#xff0c;所有这些用两个字节表示汉字的多字节编码标准统称为ANSI编…

angularJs关于指令的一些冷门属性

我们使用ng的时候&#xff0c;经常会使用到指令&#xff0c;大家所熟知的属性我在这里就不介绍了&#xff0c;讲讲大家没怎么留意的属性 1.multiElement 这是指定指令作用区间的功能&#xff0c;最常用的就是ng-repeat-start和ng-repeat-end了。 2.priority 指令优先级&#xf…

设备模型2

前言 在上一篇中&#xff0c;我们大致描述了LINUX设备模型&#xff0c;我们先来总结一下三要素的关系。 从图中可以看出,Linux设备模型就是"总线、设备、驱动、类"这四个概念之前的相互关系;这也是Linux2.6内核抽象出来的用于管理系统中所有设备的模型图; 简单地描述…