Linux驱动学习(4-字符设备-自动创建字符设备并读写)
来源:互联网 发布:淘宝怎么凑单 编辑:程序博客网 时间:2024/06/04 18:58
上一节我们主要讲解了手动创建字符设备节点并访问,但是感觉太过于麻烦,因此,我们这一节主要讲解如何自动创建字符设备并进行读写操作,以及讲解编写字符设备驱动的框架
不过在此之前,我们先不上代码,先了解一下基本的概念。
1、设备号dev_t
设备号为设备驱动模块程序在Linux系统中唯一识别号。其为32bits的无符号整数, 一个设备号分成主设备号和次设备号两部分:(Linux2.6版本的设备号)
主号12bits 次号20bits
一般情况下主设备号为一种设备类型,次设备号为这类设备的具体一个设备。
MKDEV(ma,mi);将ma主设备号和次设备号合成一个32bit的完整设备号;
MAJOR(dev);从一个设备号中提取出主设备号;
MINOR(dev);从一个设备号中提取次设备号;
2、struct cdev字符设备控制块
字符设备控制块struct cdev是字符设备的核心,内核就是通过对其的挂接和卸载完成字符设备工作。
3、字符设备函数操作集struct file_operations
利用struct file_operations声明实体,然后对相应的函数给出实现体,最后将该实体赋给cdev中ops的成员。
4、代码展示
看了些理论感觉很无聊,我们还是先上点代码吧
模块代码
cdevAPI.c
#include "include/kmodlue.h"//协议声明MODULE_LICENSE("GPL");//声明一个节点名作为模块输入参数//其将在/dev目录下被创建。static char *DeviceNodeName = "ss";module_param(DeviceNodeName, charp, 0600);MODULE_PARM_DESC(DeviceNodeName, "The default value is \"ss\"");dev_t dev; //存放设备号,因该理解为主设备号struct cdev cdev; //字符设备控制块int dsn; //次设备号起始值int acount_of_devices; //声明次设备号数量,即具体设备数量 //To define a pointer of device class 定义一个设备类型指针struct class *D_class; //To define a pointer of device 定义一个设备struct device *D_device; //Show it in(显示在) /proc/devices file#define DeviceName "Chr_dev" //Show it in(显示在) /sys/class/ dir.#define DeviceNameClass "Chr_dev_class"#define MEM_SIZE 20 //声明内核内存空间大小unsigned char *mem_datas; //内核内存空间指针//API的打开程序接口int cdev_open(struct inode *i, struct file *filp){ //将ChrDevp指针赋值给filp->private_data,也就是今后, //函数struct file *参数中的filp->private_data也指向mem_datas所指向的空间。 filp->private_data = mem_datas; printk(KERN_INFO "The device was openned by the AP!\n"); return 0;}//API的关闭程序接口int cdev_close(struct inode *i, struct file *filp){ filp->private_data = NULL; printk(KERN_INFO "The device was closed by the AP!\n"); return 0;}//定义AP程序操作接口struct file_operations cdev_fops = { .owner = THIS_MODULE, .open = cdev_open, .release = cdev_close,};//mount fuction 挂载函数static int __init chr_dev_init(void){ int rst = 0; dsn = 3; acount_of_devices = 1; //动态申请设备号 rst = alloc_chrdev_region(&dev, dsn, acount_of_devices, DeviceName); if(rst < 0) { rst = -1; printk(KERN_INFO "Fail:alloc_chrdev_region()\n"); goto Exit_1; } //To init the cdev blk 初始化字符控制快 cdev_init(&cdev,&cdev_fops); cdev.owner = THIS_MODULE; //添加设备快 rst = cdev_add(&cdev, dev, dsn+1); if(rst < 0) { rst = -2; printk(KERN_INFO "Fail:cdev_add()\n"); goto Exit_2; } //创建设备类型 D_class = class_create(THIS_MODULE, DeviceNameClass); if(IS_ERR(D_class)) { rst = -3; printk(KERN_INFO "Fail:class_create()\n"); goto Exit_3; } //创建设备节点 D_device = device_create(D_class, NULL, dev, NULL, DeviceNodeName); if(IS_ERR(D_device)) { rst = -4; printk(KERN_INFO "Fail:device_create()\n"); goto Exit_4; } //创建内核数据空间 mem_datas = kmalloc(MEM_SIZE, GFP_KERNEL); if(IS_ERR(mem_datas)) { rst = -5; printk(KERN_INFO "Fail:kmalloc() for ChrDevp->mem_datas\n"); goto Exit_5; } //Inited is success! and exit. 初始化成功 //rst = 0; printk(KERN_INFO "The device module was mounted by the kernel!,the device number maj:%d and min: %d\n", MAJOR(dev), MINOR(dev)); goto Exit_1;Exit_5: //销毁设备节点 device_destroy(D_class, dev);Exit_4: //销毁设备类型 class_destroy(D_class);Exit_3: //删除设备块 cdev_del(&cdev);Exit_2: //注销设备号 unregister_chrdev_region(dev, acount_of_devices);Exit_1://程序退出,初始化结束 return rst;}//umount fuction 卸载函数static void __exit chr_dev_exit(void){ //释放内核内存空间 kfree(mem_datas); //销毁设备节点 device_destroy(D_class, dev); //销毁设备类型 class_destroy(D_class); //删除设备块 cdev_del(&cdev); //注销设备号 unregister_chrdev_region(dev, acount_of_devices); printk(KERN_INFO "The device module was umounted by the kernel!\n");}//封装模块挂载函数module_init(chr_dev_init);//封装模块卸载函数module_exit(chr_dev_exit);
应用程序代码
testap.c
#include<stdio.h>#include<stdlib.h>#include <fcntl.h>int main(int c, char **v){ int fp = open("/dev/ss",O_RDWR); if(fp < 0) { printf("Error,device no exists!\n"); return -1; } printf("Openning success!\n"); sleep(3); printf("Closing success!\n"); close(fp); return 0;}
Makefile
include目录里面的文件
include/cmd.h
#ifndef __CMD_H__#define __CMD_H__#define MAGIC 0x34#define OPEN_LED 1#define CLOSE_LED 2#define IO_OPEN_LED _IO(MAGIC, OPEN_LED)#define IO_CLOSE_LED _IO(MAGIC, CLOSE_LED)#endif
include/kmodule.h
#ifndef __KMODULE_H__#define __KMODULE_H__#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/types.h>#include <linux/slab.h>#include <asm/uaccess.h>#endif
由于之前装载、卸载模块已经说明很多次,因此,这里不再进行说明,如果有不明白的地方,请参考以前的教程。
5、函数简要说明
一、动态分配设备号函数:
int alloc_register_region(dev_t *dev, unsigned basemonor, unsigned count, const char *name);
返回值:0表示成功,非0表示失败。
输入参数:
dev,存放获得的设备号,指针方式传入;
baseminor,第一个次设备号,;
count,总共次设备号数量;
name,被分配的设备或驱动名称。
二、创建设备类型目录及相应配置函数:
struct class *class_create(owner, name);
返回值:为struct class指针,可用IS_ERR()函数来判断返回是否成功。
输入参数:
owner ,一般使用THIS_MODULE参数;
name,设备类型名称。
会在/sys/class中创建name参数的目录及一些文件。
三、自动创建设备节点函数:
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, …);
返回值:struct device *指针,可用IS_ERR()函数来判断返回是否成功。
class,为用class_create()得到的指针;
parent,指向父级设备,一般可以为NULL;
devt,设备号;
drvdata,为回调函数,或携带数据,一般为NULL;
fmt,为设备类型名称。
自动会在/dev目录下创建fmt设备节点。
四、删除设备节点函数:
void device_destroy(struct class *class, dev_t devt);
返回参数:空。
输入参数:
class,要删除设备节点所属的设备类型;
devt,要删除的设备号。
五、删除设备类型函数:
void class_destroy(struct class *cls);
返回值:空。
输入参数:
cls,要删除的设备类型。
六、开发字符设备并读写的框架流程
初始化
1、动态申请设备号 alloc_register_region
2、初始化字符设备块 cdev_init
3、向内核添加设备块 cdev_add
4、创建设备类型 class_create
5、创建设备节点 device_create
6、创建内核数据空间 kmalloc
卸载
1、释放内核内存空间 kfree
2、销毁设备节点 device_destroy
3、销毁设备类型 class_destroy
4、注销设备号 unregister_chrdev_region
我们在insmod模块的时候,模块初始化会自动创建设备节点。通过设备节点,应用程序就可以进行正常的数据操作了。read write open close等等
- Linux驱动学习(4-字符设备-自动创建字符设备并读写)
- Linux设备驱动学习(4)-字符设备驱动
- linux驱动开发--字符设备:自动创建设备节点
- linux字符设备驱动中自动创建设备节点
- Linux字符设备驱动自动创建设备节点
- linux字符设备驱动中自动创建设备节点【转】
- linux驱动开发--字符设备:自动创建设备节点
- linux字符设备驱动之设备节点的自动创建
- linux驱动开发之字符设备--自动创建设备节点
- linux字符设备驱动:自动创建设备及其节点
- Linux驱动学习4(字符设备驱动初步学习)
- linux字符设备驱动学习
- Linux字符设备驱动学习
- Linux驱动学习字符设备
- linux学习--字符设备驱动
- LINUX字符设备驱动学习
- Linux 字符设备驱动结构(二)—— 自动创建设备节点
- Linux 字符设备驱动结构(二)—— 自动创建设备节点
- poj 2506 Tiling
- 逻辑斯蒂回归模型
- 做内心强大的女子:不念过往,不惧将来
- Activity启动模式解析
- 《欢乐颂》的引经据典
- Linux驱动学习(4-字符设备-自动创建字符设备并读写)
- iOS-沙盒(二)
- Android上仿IOS弹性ScrollView
- 卡尔曼滤波的原理说明
- android保存图片到本地并可以在相册中显示出来
- 游戏机制对IT员工激励的影响
- Jquery自定义插件
- Github README.md
- 欢迎使用CSDN-markdown编辑器