基于框架编写驱动代码

操作驱动的上层代码(pin4test)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>void main()
{int fd,data;fd = open("/dev/pin4",O_RDWR);if(fd<0){printf("open fail\n");perror("reson:");}else{printf("open successful\n");}fd=write(fd,'1',1);
}

字符设备驱动框架

#include <linux/fs.h>		 //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>	 //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件static struct class *pin4_class;  
static struct device *pin4_class_dev;static dev_t devno;                //设备号
static int major =231;  		   //主设备号
static int minor =0;			   //次设备号
static char *module_name="pin4";   //模块名//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{printk("pin4_open\n");  //内核的打印函数和printf类似return 0;
}//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk("pin4_write\n");  //内核的打印函数和printf类似return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open  = pin4_open,.write = pin4_write,
};
//static限定这个结构体的作用,仅仅只在这个文件。
int __init pin4_drv_init(void)   //真实的驱动入口
{int ret;devno = MKDEV(major,minor);  //创建设备号ret   = register_chrdev(major, module_name,&pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中pin4_class=class_create(THIS_MODULE,"myfirstdemo");//让代码在dev下自动生成设备pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);  //创建设备文件return 0;
}void __exit pin4_drv_exit(void)
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name);  //卸载驱动}module_init(pin4_drv_init);  //入口,内核加载驱动的时候,这个宏会被调用,去调用pin4_drv_init这个函数
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

自动生成设备(以下代码在框架中):

pin4_class=class_create(THIS_MODULE,"myfirstdemo");//让代码在dev下自动生成设备

手动生成设备:

sudo mknod 设备名 设备类型 主设备号 次设备号 
sudo mknod feng c 8 1
//c是字符型设备类型
//生成成功如下图

在这里插入图片描述

驱动代码(pin4driver)

#include <linux/fs.h>            //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>        //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno;                //设备号
static int major =231;                     //主设备号
static int minor =0;                       //次设备号
static char *module_name="pin4";   //模块名//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{printk("pin4_open\n");  //内核的打印函数和printf类似return 0;
}
//read函数
static int pin4_read(struct file *file,char __user *buf,size_t count,loff_t *ppos)
{printk("pin4_read\n");  //内核的打印函数和printf类似return 0;
}//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk("pin4_write\n");  //内核的打印函数和printf类似return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open  = pin4_open,.write = pin4_write,.read  = pin4_read,
};
//static限定这个结构体的作用,仅仅只在这个文件。
int __init pin4_drv_init(void)   //真实的驱动入口
{int ret;devno = MKDEV(major,minor);  //创建设备号ret   = register_chrdev(major, module_name,&pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中pin4_class=class_create(THIS_MODULE,"myfirstdemo");//让代码在dev下自动>生成设备pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);  //创建设备文件return 0;
}void __exit pin4_drv_exit(void)
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name);  //卸载驱动
}
module_init(pin4_drv_init);  //入口,内核加载驱动的时候,这个宏会被调用,去调用pin4_drv_init这个函数
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

进入linux源码树目录下的字符设备下(drivers/char/)这个文件夹,创建一个.c文件名为pin4driver2.c(名字自己定义),将驱动代码写入也可以将写好的.c文件拷贝进来

配置Makefile(模块的形式)

加入下面这句代码
obj-m                           += pindriver.o

在源码树目录下进行编译

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules
//指定架构是arm架构
//交叉编译工具是arm-linux-gnueabihf-
//KERNEL=kernel7 内核的版本
//生成modules

将生成的 pin4driver.ko和交叉编译好的上层代码pin4test(自己定义) 发送到开发板(我这里使用的是树莓派3b)

交叉编译指令:

arm-linux-gnueabihf-gcc pintest.c -o pin4test

开发板端

