Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo

这篇具有很好参考价值的文章主要介绍了Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533文章来源地址https://www.toymoban.com/news/detail-751810.html

红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

Linux系统移植和驱动开发专栏

上一篇:《Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试》
下一篇:《Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo》


前言

  驱动的开发需要先熟悉基本概念类型,本篇讲解linux杂项设备基础,还是基于虚拟机ubuntu去制作驱动,只需要虚拟机就可以尝试编写注册杂项设备的基本流程。


linux三大设备驱动

  • 字符设备:IO的传输过程是以字符为单位的,没有缓冲,比如I2C(SDA、SCL),SPI(MISO、MOSI、SCLK、CS)。
  • 块设备:IO的传输过程是以块为单位的,跟存储相关的都属于块设备,比如tf卡,sd卡。
  • 网络设备:IO的传输以socket套接字来访问的。

杂项设备

  • 杂项设备是属于字符设备,可以自动生成设备节点,设备节点位于/dev/目录下,是设备名称,如/dev/ttyS9等。
  • 主设备号相同,统一为10,次设备号不同,主设备相同可以节省内核资源。
    通过下列指令,可以查看系统杂项设备
cat /proc/misc

  在虚拟机上测试,查看杂项:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  • 设备号分为主设备号和次设备号,主设备号是唯一的,次设备号不一定唯一。
    通过下列指令,可以查看系统主设备号:
cat /proc/devices

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

杂项设备描述结构体

  ubuntu来说,自带的/usr/src下的就是内核的头文件。

cd /usr/src/linux-headers-4.18.0-15
vi include/linux/miscdevice.h

  定位到之前ubuntu自带的内核头文件下:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  查看到杂项设备的结构体:

struct miscdevice  {
        int minor;  // 次设备号
        const char *name;  // 设备节点名称(如/dev/ttyS8,则ttyS是名称)
        const struct file_operations *fops; // 文件操作集(非常重要)
        struct list_head list; 
        struct device *parent;
        struct device *this_device;
        const struct attribute_group **groups; 
        const char *nodename; 
        umode_t mode;
};

  (注意:没打注释的,一般不管)

杂项设备文件操作集

cd /usr/src/linux-headers-4.18.0-15
vi include/linux/fs.h

  搜索到(vi则直接使用“/”):
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
        ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
        int (*iterate) (struct file *, struct dir_context *);
        int (*iterate_shared) (struct file *, struct dir_context *);
        __poll_t (*poll) (struct file *, struct poll_table_struct *);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        unsigned long mmap_supported_flags;
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, loff_t, loff_t, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
        int (*setfl)(struct file *, unsigned long);
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
        int (*setlease)(struct file *, long, struct file_lock **, void **);
        long (*fallocate)(struct file *file, int mode, loff_t offset,
                          loff_t len);
        void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
        unsigned (*mmap_capabilities)(struct file *);
#endif
        ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
                        loff_t, size_t, unsigned int);
        int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
                        u64);
        ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
                        u64);
} __randomize_layout;

  例如read函数,那么就是打开驱动使用系统read,打开这个设备驱动的句柄,那么久会调用read函数,其他的以此类推,还比较好理解。
  以我们一个registerHelloWorld为例子,来简单说明。


驱动编写空模板准备

  首先复制之前的hello world的驱动,改个名字为:registerMiscDev:

cd ~/work/drive
cp -arf hellowolrd registerMiscDev

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

cd registerMiscDev/
rm *.ko *.o *.order *.symvers

  这里删除起来麻烦,修改makefile,添加clean:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  然后测试一下:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  继续修改源码文件名称:

mv helloworld.c registerMiscDev.c

  修改完如下:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  然后修改makefile里面的(obj-m模块名称改下),模板准备好了
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  下面基于registerMiscDev.c文件进行注册杂项设备,在修改.c文件:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

#include <linux/init.h>
#include <linux/module.h>

