0.包含必须的头文件

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>            /*kfree ,kmalloc */
#include <linux/device.h>

1.编写字符设备函数

1.1、分配核心结构

struct cdev *cdev_alloc(void)

功能:分配一个核心结构。
返回值:成功,返回核心结构;失败:返回负数
说明:可以不用该函数分配,直接定义如下:

   struct cdev pcdev;

1.2、申请设备号的相关函数
1)静态申请设备号函数

int register_chrdev_region( dev_t from,unsigned count,const char *name )

功能:注册一个设备号范围。
参数:
from:起始设备号(主、次)
count:连续的次设备号数量
name:设备名,不需要和/dev/的设备文件名相同,是/proc/device文件的名字
返回值:成功,返回0;失败:返回负数
2)动态申请设备号函数

int alloc_chrdev_region(dev_t *dev,unsigned int baseminor,unsigned int count,const char *name)

功能:注册一个设备号范围。
参数:
dev:存放分配到的第一个设备(包含主次设备号)。
baseminor:要分配起始次设备号
count:连续的次设备号数量
name:设备名,不需要和/dev/的设备文件名相同
返回值:成功,返回0;失败:返回负数

1.3、初始化核心结构

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

功能:初始化核心结构;具体做的是清0核心结构,初始化核心结构的list,kobj,ops成员。
参数:
cdev:需要初始化的核心结构指针。
fops:文件操作方法结构指针。

1.4、注册核心结构

int cdev_add( struct cdev *p, dev_t dev,unsigned int count)

功能 注册一个cdev结构
参数
p:已经初始化的核心结构指针
dev:起始设备号(包含主次设备号在内);前面申请设备号函数的返回值。
count:连续次设备号数量
返回值 成功:返回0 ;失败:返回负数

1.5、注销核心结构

void cdev_del(struct cdev *p)

功能:注销一个cdev结构
参数:
p:前面注册的struct cdev结构指针

1.6、释放设备号

void unregister_chrdev_region(dev_t from, unsigned count)

功能:释放设备号
参数:
from:起始设备号(主、次)
count:连续的次设备号数量
1.7、释放核心结构空间
void kfree(struct cdev *p);
功能:注销一个cdev结构
参数:
p:前面注册的struct cdev结构指针

结构体struct cdev 已经在cdev.h定义 好,具体如下:

struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;        /* 设备文件操作方法 */struct list_head list;dev_t dev;                                       /* 32位设备号,包含主和次 */unsigned int count;                            /* 占用多少个连续的次设备号 */
}

2.自动创建/dev/目录设备文件函数

2.1创建一个设备类

#define class_create(owner, name)        \
({                      \static struct lock_class_key __key;    \__class_create(owner, name, &__key);   \
})

功能:创建一个设备类
参数:
owner:类的所有者,固定是:THIS_MODULE
name:类名,随便,能有含义最好,不是 /dev/下设备的名字。
返回值:成功:返回有效 struct class *指针;失败:返回错误指针,可以使用 ERR_PTR()宏转换成错误代码。

2.2创建一个设备,报告设备信息

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)

功能:创建一个设备
参数:
class:指定所要创建的设备所从属的类, class_create的返回值。
parent:这个设备的父设备,如果没有就指定为NULL
devt:设备号。
drvdata:设备信息,一般为NULL。
fmt:设备名称,而且是缓冲形式。

2.3删除一个设备
void device_destroy(struct class *class, dev_t devt)
功能:删除一个设备
参数:
class:指定所要创建的设备所从属的类, class_create的返回值。
devt:设备号。
2.4删除一个设备类
void class_destroy(struct class *cls)
功能:删除一个设备类
参数:
cls:指定所要创建的设备所从属的类, class_create的返回值。

代码例子:

#include <linux/kernel.h>
#include <linux/module.h>//包含必须的头文件
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>            /*kfree ,kmalloc */
#include <linux/device.h>//以下是文件操作方法的具体实现代码
static int xxx_open (struct inode *pinode, struct file *pfile)
{printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);return 0;
}
static ssize_t xxx_read (struct file *pfile,  char __user *buf,  size_t count,  loff_t *poff)
{printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);return count;
}
static ssize_t xxx_write (struct file *pfile, const char __user *buf, size_t count,  loff_t *poff)
{printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);return count;
}
static loff_t xxx_llseek (struct file *pfile, loff_t off, int whence)
{printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);return off;
}
static long xxx_unlocked_ioctl (struct file *pfile, unsigned int cmd, unsigned long args)
{printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);return 0;
}static int xxx_release (struct inode *pinode, struct file *pfile)
{printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);return 0;
}//文件操作方法集合指针
static const struct file_operations char_dev_fops={.open            =   xxx_open,.write           =   xxx_write,.read            =   xxx_read,.llseek          =   xxx_llseek,.unlocked_ioctl  =   xxx_unlocked_ioctl,.release         =   xxx_release,
};//定义核心数据结构
static struct cdev *p_cdv;
//定义第一个设备号(包含主和次)
static dev_t dev_no;
//定义设备主设备号
static unsigned int major=0;
//定义设备名
#define MYCHAR_DEV  "auto_linux26"#define CLASS_NAME  "chardev26"
static struct class *linux26_class = NULL;
static struct device *this_device = NULL;static int __init chrdev_test_init(void)
{int ret = -1;//1.使用cdev_alloc函数分配p_cdv空间p_cdv=cdev_alloc();if(p_cdv == NULL){printk("cdev_alloc error!\n");ret = -ENOMEM;/* 分配失败一般是内存不足导致的  */goto cdev_alloc_error;    }//2.申请设备号:动态或者静态ret = alloc_chrdev_region(&dev_no, 0, 2,MYCHAR_DEV);if(ret < 0){printk("alloc_chrdev_region error!\n");  goto alloc_chrdev_region_error;}//3.初始化p_cdv结构cdev_init(p_cdv, &char_dev_fops);//4.注册已经初始化好的c_dev结构ret = cdev_add(p_cdv, dev_no, 2);if ( ret < 0 ) {    printk(KERN_EMERG "cdev_add  error\n");goto cdev_add_error;}/* 增加自动创建设备文件功能 *///5.创建一个设备类// linux26_class = class_create(THIS_MODULE,MYCHAR_DEV);//可以和设备名相同linux26_class = class_create(THIS_MODULE, CLASS_NAME); //取一个不同于设备名的类名if ( IS_ERR(linux26_class) ) {   ret = PTR_ERR(linux26_class);goto class_create_err;}//6.创建一个设备,报告设备信息this_device =  device_create(linux26_class,NULL , dev_no,   NULL, "%s", MYCHAR_DEV);if ( IS_ERR(this_device) ) {ret = PTR_ERR(this_device);goto device_create_err;}major=MAJOR(dev_no);printk(KERN_EMERG "major = %d \n",major);return 0;device_create_err:class_destroy(linux26_class);class_create_err:cdev_del(p_cdv);cdev_add_error:unregister_chrdev_region(dev_no, 2);alloc_chrdev_region_error:kfree(p_cdv);/*释放p_cdv结构空间*/cdev_alloc_error:return ret;
}static void __exit chrdev_test_exit(void)
{device_destroy(linux26_class, dev_no);class_destroy(linux26_class);//1.注销p_cdv结构cdev_del(p_cdv);//2.释放设备号unregister_chrdev_region(dev_no, 2);//3.释放p_cdv结构空间kfree(p_cdv);//4.删除设备device_destroy(linux26_class, devnr);//5.删除设备类class_destroy(linux26_class);
}module_init(chrdev_test_init);
module_exit(chrdev_test_exit);MODULE_LICENSE("GPL");

