Linux字符设备驱动
/*Linux字符设备驱动源代码scdd.c*/
#include <linux/init.h> /*模块头文件*/
#include <linux/module.h>
#include <linux/types.h> /*dev_t头文件*/
#include <linux/kdev_t.h> /*MAJOR和MINOR宏头文件*/
#include <linux/fs.h> /*register_chrdev_region等函数
file_operations结构体*/
#include <linux/cdev.h> /*struct cdev结构体*/
#include <asm/uaccess.h> /*copy_to_user函数*/
#define DEVICE_NAME "scdd" /*定义设备名*/
#define DEVICE_MAJOR 250
struct cdev my_cdev;
int scdd_open(struct inode *inode,structfile *filp)
{
return0;
}
int scdd_close(struct inode *inode,structfile *filp)
{
return0;
}
ssize_t scdd_read(struct file *filp,char__user *buff,size_t size,loff_t *offp)
{
intleft;
chardata=1;
for(left=size;left>0;left--)
{
/*拷贝数据到用户空间*/
copy_to_user(buff,&data,1);
buff++;
}
returnsize;
}
ssize_t scdd_write(struct file *filp,char__user *buff,size_t size,loff_t *offp)
{
return0;
}
/*file_operations结构体*/
struct file_operations scdd_fops={
.owner=THIS_MODULE,
.read=scdd_read,
.write=scdd_write,
.open=scdd_open,
.release=scdd_close,
};
static int __init scdd_init(void)
{ /*模块初始化函数*/
intsmajor;
smajor=DEVICE_MAJOR;
dev_tdev_n=MKDEV(smajor,0);
/*申请设备号*/
if(!register_chrdev_region(dev_n,1,DEVICE_NAME))
{ /*静态申请*/
printk("registersuccess\n");
}else
{
gotoregister_error;
}
/*else
{ /*动态申请*/
/*alloc_chrdev_region(&dev_n,0,1,DEVICE_NAME);
smajor=MAJOR(dev_n);
}*/
/*初始化cdev结构体*/
cdev_init(&my_cdev,&scdd_fops);
my_cdev.owner=THIS_MODULE;
my_cdev.ops=&scdd_fops;
/*注册字符设备*/
cdev_add(&my_cdev,dev_n,1);
return0;
register_error:
unregister_chrdev_region(MKDEV(DEVICE_MAJOR,0),1);
return0;
}
static void __exit scdd_exit(void)
{ /*模块卸载函数*/
cdev_del(&my_cdev);
unregister_chrdev_region(MKDEV(DEVICE_MAJOR,0),1);
}
module_init(scdd_init);
module_exit(scdd_exit);
MODULE_LICENSE("Dual BSD/GPL");
这个程序只是简单演示字符注册的一个完整过程,并不带有复杂的操作,调用read时向用户空间写全1
要点:
1.设备号,主设备号用来标识设备所对应的驱动程序,同一个驱动程序可以对应多个设备,次设备号就是用来区分采用同一个驱动程序的不同设备文件。
内核中采用dev_t来描述设备号,其实dev_t实质为unsigned int类型,其中高12位为主设备号,低20位为次设备号,其定义在linux/types.h中
从dev_t中分解出主设备号和次设备号
MAJOR(dev_t dev)
MINOR(dev_t dev)
将主设备号和次设备号转换成dev_t类型
MKDEV(intmajor,int minor)
2.申请设备号
静态申请,函数定义在linux/fs.h中
int register_chrdev_region(dev_t from,unsigned count,const char *name)
from是申请设备号起始值,from次设备号经常被置成0,count是所请求连续设备号个数,name是该设备号范围关联的名称,它将出现在/proc/device和sysfs中。
分配成功返回0,错误情况下,将返回一个负的错误码,并且不能使用所请求的设备号。
动态申请
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
申请的设备号将保存在dev中,baseminor为所申请的第一个次设备号
无论哪种方式申请设备号,不使用时要释放设备号
void unregister_chrdev_region(dev_t first,unsigned int count)
3.三个重要的结构
struct file_operations
struct file
struct inode
struct file_operations一个函数指针集合,定义能在设备上进行的操作,常用的有:
int (*open)(structinode *inode,stuuct file *filep)
void (*release)(structinode *inode,struct file *filep)
ssize_t(*read)(struct file *filep,char __user *buff,size_t size,loff_t *offp)
ssize_t(*write)(struct file *filep,char __user *buff,size_t seze,loff_t * offp)
int(*ioctl)(struct inode *inode,struct file *filep,unsigned int cmd,unsigned longarg) off_t(*llseek)(struct file *filp,loff_t,int)
struct file表示一个打开的文件,一个文件被打开十次,则有10个structfile结构
struct file结构成员有:
mode_t f_mode 文件模式,例如:可读可写
lofft_t f_pos 当前读/写位置
struct file_operations *f_op 与文件相关操作,执行open操作时对这个指针赋值
void *private_data在open时置为NULL,用于跨系统调用时保存非常有用的资源
struct inode用来记录文件的物理上的信息,一个文件被打开10次,但只有一个structinode结构,struct inode结构成员如下:
dev_t i_rdev 用来保存设备号
struct cdev*i_cdev 指向字符设备结构struct cdev的指针
4.字符设备的注册
内核使用struct cdev结构表示字符设备,定义在linux/cdev.h中。
初始化cdev结构体有两种方式
静态:
struct cdev my_cdev;
cdev_init(&my_cdev,&fops);
my_cdev.owner = THIS_MODULE;
动态(就是通过kmalloc去申请cdev结构):
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops= &my_fops;
my_cdev.owner= THIS_MODULE;
注册
int cdev_add(struct cdev *dev,dev_t num,unsigned int count)
num是设备号,count经常取1
注销
void cdev_del(struct cdev *dev)
早起比较经典的字符设备驱动注册和注销方法
注册
int register_chrdev(unsigned int major,const char *name,struct file_operations*fops)
注销
int unregister_chrdev(unsigned int major,const char *name)
转载于:https://www.cnblogs.com/phonegap/archive/2011/12/09/2536134.html
Linux字符设备驱动相关推荐
- ()shi linux字符设备,Linux字符设备驱动基础(三)
Linux字符设备驱动基础(三) 6 创建设备节点 6.1 手动创建设备节点 查看申请的设备名及主设备号: cat /proc/devices # cat /proc/devices Characte ...
- linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说
一.软件操作硬件设备模型 在进行嵌入式开发的过程中,在常做的事情就是驱动配置硬件设 备,然后根据功能需求使用硬件设备,实现功能的逻辑.如下图为其 相互之间的关系. 如上图所示: 驱动程序:主要作为操作 ...
- linux字符设备文件的打开操作,Linux字符设备驱动模型之字符设备初始化
因为Linux字符设备驱动主要依赖于struct cdev结构,原型为: 所以我们需要对所使用到的结构成员进行配置,驱动开发所使用到的结构成员分别为:[unsigned int count;].[de ...
- linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点
嵌入式Linux字符设备驱动开发流程--以LED为例 前言 留空 头文件 #include 查看系统设备类 ls /sys/class 设备类结构体 文件(路径):include/linux/devi ...
- linux字符设备驱动的 ioctl 幻数
在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能.首先,我们先来看看3.0内核下../include/linux/fs.h中fil ...
- Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析
前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...
- linux字符设备驱动在哪里设置,从点一个灯开始学写Linux字符设备驱动!
原标题:从点一个灯开始学写Linux字符设备驱动! [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一 ...
- Linux字符设备驱动中container_of宏的作用
Linux字符设备驱动中container_of宏的作用 首先看看这个宏的原型: container_of(ptr,type,member) 功能:根据一个结构体变量中的一个成员变量的指针来获取指向整 ...
- linux3.0字符设备驱动,linux字符设备驱动的 ioctl 幻数
在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能.首先,我们先来看看3.0内核下../include/linux/fs.h中fil ...
最新文章
- 面试命中率 90% 的点 :MySQL 锁
- kindle刷多看系统_疑问解答 | kindle真的能护眼吗?
- 2013\Province_C_C++_A\3.振兴中华
- python中排序从小到大_从Python看排序:冒泡排序
- 使用 gunicorn 部署flask项目
- VMware 安装kali——linux
- ipc (进程间通信
- 2019年7月9日星期二(C语言)
- 关于Unity3D脚本调试
- 由浅入深探究mysql索引结构原理、性能分析与优化
- java 获取拦截url,java – 从数据库或属性中获取Spring Security拦截URL
- 解决未在此计算机注册ActiveX 控件
- python输入矩阵_python矩阵输入
- Linux固态硬盘 设置写入缓存,Win10下的写入缓存策略严重影响SSD硬盘的性能!
- 不越狱将ipa安装到iphone
- EXCEL插入、数据灰色不能使用的解决办法之一
- 数组(一维数组,二维数组)
- 固态硬盘在线测试软件,ssd测试软件,详细教您ssd测试软件
- wireshark源码分析二
- Omnipeek空口抓包(2):扫描无线网络
热门文章
- C++函数参数传递--值传递和地址传递
- 详解机器学习的凸优化、图神经网络、强化学习、贝叶斯方法等四大主题
- Unet美发实例分割,染发展示
- yum update upgrade 区别_CentOS与RedHat的区别
- oracle 11g Flashback Data Archive(闪回数据归档)
- Qt实现Areo效果_vortex_新浪博客
- egg风格 什么意思_egg裙什么意思
- 嵌入式实时操作系统ucos-ii_「正点原子NANO STM32开发板资料连载」第三十八章 UCOSII 实验 3...
- mysql性能优化方案总结
- Nancy之从403到错误处理