static int registerMiscDev_init(void)
{ 
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registerMiscDev_init\n");	
    return 0;
}
static void registerMiscDev_exit(void)
{
    printk("bye-bye!!!\n");
}
MODULE_LICENSE("GPL");
module_init(registerMiscDev_init);

module_exit(registerMiscDev_exit); 

杂项设备注册流程Demo

步骤一:填充miscdevice结构体

  在编写驱动的时候,代码中填充信息结构体。
  添加头文件miscdevice.h

#include <linux/miscdevice.h>
#include <linux/fs.h>

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  然后填充杂项设备结构体:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  (注意:开始为“.”,结束为“,”,最后一行习惯加“,”了,这样可以全部统一复制啥的,省的加没加的)

struct miscdevice misc_dev {
    .minor = MISC_DYNAMIC_MINRO, // 这个宏是动态分配次设备号,避免冲突
    .name = "register_hongPangZi_misc,  // 设备节点名称
    .fops = misc_fops, // 这个变量记住,自己起的,步骤二使用
}

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

步骤二:填充file_operations结构体

  在编写驱动的时候,代码中填充文件操作结构体。
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

struct file_operations misc_fops {
  .owner = THIS_MODULE
}

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

步骤三:注册杂项设备并生成设备节点

  注册到内核:

static int registerMiscDev_init(void)
{ 
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registerMiscDev_init\n");	

    int ret = 0;
    ret = misc_register(misc_dev);
    if(ret < 0)
    {
        printk("Failed to misc_register(misc_dev)\n");	
        return -1;
    } 
    return 0;
}

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  有注册就有注销:

static int registerMiscDev_init(void)
{ 
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registerMiscDev_init\n");	

    int ret = 0;
    ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("Failed to misc_register(misc_dev)\n");	
        return -1;
    } 
    return 0;
}

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  完整的文件源码:

#include <linux/init.h>
#include <linux/module.h>

#include <linux/miscdevice.h>
#include <linux/fs.h>

struct file_operations misc_fops = {
  .owner = THIS_MODULE,
};

struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR, // 这个宏是动态分配次设备号,避免冲突
    .name = "register_hongPangZi_misc", // 设备节点名称
    .fops = &misc_fops,  // 这个变量记住,自己起的,步骤二使用
};

static int registerMiscDev_init(void)
{ 
    // 在内核里面无法使用基础c库printf,需要使用内核库printk
    printk("Hello, I’m hongPangZi, registerMiscDev_init\n");	

    int ret = 0;
    ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("Failed to misc_register(&misc_dev)\n");	
        return -1;
    } 
    return 0;
}

static void registerMiscDev_exit(void)
{
    misc_deregister(&misc_dev);
    printk("bye-bye!!!\n");
}

MODULE_LICENSE("GPL");
module_init(registerMiscDev_init);
module_exit(registerMiscDev_exit);

步骤四:编译make

make

  直接在驱动工程目录编译:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  下面这个警告,实际上定义要在任何使用函数之前:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  修改下:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  编译成功
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

步骤五:加载卸载驱动测试

  将驱动拷贝到开发板或者目标系统,然后使用加载指令:

sudo insmod registerMiscDev.ko

  会打印入口加载的printk输出。
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  出现问题可能原因一是内核编译使用的编译器和模块使用的编译器版本不一致。ubuntu中printk终端打入内核日志消息了,可以使用dmesg进行查看:

dmesg

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  然后查看是否加入了杂项设备节点:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  然后注销:

sudo rmmod registerMiscDev.ko

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

  跟随着,结点消失了:
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发


入坑

入坑一:编译报错,结构体之后未加分号

问题

  编译错误,结构体后面加分号

解决

  加分号,脑袋有点蒙
  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

入坑二:编译错误,文件操作指针问题

问题

  Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo,linux驱动开发,linux,驱动开发

解决

  这是写错了,是指针,需要加取地址&。


上一篇:《Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试》
下一篇:《Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo》


若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533

