linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架
还是老规矩先上代码
demo.c
#include #include#include#include#include
int demo_major = 250;int demo_minor = 0;int demo_count = 1;structcdev cdev;int demo_open(struct inode *inodep, struct file * filep) //打开设备
{
printk("%s,%d\n", __func__, __LINE__);return 0;
}int demo_release(struct inode * inodep, struct file * filep) //关闭设备
{
printk("%s,%d\n", __func__, __LINE__);return 0;
}struct file_operations fops ={
.owner=THIS_MODULE,
.open=demo_open,
.release=demo_release,
};static int __init demo_init(void)
{int ret = 0;
dev_t devno;
printk("%s,%d\n", __func__, __LINE__);//使用下列宏则可以通过主设备号和次设备号生成 dev_t
devno =MKDEV(demo_major, demo_minor);
printk("devno:%d\n", devno);
printk("demo_major:%d\n", demo_major);/**在调用 cdev_add()函数向系统注册字符设备之前,
*应首先调用 register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号
**/
if(demo_major)//静态申请
{
ret= register_chrdev_region(devno, 1, "demo");
}else//动态分配
{
ret= alloc_chrdev_region(&devno, 0, 1, "demo");
}if(ret)
{
printk("Failed to register_chrdev_region.\n");returnret;
}//cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接
cdev_init(&cdev, &fops);
cdev.owner=THIS_MODULE;//系统添加一个 cdev,完成字符设备的注册。
ret = cdev_add(&cdev, devno, demo_count);if(ret)
{
printk(KERN_NOTICE"Failed to cdev_add [Error] %d adding demo%d", ret, demo_count);
unregister_chrdev_region(devno, demo_count);returnret;
}return 0;
}static void __exit demo_exit(void)
{
printk("%s,%d\n", __func__, __LINE__);//删除一个 cdev,完成字符设备的注销。
cdev_del(&cdev);//在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号
unregister_chrdev_region( MKDEV(demo_major, demo_minor), demo_count );
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_AUTHOR("libra13179");
MODULE_LICENSE("GPL v2");
Makefile
VERS = $(shell uname -r)
# Kernel modules
obj-m +=demo.o
# Specify flagsforthe module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make-C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make-C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
make测试一下
使用dmesg指令来查看
使用 cat /proc/devices看到demo的信息
下面截图来自https://blog.csdn.net/u012142460/article/details/78932165
现在主要介绍demo.c中使用到函数和宏,结构体等
使用cdev结构体描述一个字符设备
1 structcdev2 {3 struct kobject kobj; /*内嵌的 kobject 对象*/
4 struct module *owner; /*所属模块*/
5 struct file_operations *ops; /*文件操作结构体*/
6 structlist_head list;7 dev_t dev; /*设备号*/
8 unsigned intcount;9 };
cdev结构体
cdev 结构体的 dev_t 成员定义了设备号,为 32 位,其中 12 位主设备号,20 位次设备号。
比较用到三个宏
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
用下列宏可以从 dev_t 获得主设备号和次设备号:
MAJOR(dev_t dev)
MINOR(dev_t dev)
使用下列宏则可以通过主设备号和次设备号生成 dev_t:
MKDEV(int major, int minor)
void cdev_init(struct cdev *, const struct file_operations *);//初始化cdev的成员,并建立cdev和file_operations之间关联起来struct cdev *cdev_alloc(void);//动态申请(构造)cdev内存(设备对象)void cdev_put(struct cdev *p);//释放cdev内存int cdev_add(struct cdev *, dev_t, unsigned);//注册cdev设备对象(添加到系统字符设备列表中)void cdev_del(struct cdev *);//将cdev对象从系统中移除(注销 )
/切割线//
我们增加一个测试
#include #include#include#include
int main(int argc, const char *argv[])
{intfd;int val = 1;
fd= open("/dev/xyz", O_RDWR);if (fd < 0)
{
printf("can't open!\n");return -1;
}else{
printf("open success.\n");
}
getchar();
close(fd);return 0;
}
root@lin-virtual-machine:/home/lin/demo# gcc -o demodrvtest demodrvtest.c
root@lin-virtual-machine:/home/lin/demo# ls
demo~ demodrvtest demo.mod.c Makefile~ Untitled Document~
demo.c demodrvtest.c demo.mod.o modules.order
demo.c~ demo.ko demo.o Module.symvers
root@lin-virtual-machine:/home/lin/demo# pwd/home/lin/demo
root@lin-virtual-machine:/home/lin/demo# ./demodrvtest
can't open!
root@lin-virtual-machine:/home/lin/demo# mknod /dev/xyz c 250 0root@lin-virtual-machine:/home/lin/demo# ./demodrvtest
open success.
这边使用手动来创建
手动创建设备 mknod命令
命令的格式是:mknod 设备名 设备类型(字符:c,块:b) 主设备号 从设备号
linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架相关推荐
- 奇小葩讲设备树(3/5)-- Linux设备树详解(三)u-boot设备树的传递
前面两节介绍了设备的基本概念.编译.结构的组成,本章讨论的主要内容为 dtb如何通过Bootloader引导程序加载到内核 bootloader如何解析dbt bootloader支持哪些dtb的操作 ...
- 设备树学习(三、设备树dtb格式和结构)
上一节我们学习了dts文件的格式,dts文件是方便我们书写和读写的格式.本节我们来学习一下经过Device Tree Compiler编译,Device Tree source file变成了Devi ...
- 为Exynos4412移植U-Boot-2017.11(三)——DM9000A驱动
系列文章 为Exynos4412移植U-Boot-2017.11的步骤(一) 为Exynos4412移植U-Boot-2017.11(二)--SD卡.eMMC驱动 为Exynos4412移植U-Boo ...
- windows无法访问指定设备_恢复 你的电脑/设备需要修改 未连接或无法访问所需设备。...
重装系统后重启电脑就出现了:你的电脑/设备需要修复,未连接或无法访问所需设备. 错误代码:0xc000000e 这个无法连接设备.有三种原因:一,系统驱动程序出错.二.接触不良.三.设备故障.按不同的 ...
- 字符设备驱动模板方式(linux驱动开发篇)
简述 下面针对led灯,编写老版字符驱动设备.新字符设备驱动.设备树驱动. 老版本驱动设备 register_chrdev和unregister_chrdev 问题: 1需要我们事先确定好哪些主设备号 ...
- Linux platform 设备驱动实验-基于正点原子IMX6ULL开发板
我们以前的设备驱动都非常的简单,都是对IO进行最简单的读写操作.像I2C. SPI.LCD 这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因此提出了驱动的分离与分层这样的 ...
- 君君学Linux设备驱动第一天之概述及开发环境搭建
一.设备驱动的作用: 1 计算机系统里面的软件和硬件是互相成就的,没有软件的硬件是废铁,没有硬件作为依托的软件是空中楼阁. 2 当应用软件工程师不想了解硬件底层的具体操作的时候,就需要 ...
- 应用QQ2440(s3c2440)ARM开发板驱动MMA7455加速度计的linux设备驱动编写
课题水下机器人需要测定水下机器人的位姿,为此应用了加速度计MMA7455,该传感器可以用SPI或I2C读取数字信号到MCU. 驱动MMA7455在atmega128上已经实现,但是由于mega128的 ...
- 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十一)驱动进化之路:设备树的引入及简明教程
文章目录 1.驱动进化之路:设备树的引入及简明教程 1.1 设备树的引入与作用 1.2 设备树的语法 1.2.1 Devicetree格式 1.2.1.1 DTS文件的格式 1.2.1.2 node的 ...
最新文章
- 输出程序运行的时间(精确到微秒)
- [Math][Algebra]--线性代数中的各种空间
- Chrome 0 day漏洞利用链
- apache+mod_wsgi+django的环境配置
- 到国外使用wifi悠着点防止天价帐单
- 多除了1次100的FM BAPI_CURRENCY_CONV_TO_INTERN_9
- 360浏览器 当前环境不支持支付宝控件_360 小程序来了,进攻 PC 端!
- python调用其他类中的方法_无法调用其他类中的方法
- MultipartFile多文件上传
- createdroptargets_拖拽神器React DnD你真的了解了吗?
- ASPUpLoad 文件上传
- SQL中的go、begin、end的用法
- Pareto最优解 Pareto分布
- WINDOWS备份与恢复
- 激光雕刻机装上AI,混合材料T恤上都能雕出花,自动变换力度保证不割破
- 好好说话之Use After Free
- 加拿大玩具巨头斯平玛斯特在华确权维权,爆丸专利获赔超千万,汪汪队品牌获刑事保护...
- 电源设计经验谈1-5
- 阿里云跨境游戏及电商网络加速方案(全球加速和CDN)
- 2021| 四月行业营销活动指导方案
热门文章
- Linux磁盘配额(一)
- Java自带的常用工具
- Redis笔记系列(特别总结篇)——常见配置redis.conf知识点总结
- 【巧妙算法系列】【Uva 11464】 - Even Parity 偶数矩阵
- 数论概论(Joseph H.Silverman) 定理39.2 连分数相邻收敛项之差定理
- golang time 时间 加减法
- 可视化监控指标展示工具 grafana 简介
- php web框架 symfony简介
- java jar包 和 war包 区别
- linux rpm命令 查询包安装与否、包详细信息、包安装位置、文件属于哪个包、包依赖