sudo insmod pin4driver2.ko 
//加载内核模块,就会自动的在dev下生成pin4文件若直接运行pin4test会出现以下报错:
open fail
reson:: Permission denied
//报错——没有权限打开这个文件pi@raspberrypi:~ $ lsmod(可以查看驱动是否装进去,列出内核的驱动模块)
Module                  Size  Used by
pin4driver2            16384  0//由此可见驱动已经装好
fuse                  106496  3
rfcomm                 49152  4
bnep                   20480  2
hci_uart               36864  1
btbcm                  16384  1 hci_uart
serdev                 20480  1 hci_uart
bluetooth             372736  29 hci_uart,bnep,btbcm,rfcomm
ecdh_generic           28672  1 bluetooth
8021q                  32768  0
garp                   16384  1 8021q
stp                    16384  1 garp
llc                    16384  2 garp,stp
brcmfmac              278528  0
brcmutil               16384  1 brcmfmac
cfg80211              569344  1 brcmfmac
rfkill                 24576  6 bluetooth,cfg80211
snd_bcm2835            32768  2
snd_pcm                98304  1 snd_bcm2835
snd_timer              32768  1 snd_pcm
snd                    69632  7 snd_timer,snd_bcm2835,snd_pcm
uio_pdrv_genirq        16384  0
uio                    20480  1 uio_pdrv_genirq
fixed                  16384  0
i2c_dev                16384  0
ip_tables              24576  0
x_tables               32768  1 ip_tables
ipv6                  425984  24sudo chmod 666 /dev/pin4
//这句指令的意思是修改权限,666是所有人都可以打开

删除驱动模块

sudo rmmod 驱动模块名(不用写后缀ko)
//删除驱动模块,dev下的设备文件也会被删除

查看内核态打印的内容

dmesg
//查看内核态打印的printk
通过下图可以看到通过上层的open和write触发底层
驱动调用open和write,打印pin4_open和pin4_write

在这里插入图片描述

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

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

相关文章

nacos在windows下安装

1:访问https://github.com/alibaba/nacos/releases下载nacos 2:下载到本地解压 3:点击startup.cmd 启动nacos 4:访问 http://127.0.0.1:8848/nacos 输入账号和密码&#xff0c;nacos/nacos

微机总线地址,物理地址 ,虚拟地址