到了这里,关于Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 4、Linux驱动开发:设备-设备号&设备号注册

    🍅点击这里查看所有博文   随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有

    2024年02月15日
    浏览(47)
  • Linux驱动开发实战(一)——设备驱动模型

    在早期的Linux内核中并没有为设备驱动提供统一的设备模型。随着内核的不断扩大及系统更加复杂,编写一个驱动程序越来越困难,所以在Linux2.6内核中添加了一个统一的设备模型。这样,写设备驱动程序就稍微容易一些了。本章将对设备模型进行详细的介绍。 设备驱动模型

    2024年02月16日
    浏览(39)
  • Linux设备驱动开发 - 虚拟时钟Clock驱动示例

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 很多设备里面系统时钟架构极其复杂,让学习Clock驱动的盆友头大。这里我参考S3C2440的clock驱动写了一个virtual clock,即虚拟时钟驱动,分别包含clock的provider和

    2023年04月21日
    浏览(31)
  • LDD学习笔记 -- Linux字符设备驱动

    字符驱动程序用于与Linux内核中的设备进行交互; 字符设备指的是像内存区域这样的硬件组件,通常称为伪设备; 用户空间应用程序通常使用 open read write 等系统调用与这些设备通信; 把用户空间的系统调用连接到设备驱动的系统调用实现方法上。 内核的虚拟文件系统 vir

    2024年02月02日
    浏览(37)
  • Linux -- 字符设备驱动--LED的驱动开发(初级框架)

    看原理图确定引脚,确定引脚输出什么电平才能点亮 / 熄灭 LED 看主芯片手册,确定寄存器操作方法:哪些寄存器?哪些位?地址是? 编写驱动:先写框架,再写硬件操作的代码 注意 :在芯片手册中确定的寄存器地址被称为 物理地址 ,在 Linux 内核中无法直接使用。 需要使

    2024年04月28日
    浏览(24)
  • itop-3568开发板驱动学习笔记(22)设备树(一)设备树基础

    《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 什么是设备树 设备树是保留着存在于系统中的设备信息,当机器引导时,OS通过使用驱动程序和其他组件获得的信息建立此树,并且当添加或删除设备时更新此树。 上一篇笔记提到了平台设备模型,它将设备和驱动区

    2024年02月13日
    浏览(36)
  • 嵌入式Linux驱动开发 04:基于设备树的驱动开发

    前面文章 《嵌入式Linux驱动开发 03:平台(platform)总线驱动模型》 引入了资源和驱动分离的概念,这篇文章将在前面基础上更进一步,引入设备树的概念。 在平台总线驱动模型中资源和驱动已经从逻辑上和代码组织上进行了分离,但每次调整资源还是会涉及到内核,所以现

    2024年02月16日
    浏览(58)
  • 正点原子嵌入式linux驱动开发——Linux 网络设备驱动

    网络驱动是linux里面驱动三巨头之一 ,linux下的网络功能非常强大,嵌入式linux中也常常用到网络功能。前面已经讲过了字符设备驱动和块设备驱动,本章就来学习一下linux里面的 网络设备驱动 。 本次笔记中讨论的都是有线网络! 提起网络,一般想到的硬件就是“网卡”。在

    2024年01月17日
    浏览(61)
  • 嵌入式Linux系统中的设备驱动开发:从设备树到驱动实现

    大家好,今天给大家介绍 嵌入式Linux系统中的设备驱动开发:从设备树到驱动实现 ,文章末尾附有分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全! 可进群免费领取。 在嵌入式Linux系统中,设备驱动是连接硬件设备和操作系统之间的桥梁。

    2024年02月19日
    浏览(54)
  • 【Linux驱动开发】设备树详解(三)设备树Kernel解析

    ​ ​ 活动地址:CSDN21天学习挑战赛 【Linux驱动开发】设备树详解(一)设备树基础介绍 【Linux驱动开发】设备树详解(二)设备树语法详解 【Linux驱动开发】设备树详解(三)设备树Kernel解析   个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享

    2023年04月24日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包