• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Linux字符设备驱动

武飞扬头像
Linux内核站
帮助1

globalmem

看 linux 设备驱动开发详解时 ,字符设备驱动一章,写的测试代码和应用程序,加上自己的操作,对初学者我觉得非常有帮助。

写这篇文章的原因是因为我看了我之前发表的文章,还没有写过字符设备相关的,至于里面提到的结构体的作用,有很多详细的文章说明,我就不做更深的叙述。

代码在github上,点击下面阅读原文可以直达

https://github.com/weiqifa0/globalmem/blob/main/README.md

把这部分放在github上也有好处,后续可以增加删除一些东西,以后自己需要使用的时候也方便许多。

我们讨论字符设备驱动,就有必要知道他的结构体和头文件,像一些后来的封装什么的,大部分还是脱离不了操作这个结构体里面的东西。

 资料直通车:Linux内核源码技术学习路线 视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

  1.  
    /* SPDX-License-Identifier: GPL-2.0 */
  2.  
    #ifndef _LINUX_CDEV_H
  3.  
    #define _LINUX_CDEV_H
  4.  
     
  5.  
    #include <linux/kobject.h>
  6.  
    #include <linux/kdev_t.h>
  7.  
    #include <linux/list.h>
  8.  
    #include <linux/device.h>
  9.  
     
  10.  
    struct file_operations;
  11.  
    struct inode;
  12.  
    struct module;
  13.  
     
  14.  
    struct cdev {
  15.  
    struct kobject kobj; /*内嵌kobject结构体,方便以后应用,也会在sys下生成相关设备文件*/
  16.  
    struct module *owner;/*所属于的模块,正常就是本模块THIS_MODULE*/
  17.  
    const struct file_operations *ops;/*文件的操作结构体,设备也是一个文件*/
  18.  
    struct list_head list;/*字符设备的链表头*/
  19.  
    dev_t dev;/*设备号*/
  20.  
    unsigned int count;
  21.  
    } __randomize_layout;
  22.  
    /*初始化cdev,并建立和file_operation的联系*/
  23.  
    void cdev_init(struct cdev *, const struct file_operations *);
  24.  
    /*申请cdev内存*/
  25.  
    struct cdev *cdev_alloc(void);
  26.  
     
  27.  
    void cdev_put(struct cdev *p);
  28.  
     
  29.  
    int cdev_add(struct cdev *, dev_t, unsigned);
  30.  
     
  31.  
    void cdev_set_parent(struct cdev *p, struct kobject *kobj);
  32.  
    int cdev_device_add(struct cdev *cdev, struct device *dev);
  33.  
    void cdev_device_del(struct cdev *cdev, struct device *dev);
  34.  
     
  35.  
    void cdev_del(struct cdev *);
  36.  
     
  37.  
    void cd_forget(struct inode *);
  38.  
     
  39.  
    #endif
学新通

学新通

加载内核模块insmod globalmem.ko 错误需要的修改。

insmod: can't insert 'globalmem.ko': Device or resource busy

出错的原因:

模块使用的是静态分配设备号的方式,而这个设备号已经被系统中的其他设备所占用。查看未被占用的设备号,需要到pro/devices下面去查看。

查看设备号的方法:

cat /proc/devices

编译内核版本

  1.  
    #uname -a
  2.  
    Linux bsp-ubuntu1804 4.15.0-117-generic #118-Ubuntu SMP Fri Sep 4 20:02:41 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

加载模块之后使用lsmod查看模块

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo insmod globalmem.ko
  2.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ lsmod |grep global
  3.  
    globalmem 16384 0
  4.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$
  5.  
     
  6.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /proc/devices |grep global
  7.  
    230 globalmem
  8.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$

创建设备文件节点

使用mknod创建设备节点的时候,后面跟上的参数需要跟我们在/proc/devices下面看到的对应,也就是我们在驱动里面申请的主设备号。

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo mknod /dev/globalmem c 230 0
  2.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ ls /dev/globalmem -al
  3.  
    crw-r--r-- 1 root root 230, 0 Dec 22 16:19 /dev/globalmem
  4.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$

使用命令读写设备文件

Linux 下的 echo 和cat 命令是十分有用,这两个命令可以让在不写代码的情况下就可以完成调试读写设备。

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo chmod 777 /dev/globalmem
  2.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo echo "linux" > /dev/globalmem
  3.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /dev/globalmem
  4.  
    linux
  5.  
    cat: /dev/globalmem: No such device or address
  6.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /dev/globalmem
  7.  
    linux
  8.  
    cat: /dev/globalmem: No such device or address
  9.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo echo "linuxgdb" > /dev/globalmem
  10.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /dev/globalmem
  11.  
    linuxgdb
  12.  
    cat: /dev/globalmem: No such device or address
  13.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$

通过代码来读写设备文件

代码在下面阅读原文的链接里面。

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ gcc app-main.c && ./a.out
  2.  
    str:LINUX,GDB
  3.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$

使用传入参数设置主设备号

内核模块参数 我觉得是一个比较冷门的知识点,冷门的原因是因为我们在做项目的时候很少使用这个参数,但是实际上这个参数非常有用。

我们可以把内核模块当做main函数 ,main函数是可以接收传参的,内核模块也可以在加载的时候接收传入的参数。

如下是把主设备号传给内核模块,但是需要注意,这个主设备号不能被占用了。

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo insmod globalmem.ko globalmem_major=231
  2.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /proc/devices |grep globalmem
  3.  
    231 globalmem
  4.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$

增加自动创建设备节点的驱动文件

每次手动创建设备文件节点总是很麻烦,而且在实际编写设备驱动的时候,不会出现自己手动创建设备节点这种低端的操作。

当然了,聪明的内核提供了接口让我们在注册驱动的时候也把设备文件节点注册上去。

具体代码可以查看globalmem2.c里面的代码。

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ chmod 777 globalmem.ko
  2.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo insmod globalmem.ko
  3.  
    [sudo] password for weiqifa:
  4.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ ls /dev/globalmem
  5.  
    /dev/globalmem
  6.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ ls /dev/globalmem -al
  7.  
    crw------- 1 root root 238, 0 Dec 22 17:18 /dev/globalmem
  8.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$
  9.  
     
  10.  
    /*修改权限后才可以正常进行独写操作*/
  11.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo chmod 777 /dev/globalmem
  12.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ gcc app-main.c && ./a.out
  13.  
    write data ok!
  14.  
    str:LINUX,GDB
  15.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$
学新通

使用lseek操作文件位置

具体对应的文件是app-main2.c

  1.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$ gcc app-main2.c && ./a.out
  2.  
    file ret:0
  3.  
    write data ok! fd:3
  4.  
    str:123456789ABCDEF10111213141516171819201617181920
  5.  
    lseek:1
  6.  
    str:23456789ABCDEF10111213141516171819201617181920
  7.  
    weiqifa@bsp-ubuntu1804:~/c/globalmem$

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhcakf
系列文章
更多 icon
同类精品
更多 icon
继续加载