写点什么

Linux 驱动框架与杂项字符设备框架介绍

作者:DS小龙哥
  • 2022 年 4 月 20 日
  • 本文字数:2979 字

    阅读完需:约 10 分钟

1. Linux 下驱动框架介绍

1.1 驱动框架分类

Linux 下驱动框架分为 3 大类型:


  1. 字符设备 ---------

  2. 块设备 存储设备 SD 硬盘

  3. 网络设备 网卡 无线 有线


字符设备和块设备都会生成设备节点在/dev 目录下。


网络设备不会生成设备节点. 可以使用 ifconfig 查看


字符设备标准框架详细区分:


  1. RTC 设备驱动

  2. LCD 屏设备驱动---帧缓冲设备框架

  3. 声卡设备驱动---音频设备

  4. 标准输入设备驱动—输入子系统框架

  5. ......................等等


内核提供的字符设备注册的方式: 原生的—最底层注册方式


  1. 早期设备注册方式—linux 2.6

  2. 标准设备注册方式

  3. 杂项设备注册方式


比如: 温度传感器、湿度传感器、光照度、门锁、LED 灯、蜂鸣器 驱动都是使用字符设备框架编写


1.2 驱动框架代码模板


示例代码:


#include <linux/kernel.h>#include <linux/module.h>
static int __init tiny4412_hello_drv_init(void){ printk("Hello 驱动注册-安装成功.\n"); return 0;}
static void __exit tiny4412_hello_drv_exit(void){ printk("Hello 驱动注销成功.\n");}
/*驱动入口*/module_init(tiny4412_hello_drv_init);/*驱动出口*/module_exit(tiny4412_hello_drv_exit);/*许可证*/MODULE_LICENSE("GPL");
复制代码

1.3 Makefile 示例代码

KER_DRI=/home/wbyq/work/linux-3.5/linux-3.5all:    make -C $(KER_DRI) M=`pwd` modulesclean:    make -C $(KER_DRI) M=`pwd` modules cleanobj-m += drv_hello.o
复制代码


编译完成之后,生成的驱动文件名称还是 xxxx.ko 文件。以 ko 为后缀。

1.4 安装驱动过程

[root@wbyq ]#insmod drv_hello.ko [  435.765000] Hello 驱动注册-安装成功.[root@wbyq ]#rmmod drv_hello.ko rmmod: can't change directory to '/lib/modules': No such file or directory[root@wbyq ]#mkdir /lib/modules[root@wbyq ]#rmmod drv_hello.ko rmmod: can't change directory to '3.5.0-FriendlyARM': No such file or directory[root@wbyq ]#[root@wbyq ]#[root@wbyq ]#mkdir /lib/modules/3.5.0-FriendlyARM[root@wbyq ]#rmmod drv_hello.ko [ 1024.225000] Hello 驱动注销成功.[root@wbyq ]#insmod drv_hello.ko [ 1080.500000] Hello 驱动注册-安装成功.[root@wbyq ]#lsmoddrv_hello 614 0 - Live 0xbf004000 (O)[root@wbyq ]#modinfo drv_hello.ko modinfo: can't open '/lib/modules/3.5.0-FriendlyARM/modules.dep': No such file or directory[root@wbyq ]#touch /lib/modules/3.5.0-FriendlyARM/modules.dep[root@wbyq ]#modinfo drv_hello.ko filename:       drv_hello.kolicense:        GPLdepends:        vermagic:       3.5.0-FriendlyARM SMP preempt mod_unload ARMv7 p2v8 [root@wbyq ]#
复制代码


驱动的安装方式:


  1. 动态安装. lsmod 查看动态方式安装的驱动.

  2. 静态安装. 静态是固化到内核里的。

2. 杂项设备框架

2.1 框架结构介绍

杂项字符设备的主设备号固定: 10 主设备号: 0 ~ 255


次设备号范围: 0 ~ 255


Linux 内核寻找驱动节点是依靠设备号寻找的。


设备号: 主设备号(区分类型)、次设备号(区分同类型的具体设备)


主设备号: 10 ,240


下面是查看串口设备节点、MMC 设备节点的详细信息:



下面是杂项设备的模型图:



Linux 下把无法分类的一些设备都归类为杂项设备,杂项设备本身就是字符设备,只是简单封装了一层,注册调用更加简单。杂项设备(misc device)是在嵌入式系统中用得比较多的一种设备驱动。


在 Linux 内核的 include\linux 目录下有 Miscdevice.h 文件,misc 设备定义及其内核提供的相关函数在这里。


内核用 struct miscdevice 的结构体来描述杂项设备:


struct miscdevice  {            int minor;                       //次设备号,杂项设备的主设备?10        const char *name;                //设备的名称            const struct file_operations *fops;   //文件操作         /* 下面的成员是供内核使用 ,驱动编写不需要理会 */        struct list_head list;      //misc_list的链表头        struct device *parent;      //父设备            struct device *this_device; //当前设备,是device_create的返回值  }; 
复制代码


杂项设备结构里有一个文件集合指针,当字符设备驱动安装成功之后,在应用层是 open 函数打开这个设备文件,会访问到驱动层里文件集合对应的函数。


文件操作集合的模型图:


2.2 蜂鸣器驱动示例代码

这是蜂鸣器的驱动层示例代码,使用杂项设备框架编写:


#include <linux/init.h>#include <linux/module.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/uaccess.h>#include <asm/io.h>static volatile unsigned int *GPD0CON=NULL;static volatile unsigned int *GPD0DAT=NULL;
static int tiny4412_open(struct inode *my_indoe, struct file *my_file){ printk("open ok\n");
/*设置蜂鸣器为输出模式*/ *GPD0CON &= ~(0xf << 0 * 4); *GPD0CON |= (1 << 0 * 4); return 0;}
static int tiny4412_release(struct inode *my_indoe, struct file *my_file){ printk("open release\n"); *GPD0DAT &=~(1 << 0); //关蜂鸣器 return 0;}
static ssize_t tiny4412_read(struct file *my_file, char __user *buff, size_t cnt, loff_t *loff){ *GPD0DAT |= (1 << 0); //开蜂鸣器 return 0;}
static ssize_t tiny4412_write(struct file *my_file, const char __user *buff, size_t cnt, loff_t *loff){ *GPD0DAT &=~(1 << 0); //关蜂鸣器 return 0;}
static struct file_operations tiny4412_fops={ .open=tiny4412_open, .release=tiny4412_release, .read=tiny4412_read, .write=tiny4412_write,};

static struct miscdevice misc={ .minor=255, .name="tiny4412_hello", // /dev/下的名称 .fops=&tiny4412_fops,};
//__init标号: 对应一段代码(汇编)--一般设置属性(指定文本段存放的位置)。 执行hello_init函数之前先执行__initstatic int __init hello_init(void){ /*1. 注册杂项字符设备*/ misc_register(&misc);
/*映射地址*/ GPD0CON=ioremap(0x114000A0,4); GPD0DAT=ioremap(0x114000A4,4);
printk("hello_init 驱动安装成功!\n"); return 0;}
static void __exit hello_exit(void){ /*2. 注销*/ misc_deregister(&misc); iounmap(GPD0CON); //将映射的地址释放掉 iounmap(GPD0DAT); printk("hello_exit驱动卸载成功!\n");}
module_init(hello_init); //驱动入口。安装驱动的时候调用module_exit(hello_exit); //驱动出口。卸载驱动的时候调用
MODULE_AUTHOR("www.edu118.com"); //声明驱动的作者MODULE_DESCRIPTION("hello 模块测试"); //描述当前驱动功能MODULE_LICENSE("GPL"); //驱动许可证。支持的协议GPL。
复制代码


应用层的代码:


#include <stdio.h>int main(int argc,char**argv){   int fd;   fd=open("/dev/tiny4412_hello",2); //3  0 - 1 - 2   if(fd<0)     {       printf("驱动打开失败!\n");       return -1;       }   int data1;   int data2;   while(1)   {      read(fd,&data1,4);      sleep(1);     write(fd,&data2,4);     sleep(1);   }   close(fd);   return 0;}
复制代码

2.3 运行效果



发布于: 刚刚阅读数: 3
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
Linux驱动框架与杂项字符设备框架介绍_4月月更_DS小龙哥_InfoQ写作社区