如何编写字符设备驱动相关推荐

  1. 新字符设备驱动实验(自动分配设备号、自动创建应用层设备节点、新字符设备注册到内核的结构体)

    目录 自动分配和释放设备号 示例代码 新的字符设备注册到内核方法 字符设备结构体(前面的设备号也放进来) cdev_init结构体初始化函数 cdev_add 添加到linux内核 cdev_del内 ...

  2. 虚拟字符设备驱动开发步骤

    目录 前言 字符设备驱动简介 内核驱动操作函数集合(file_operations结构体) 字符设备驱动开发步骤 .ko驱动模块的加载和卸载(module_init驱动入口.insmod驱动加载) 字 ...

  3. linux的驱动开发——字符设备驱动

    1.字符设备驱动 \qquad字符设备驱动是最基本,最常用的设备.它将千差万别的硬件设备采用统一的接口封装起来,屏蔽了硬件的差异,简化了应用层的操作. 2.描述所有字符设备的结构体 \qquad描述所 ...

  4. Linux内核学习-字符设备驱动学习(二)

    在Linux内核学习-字符设备驱动学习(一)中编写字符设备驱动的一种方法,但是需要手动创建设备节点. 有没有能够自动的创建设备节点的呢? 有!使用class_create()和device_creat ...

  5. 第六讲 Linux字符设备驱动1

    六.字符设备驱动 6.1.基本概念 Linux操作系统思想:一切皆文件 对设备的操作,也是将设备抽象成设备文件,应用层通过文件IO对设备文件进行操作,其最终结 果,是在操作设备. Linux操作系统, ...

  6. Linux驱动之字符设备驱动

    系列文章目录 第一章 Linux入门之驱动框架 第二章 Linux驱动之字符设备驱动 文章目录 系列文章目录 前言 一.认识字符设备驱动 1.基本概念 2.基本概念 二.字符设备旧框架 1.注册和注销 ...

  7. 【正点原子MP157连载】第二十二章 新字符设备驱动实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  8. Linux 字符设备驱动开发基础(一)—— 编写简单 LED 设备驱动

    现在,我们来编写自己第一个字符设备驱动 -- 点亮LED.(不完善,后面再完善) 硬件平台:Exynos4412(FS4412) 编写驱动分下面几步: a -- 查看原理图.数据手册,了解设备的操作方 ...

  9. 编写最简单的字符设备驱动

    编写最简单的字符设备驱动 1 编写驱动代码 2 编写makefile 3 编译和加载驱动 4 编写应用程序测试驱动 参考文章: linux驱动开发第1讲:带你编写一个最简单的字符设备驱动 linux驱 ...

最新文章

  1. php图形图像处理技术
  2. 【OpenCV3】cv::compare()使用详解
  3. Java中使用Jedis连接Redis对Set进行操作的常用命令
  4. 一个表单同时向两个页面传值
  5. .NET 3.5 - DLINQ(LINQ to SQL)之面向对象的添加、查询、更新和删除
  6. jelly bean android,Jelly Bean占Android系统份额突破10%
  7. kingbase7获取唯一索引和子分区键的view
  8. mysql存储过程详解以及PHP调用MYSQL存储过程实例
  9. Win10系统优化工具
  10. 用户与计算机的交互界面是什么,终于知道交互界面设计是什么
  11. DOM 详细 一篇就够【重点】
  12. Django DTL 与verbatim
  13. SpringBoot2.0(九):实现微信授权登录并且获取用户信息
  14. android在framework层增加自己的service---仿照GPS
  15. Unity3D 放大缩小图片
  16. Java编程题-买苹果
  17. 整理一份API接口,包括音乐API,图片API,聚合API等等
  18. OpenCV 文字绘制----cv::putText详解
  19. Android 项目必备(四十二)-->Android 多窗口模式
  20. VirtualBox免费虚拟机使用简介、3G无线上网的Virtualbox实现

热门文章

  1. C#下载大文件并实现断点续传
  2. js面试题:创建一个json对象people,并追加属性:姓名、性别、年龄,追加run方法...
  3. 高可用Redis(八):Redis主从复制
  4. mkpasswd命令
  5. 位带操作全解释,个人觉得不错就转过来理解下
  6. 51nod--1212 最小生成树
  7. 我的设计模型之适配器模式
  8. java selenium click_按钮单击selenium java
  9. 03-26 网络流量分析
  10. Given inorder and postorder traversal of a tree, construct the binary tree