【驱动】linux设备驱动·字符设备驱动开发
Preface
前面对linux设备驱动的相应知识点进行了总结,现在进入实践阶段!
《linux设备驱动入门篇》:http://infohacker.blog.51cto.com/6751239/1218461
《linux设备驱动扫盲篇》:http://infohacker.blog.51cto.com/6751239/1218747
《fedora下的字符设备驱动开发》:http://infohacker.blog.51cto.com/6751239/1155153
开发一个基本的字符设备驱动
在Linux内核驱动中,字符设备是最基本的设备驱动。
字符设备包括了设备最基本的操作,如打开设备、关闭设备、I/O控制等。
功能:❶建立一个名为GlobalChar的虚拟设备,设备内部只有一个全局变量供用户操作。设备提供了❷读函数读取全局变量的值并且返回给用户,❸写函数把用户设定的值写入全局变量。
①代码如下:
//GlobalCharDev.c
#include <linux/fs.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("mystery");
#define DEV_NAME "GlobalChar"
static ssize_t GlobalRead(struct file *, char *, size_t, loff_t *);
static ssize_t GlobalWrite(struct file *, const char *, size_t, loff_t *); static int char_major = 0;
static int GlobalData = 0; // "GlobalData" 设备的全局变量
//初始化字符设备驱动的file_operations结构体
static const struct file_operations globalchar_fops =
{
.read = GlobalRead,
.write = GlobalWrite
}; //注意分号啊!!!
//模块初始化函数
static int __init GlobalChar_init(void)
{
int ret;
ret = register_chrdev(char_major, DEV_NAME, &globalchar_fops); //注册设备驱动
if (ret < 0)
{
printk(KERN_ALERT "GlobalChar Reg Fail ! \n");
}
else
{
printk(KERN_ALERT "GlobalChar Reg Success ! \n");
char_major = ret;
printk(KERN_ALTER "Major = %d \n",char_major);
}
return ret;
}
//模块卸载函数
static void __exit GlobalChar_exit(void)
{
unregister_chrdev(char_major, DEV_NAME); //注销设备驱动
return;
}
//设备驱动读函数
static ssize_t GlobalRead(struct file *filp, char *buf, size_t len, loff_t *off)
{
if(copy_to_user(buf, &GlobalData, sizeof(int))) //从内核空间复制GlobalData到用户空间
{
return -EFAULT;
}
return sizeof(int);
}
//设备驱动写函数
static ssize_t GlobalWrite(struct file *filp, const char *buf, size_t len, loff_t *off)
{
if(copy_from_user(&GlobalData, buf, sizeof(int))) //从用户空间复制GlobalData到内核空间
{
return -EFAULT;
}
return sizeof(int);
}
module_init(GlobalChar_init);
module_exit(GlobalChar_exit);
在内核中操作数据要区分数据的来源,对于用户空间的数据要使用copy_from_user()函数复制,使用copy_to_user()函数回写,不能直接操作用户空间的数据,否则会产生内存访问错误。
②编写Makefile
obj-m := GlobalCharDev.o
KDIR := /lib/modules/$(shell uname -r)/build
SRCPWD := $(shell pwd)
all:
make -C $(KDIR) M=$(SRCPWD) modules
③编译并加载内核模块
④查看内核分配的主设备号
⑤使用mknod命令建立一个设备文件
mknod命令使用-m参数指定GlobalChar设备可以被所有用户访问。
249即上面查询的主设备号。
到这里,我们就已经正确地添加了一个字符设备到内核,下面需要测试一下驱动程序能否正常工作。
测试字符设备驱动
为了测试编写的字符设备是否能正常工作,我们编写一个应用程序测试一下能否正常读写字符设备。
测试代码:
//GlobalCharTest.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#define DEV_NAME "/dev/GlobalChar"
int main()
{
int fd,num; fd = open(DEV_NAME, O_RDWR, S_IRUSR | S_IWUSR); //打开设备文件
if (fd < 0)
{
printf("Open Deivece Fail ! \n");
return -1;
}
read(fd, &num, sizeof(int));
printf("The GlobalChar is %d \n", num); //获取当前设备数值
printf("Please input a number written to GlobalChar: ");
scanf("%d", &num);
write(fd, &num, sizeof(int)); //写入新的数值
read(fd, &num, sizeof(int));
printf("The GlobalChar is %d \n", num); //重新读取设备数值
close(fd);
return 0;
}
程序首先使用open函数打开设备文件,然后使用read()函数读取字符设备的值,open()系统调用最终会被解释为字符设备注册的read调用。
测试结果:
从程序输出结果来看,最初从设备得到的数值是0,输入520后写入到字符设备,重新读出的数值也是520,与设置相同,表示设备驱动程序功能正确。
总结
linux字符设备驱动也不过如此嘛,嘿嘿,虽然只实现了read和write两个函数,不过其它函数也大同小异。
重点:实践再实践!!!
本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1219217
【驱动】linux设备驱动·字符设备驱动开发的更多相关文章
- Linux块设备和字符设备
块设备:系统能够随机无序访问固定大小的数据片的设备,这些数据片称为块.块设备是以固定大小长度来传送资料的,它使用缓冲区暂存数据,时机成熟后从缓存中一次性写入到设备或者从设备中一次性放到缓存区.常见的块 ...
- Linux平台块设备到字符设备(裸设备)的三种映射方式(转载)
在Linux平台oracle rac的组建过程中,如果使用ASM+RAW的存储方式的话,由于asm不支持块设备,支持持字符访问设备,所以需要配置将Block Device Drive转变成Charac ...
- 002_linux驱动之_register_chrdev注册字符设备
(一)解析:register_chrdev函数和unregister_chrdev函数 (二)register_chrdev函数原型 int register_chrdev(unsigned int ...
- Linux学习 :字符设备框架
一.系统功能框架: U-boot : 启动内核 linux kernel: 启动应用 应用: open,read,write 都是通过C库实现,汇编就相当于swi val,引发中断,通过系统调用接口在 ...
- linux device driver —— 字符设备
现在对linux设备驱动还没有什么认识,跟着书上敲了一个字符驱动,这里把代码贴一下. 测试环境是 Ubuntu 16.04 64bit 驱动程序: #include <linux/fs.h> ...
- 韦东山驱动视频笔记——3.字符设备驱动程序之poll机制
linux内核版本:linux-2.6.30.4 目的:我们在中断方式的按键应用程序中,如果没有按键按下,read就会永远在那等待,所以如果在这个程序里还想做其他事就不可能了.因此我们这次改进它,让它 ...
- Linux 设备驱动程序 字符设备
已经无法再精简,适合入门. #include<linux/module.h> #include<linux/init.h> #include<asm/uaccess.h& ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
- 《linux设备驱动开发详解》笔记——6字符设备驱动
6.1 字符设备驱动结构 先看看字符设备驱动的架构: 6.1.1 cdev cdev结构体是字符设备的核心数据结构,用于描述一个字符设备,cdev定义如下: #include <linux/cd ...
- Linux应用程序访问字符设备驱动详细过程【转】
本文转载自:http://blog.csdn.net/coding__madman/article/details/51346532 下面先通过一个编写好的内核驱动模块来体验以下字符设备驱动 可以暂时 ...
随机推荐
- Swift3 文件操作常用方法汇总
基于swift3的一些常用文件操作方法: 1.创建文件(文件夹) 2.读取文件(根据名称) 3.读取文件(根据路径) 4.判断文件是否存在(根据名称) 5.判断文件是否存在(根据路径) 6.删除指定名 ...
- HDUOJ-------单词数
单词数 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- 更新卡片的zIndex
问题描述 屏幕上有若干张互相重叠的卡片,用户每点击一张卡片,就要把这张卡片的移到最上面,也就是把它的zIndex置为最大值.应该如何操作每个卡片的zIndex才能实现? 实现方案一 定义一个全局变量g ...
- android开发学习---linux下开发环境的搭建&& android基础知识介绍
一.配置所需开发环境 1.基本环境配置 JDK 5或以上版本(仅有JRE不够) (http://www.oracle.com/technetwork/java/javase/downloads/ind ...
- HTTPS 指南
苹果在 WWDC 2016 上宣布:2016 年底将要求所有 APP 适配苹果的 App Transport Security,简单地说就是除了特殊情况(浏览器.第三方服务.媒体)外,APP 跟服务端 ...
- .NET跨平台实践:用C#开发Linux守护进程-Daemon
Linux守护进程(Daemon)是Linux的后台服务进程,它脱离了与控制终端的关联,直接由Linux init进程管理其生命周期,即使你关闭了控制台,daemon也能在后台正常工作. 一句话,为L ...
- sqlserver不太常见的,可能常见但又疑问的tsql语句
2013年10月29日16:01:58 当数据有 time类型列时候,比如 打电话的通话时长,我们查询时候不方便,我们可以添加一个冗余列,直接统计秒 ,但是 后期知道的,现在我把例如 00:12:23 ...
- 跟我学SharePoint 2013视频培训课程——使用垃圾箱(5)
课程简介 第5天,在SharePoint 2013中 使用垃圾箱 视频 SharePoint 2013 交流群 41032413
- freeswitch订阅会议相关通知
一. freeswitch订阅会议相关通知 event plain CUSTOM conference::maintenance 这时会收到各种通知,会议创建.成员加入.成员离开.成员开始讲话,成员停 ...
- springboot 中使用Druid 数据源提供数据库监控
一.springboot 中注册 Servlet/Filter/Listener 的方式有两种,1 通过代码注册 ServletRegistrationBean. FilterRegistration ...