总线地址 地址总线 (Address Bus&#xff1b;又称&#xff1a;位址总线) 属于一种电脑总线 &#xff08;一部份&#xff09;&#xff0c;是由CPU 或有DMA 能力的单元&#xff0c;用来沟通这些单元想要存取&#xff08;读取/写入&#xff09;电脑内存元件/地方的实体位址。 自己…

Navicat远程连接linux下mysql服务器1045错误解决办法在这儿

1&#xff1a;首先通过xshell工具或者你熟悉的工具连接远程linux下的服务器 mysql -uroot -p 然后输入密码 2.进行授权 如果想root用户使用password从任何主机连接到mysql服务器的话。 GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY 你的mysql密码 WITH GRANT O…

树莓派 博通BCM2835芯片手册

手册提取链接 链接&#xff1a;https://pan.baidu.com/s/1fdmIBNn1Pr1j3-ercNhKJg 提取码&#xff1a;8y1b 驱动的两大利器&#xff1a; 1、电路图:通过电路图找到寄存器 2、芯片手册 树莓派有54个通用IO口(0到53)&#xff0c;所有GPIO口至少有两个可选功能&#xff08;输入输…

Intellij idea 报错:Error : java 不支持发行版本5

idea运行出现了这个错误 解决办法按下图所示&#xff1a;

Vscode如何新建html文件

1、点击Open Folder&#xff1a; 2、选择目标文件夹&#xff0c;在本地新建一个拓展名为html的文件&#xff1a; 3、在第1行输入!&#xff08;英文状态下&#xff09;&#xff0c;按tab键&#xff0c;新建成功。界面如下图所示&#xff1a;

混合app

cordova run android 把应用发送到手机ionic serve 电脑浏览器调试命令创建&#xff1a;cordova create hello com.example.hello HelloWorldcd hellocordova platform add androidcordova build androidcordova emulate android查询cordova platform lscord…

vscode浏览器打开html

1.点击拓展 2.输入open in browser&#xff0c;选择第一个 3.点击安装

VMware虚拟机克隆CentOS后网卡修改方法

转自:http://www.linuxidc.com/Linux/2015-03/114975.htm 转载于:https://www.cnblogs.com/water-sky/p/5169107.html

解决redis-cli连接时出现Could not connect to Redis at 127.0.0.1:6379: Connection refused

解决redis-cli连接时Could not connect to Redis at 127.0.0.1:6379: Connection refused 原因&#xff1a;服务端未启动 [rootlocalhost bin]# ./redis-server redis.conf [rootlocalhost bin]# redis-cli -bash: redis-cli: 未找到命令 [rootlocalhost bin]# ./redis-cli 1…

51单片机点亮第一个LED教程

单片机芯片型号&#xff1a; STC89C52 建立工程文件 打开keil4软件界面如下&#xff1a; 新建工程文件&#xff08;自己选择文件路径&#xff0c;并给工程命名&#xff09;&#xff1a; 若出现下图点击OK&#xff1a; 然后选择Atmel点击OK&#xff08;根据自己的芯片型号选择…

linux环境下用docker安装rabbitmq

1、进入docker hub镜像 仓库地址&#xff1a;https://hub.docker.com/ 2、搜索rabbitMq&#xff0c;进入官方 的镜像可以&#xff0c;看到以下几种类型的镜像&#xff1b;我们选择带有“mangement”的版本&#xff08;包含web管理页面&#xff09;&#xff1b; 3、拉取镜像 …

从头学Qt Quick(3)-- 用QML写一个简单的颜色选择器

先看一下效果图&#xff1a; 实现功能&#xff1a;点击不同的色块可以改变文字的颜色。 实现步骤&#xff1a; 一、创建一个默认的Qt Quick工程: 二、添加文件Cell.qml 这一步主要是为了实现一个自定义的组件&#xff0c;这个组件就是我们看到的那个色块&#xff0c;很明显定义…

LED闪烁和流水灯,调试教程,在线仿真器的使用

常用的延时方法&#xff1a; 软件延时&#xff08;使用简单但是浪费CPU资源&#xff09;、定时器延时&#xff08;不浪费CPU资源&#xff09;&#xff0c;本次先使用软件延时。 LED全亮代码&#xff1a; #include<reg52.h> //引用51的头文件 void main() {P10; }整体代…

docker中命令docker images

docker images 用于查看本地已下载的镜像 REPOSITORY 镜像仓库 TAG 镜像标签 IMAGE ID 镜像ID CREATED 镜像创建时间 SIZE 镜像大小

用VS2017开发安卓应用

vs2017自安装以后就没怎么打开过&#xff0c;虽然12出的时候用10&#xff0c;15出的时候用13&#xff0c;17出的时候用15&#xff0c;但我依然坚持不用也装上再说的理念。1、vs2017开发IOS和Android安装所必不可少的&#xff0c;uwp和net core也顺便装了吧&#xff0c;作为一个…

C51蜂鸣器和数码管动静态显示

蜂鸣器代码 #include<reg52.h> #include<intrins.h>#define uint unsigned int #define uchar unsigned charsbit beepP2^3; uchar temp; void delay(void) //误差 -0.000000000023us {unsigned char a,b;for(b221;b>0;b--)for(a207;a>0;a--); } void mai…

MYSQL 定时自动执行任务

MYSQL5.1开始支持EVENT功能&#xff0c;类似Oracle和MSSQL的定时任务job功能。有了这个功能之后我们就可以让MySQL自动的执行存储过程来实现数据汇总等功能了&#xff0c;不用像以前哪样手动操作完成了。下面我们来测试下&#xff0c;在MYSQL中如何自动执行指定存储过程&#x…

docker删除本地已下载的镜像

1&#xff1a;首先用 docker images 查看一下本地已下载的镜像 2&#xff1a;使用 docker rmi --force IMAGED ID 删除镜像

51单片机独立键盘和矩阵键盘

独立键盘代码&#xff1a; #include<reg52.h> #include<intrins.h>#define uint unsigned int #define uchar unsigned charsbit beepP2^3; sbit DUAN P2^6;//数码管段选 sbit WEIP2^7; //数码管位选sbit key_s2 P3^0;//独立按键s2 sbit key_s3 P3^1;//独立按键s3…