字符设备 -----LDD3
来源:互联网 发布:中国消防网站域名 编辑:程序博客网 时间:2024/05/17 02:23
水平有限,若有错误亦或者不当的地方,请大家不吝值出。谢谢~
字符设备创建流程
1、申请字符设备设备号
2、注册字符设备
一、字符设备主次设备号的申请
dev_t --->linux/types.h
dev_t 设备号变量声明, 32 bit
bit31-20 主设备号
bit19- 0 次设备号
1、静态申请
int register_chrdev_region(dev_tfirst, unsigned int count, char *name)
first: 设备号的起始值(主设备号,起始次设备号)
count:申请的次设备号个数
name: 与设备号关联的设备名称,出现在/proc/devices
返回值 : 0 : 成功 <0 :失败
2、动态申请
int alloc_chrdev_region(dev_t*dev, unsigned intfirstminor, unsigned int count, char *neme)
dev:输出值,起始设备号
firstminor:起始次设备号
count:次设备号个数
name:与设备号关联的设备名称,出现在/proc/devices
返回值 : 0 : 成功 <0 :失败
3、释放设备号
voidunregister_chrdev_region(dev_tfirst, unsigned int count)
first: 起始设备号
count:次设备号个数
二、字符设备注册
//字符设备结构体
struct cdev { -----><linux/cdev.h>
structkobjectkobj;
struct module *owner;
conststructfile_operations *ops; //文件操作
structlist_head list;
dev_tdev;
unsignedint count;
};
1、字符设备注册
方法一:
//分配一个字符设备结构体
structcdev *my_cdev = cdev_alloc();
//初始化字符设备结构体
my_cdev->ops = *my_fops; //关联file_operations
my_cdev->ower = THIS_MODULE;
//添加设备及其关联设备号、到内核中
int cdev_add(structcdev *dev, dev_tnum;unsigned int count);
dev:字符设备结构体
num:字符设备起始设备号
count: 次设备号个数
返回值: 0 成功 <0:失败
方法二:
structcdevcdev;
cdev_init(&dev->cdev,&scull_fops); //关联字符设备及file_operation
dev->cdev.owner = THIS_MODULE;
int cdev_add(structcdev *dev, dev_tnum;unsigned int count);
2、移除字符设备
voidcdev_del(structcdev *dev)
三个重要结构体-----><linux/fs.h>
structfile_operations ---->文件操作结构体
struct file ---->每个打开的文件都有一个structfile
structinode --->每个文件都对应着一个inode->structcdev
每个打开的文件都对应着一个struct file. 每个文件在文件系统中都对应着一个inode.
当多次打开同一文件时,内核中会存在多个struct file,但都对应一个inode.
struct inode
{
dev_ti_rdev; --->字符设备设备号
structcdev* i_cdev; --->字符设备结构体
......
}
打开一个字符设备结构体关联流程
Open(“/dev/xxx”, O_RDWR)–->struct file->inode->cdev->structfile_operations
//2.6版本前字符设备注册与释放
intregister_chrdev(unsigned int major,const char *name, structfile_operations *fops)
major : 主设备号
name : 驱动程序,出现在/proc/devices中
fops :文件操作相关, file_operations
返回值:> 0主设备号。次设备号会默认0-255中的某一个
<0, 调用失败
//释放
intunregister_chrdev(unsigned int major, constchar *name)
major:主设备号
name : 设备名称
Demo
/*
* cdev demo create by Yxl @20150406
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/cdev.h> //char devices
#include <linux/fs.h> //struct file, struct inode, struct file_operation
#include <linux/proc_fs.h> //----> procfs
#include <linux/device.h> // class & device
#include <asm/uaccess.h> //copy_to_user, copy_from_user
unsigned char* gPMem = NULL;
/*模块参数*/
static int gData = 0;
static char *gStr = "this is my cdev.ko";
module_param(gData, int, S_IRUGO);
module_param(gStr, charp, S_IRUGO);
/****************************字符设备*******************************/
/*设备号*/
dev_t gDev = 0;
/*字符设备设备*/
struct cdev *gCdev = NULL;
static int Mycdev_open(struct inode * inode, struct file * filp)
{
printk(KERN_INFO "%s", __FUNCTION__);
try_module_get(THIS_MODULE);
return 0;
}
static ssize_t Mycdev_read(struct file* filp, char __user *buffer, size_t count, loff_t *offp)
{
printk(KERN_INFO "%s", __FUNCTION__);
return 0;
}
static ssize_t Mycdev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
printk(KERN_INFO "%s", __FUNCTION__);
return 0;
}
static int Mycdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
printk(KERN_INFO "%s", __FUNCTION__);
return 0;
}
static int Mycdev_release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "%s", __FUNCTION__);
module_put(THIS_MODULE);
return 0;
}
/*字符设备文件操作*/
struct file_operations Mycdev_fops = {
.owner = THIS_MODULE,
.open = Mycdev_open,
.read = Mycdev_read,
.write = Mycdev_write,
.unlocked_ioctl = Mycdev_ioctl,
.release = Mycdev_release,
};
/******************************class&device*******************************/
struct class *gcdev_class = NULL;
struct device *gcdev_device = NULL;
/*********************************proc操作*****************************/
/*Proc 调试信息*/
struct proc_dir_entry *gPentry = NULL;
struct proc_dir_entry *gentry = NULL;
/*proc_read/ proc_write*/
static int cdevDump_read_proc(char *page, char **start, off_t offset, int count, int *eof, void *data)
{
int len = sprintf(page,"%s\n","hello world");
return len;
}
static int cdevDump_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
return 0;
}
//proc file_operations 操作
struct file_operations CdevProc_fpos={
};
/*********************************proc操作**************************/
static int __init Mycdev_init(void)
{
int ret = 0;
printk(KERN_INFO "%s", __FUNCTION__);
printk(KERN_INFO "gStr = %s, module_param gData = %d\n",gStr, gData);
// 1
/*注册设备号, /proc/devices可以看到Mycdev名字*/
ret = alloc_chrdev_region(&gDev, 0, 1, "Mycdev");
if(ret < 0)
{
printk(KERN_ERR "alloc_chrdev_region failed, ret = %d\n", ret);
return ret;
}
/*注册字符设备*/
gCdev = cdev_alloc();
cdev_init(gCdev, &Mycdev_fops);
gCdev->owner = THIS_MODULE;
gCdev->ops = &Mycdev_fops;/*可以不做,cdev_init里已经做了*/
ret = cdev_add(gCdev, gDev, 1);
if(ret < 0)
{
printk(KERN_ERR "cdev_add failed, ret = %d\n", ret);
return ret;
}
// 2 /sys/class/cdev/DevCdev
/*自动创建/dev/设备节点, cdev : /sys/class下类名文件夹*/
gcdev_class = class_create(THIS_MODULE, "cdev");
if(gcdev_class == NULL)
{
printk(KERN_ERR "class_create failed...\n");
return -1;
}
/*向sysfs注册class, 并关联设备号, DevCdev: /dev/下节点名字*/
gcdev_device = device_create(gcdev_class, NULL, gDev, NULL, "DevCdev");
if(gcdev_device == NULL)
{
printk(KERN_ERR "device_create failed...\n");
return -1;
}
// 3
/*创建/proc/media 调试信息*/
// 1 创建/proc/media目录
gPentry = proc_mkdir("media", NULL);
if(gPentry == NULL)
{
printk(KERN_ERR "proc_mkdir failed...\n");
}
// 创建/proc/media/cdevDump文件
#if 1
gentry = create_proc_entry("cdevDump", 0666, gPentry);
if(gentry)
{
gentry->proc_fops = &CdevProc_fpos;
gentry->read_proc = cdevDump_read_proc;
gentry->write_proc = cdevDump_write_proc;
}
else
{
printk(KERN_ERR "create_proc_entry failed...\n");
}
#else
/*在高版本中, create_proc替换了create_proc_entry*/
gentry = proc_create("cdevDump", 0666, gPentry, &CdevProc_fpos);
if(gentry == NULL)
{
printk(KERN_ERR "create_proc failed...\n");
}
#endif
return 0;
}
static void __exit Mycdev_exit(void)
{
printk(KERN_INFO "%s", __FUNCTION__);
// 1
/*销毁proc 文件*/
remove_proc_entry("cdevDump", gPentry);
remove_proc_entry("media", NULL);
// 2
/*销毁class & device*/
device_destroy(gcdev_class, gDev);
class_destroy(gcdev_class);
// 3
/*销毁字符设备(先销毁设备,再销毁设备号)*/
cdev_del(gCdev);
/*销毁设备号*/
unregister_chrdev_region(gDev, 1);
}
module_init(Mycdev_init);
module_exit(Mycdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yxl");
- LDD3--字符设备源码
- 字符设备 -----LDD3
- LDD3 字符设备驱动
- LDD3笔记:第三章 字符设备驱动
- LDD3源码分析之字符设备驱动程序
- LDD3源码分析之字符设备驱动程序
- 学习Ldd3--字符设备驱动(第三章)
- LDD3源码分析之字符设备驱动程序
- LDD3源码分析之字符设备驱动程序
- ldd3笔记_字符设备驱动
- LDD3源码分析之字符设备驱动程序
- LDD3源码分析之字符设备驱动程序
- LDD3笔记——字符设备驱动简单分析
- 字符设备驱动相关函数及数据结构简介 (ldd3)
- 字符设备驱动相关函数及数据结构简介 (ldd3)
- LDD3中scull字符设备源代码完全解析(一)
- LDD3源码分析之字符设备驱动程序(加上测试代码)
- ldd3 源码编译之 scullc 字符设备驱动 错误解决办法
- HDU 1863--畅通工程【Prim && kruskal】
- USB device & USB controller & USB passthrough
- [驱动注册]platform_driver_register()与platform_device_register()
- gradle学习(14)-任务
- 问题四
- 字符设备 -----LDD3
- 推导坐标旋转公式
- 版本升级提示与下载
- 数据结构课程设计(c++) 3号题
- ubuntu下载mysql
- SSL/TLS/DTLS对比
- cas keytools 导入 jks
- Android createChooser方法源码简析
- 计算机视觉、机器学习相关领域论文和源代码