资讯详情

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

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灯、蜂鸣器 驱动是用字符设备框架编写的

image-20211225194706596

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.5 all:     make -C $(KER_DRI) M=`pwd` modules clean:     make -C $(KER_DRI) M=`pwd` modules clean obj-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 ]#lsmod
drv_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.ko
license:        GPL
depends:        
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  { 
              
	    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函数之前先执行__init
static 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 运行效果

标签: con021传感器传感器pwd12

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台