字符设备驱动第四课----自动生成设备
2016-12-05 12:45
239 查看
【概述】
前面的时候我们要在应用程序中使用我们自己写的内核模块要做以下步骤:
1.insmod
2.mknod /dev/demo1 c 250 0
3.在运用程序中调用open(“/dev/demo1”,O_RDWR)打开我们自己创建的设备
现在问题来了,难道每次使用设备都要让用户(写运用程序的人)自己去创建设备吗?这显然不好,所以本节课就要解决“在驱动中自动创建设备”这个问题。
【涉及到的内核接口函数】
1.创建一个类
其实质是个目录,将同一类设备(共用同一个驱动程序的设备)归纳到其目录下,目录下是具体的设备。
/* * 功能: 创建一个目录 * 输入参数: owner:THIS_MODULE * name:目录名 * 返回值: 成功:返回对象指针 失败:错误码 */ struct class *class_create(owner, name)
2.创建一个设备:
跟手动敲mknod命令效果一样
<driver/base/core.h> /* * 功能:创建一个设备 * 输入参数:struct class *:所属对象,上一步创建的对象 * struct device *parent:父设备 * dev_t:将要创建的设备 * void *drvdata:驱动传入的一些数据 * const char *fmt:路径 * 返回值:成功:返回所创建的设备 失败:返回错误码 */ struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
3.销毁一个设备:
跟手动敲rmnod命令效果一样
<drivers/base/core.c> /* * 功能: 销毁指定设备 * 输入参数:struct class:所属类的指针 * dev_t:设备号 * 返回值: none */ void device_destroy(struct class *class, dev_t devt)
4.销毁一个类:
<drivers/base/driver.h> /* * 功能: 销毁一个类 * 输入参数:struct class *:类指针 * 返回值:none */ void class_destroy(struct class *cls);
【工程实例】
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/errno.h> #include <asm/current.h> #include <linux/sched.h> #include <linux/device.h> static struct class *cls = NULL; static int major = 0; static int minor = 0; const int count = 6; #define DEVNAME "demo" static struct cdev *demop = NULL; //打开设备 static int demo_open(struct inode *inode, struct file *filp) { //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__); //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); return 0; } //关闭设备 static int demo_release(struct inode *inode, struct file *filp) { //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__); //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); return 0; } //读设备 //ssize_t read(int fd, void *buf, size_t count) static ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *offset) { struct inode *inode = filp->f_path.dentry->d_inode; //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__); //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); return 0; } //写设备 static ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset) { struct inode *inode = filp->f_path.dentry->d_inode; //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__); //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); return 0; } static struct file_operations fops = { .owner = THIS_MODULE, .open = demo_open, .release= demo_release, .read = demo_read, .write = demo_write, }; static int __init demo_init(void) { dev_t devnum; int ret, i; struct device *devp = NULL; //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__); //1. alloc cdev obj demop = cdev_alloc(); if(NULL == demop){ return -ENOMEM; } //2. init cdev obj cdev_init(demop, &fops); ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME); if(ret){ goto ERR_STEP; } major = MAJOR(devnum); //3. register cdev obj ret = cdev_add(demop, devnum, count); if(ret){ goto ERR_STEP1; } cls = class_create(THIS_MODULE, DEVNAME); if(IS_ERR(cls)){ ret = PTR_ERR(cls); goto ERR_STEP1; } for(i = minor; i < (count+minor); i++){ devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i); if(IS_ERR(devp)){ ret = PTR_ERR(devp); goto ERR_STEP2; } } //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n", current->comm, current->pid, __FILE__, __func__, __LINE__); return 0; ERR_STEP2: for(--i; i >= minor; i--){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); ERR_STEP1: unregister_chrdev_region(devnum, count); ERR_STEP: cdev_del(demop); //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n", current->comm, current->pid, __FILE__, __func__, __LINE__); return ret; } static void __exit demo_exit(void) { int i; //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n", current->comm, current->pid, __FILE__, __func__, __LINE__); for(i=minor; i < (count+minor); i++){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); unregister_chrdev_region(MKDEV(major, minor), count); cdev_del(demop); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Farsight"); MODULE_DESCRIPTION("Demo for kernel module");
相关文章推荐
- (6)2.4之前的字符驱动-用devfs_register自动生成设备文件(可能在2.6linux目录树下编译不了)
- 简单字符设备驱动和自动创建设备文件
- Linux字符驱动中动态分配设备号与动态生成设备节点
- linux字符设备驱动中自动创建设备节点
- Linux驱动学习(4-字符设备-自动创建字符设备并读写)
- linux字符驱动之自动创建设备节点
- linux字符设备驱动 自动创建设备节点的的方法
- linux字符设备驱动总结之:全自动创建设备及节点
- linux字符设备驱动总结之:全自动创建设备及节点
- Linux字符驱动中动态分配设备号与动态生成设备节点
- linux字符驱动之自动创建设备节点
- Linux字符驱动中动态分配设备号与动态生成设备节点
- TQ2440 LINUX 2.6.30.4 LED驱动感言,从最初的打印字符,到自动分配设备号,到自动创建设备节点,到次设备号分控led
- Linux字符驱动中动态分配设备号与动态生成设备节点
- 高级字符设备驱动-自动创建设备文件笔记
- Linux字符驱动中动态分配设备号与动态生成设备节点
- Linux字符驱动中动态分配设备号与动态生成设备节点
- linux字符设备驱动总结之:全自动创建设备及节点 .
- Linux 字符设备驱动结构(二)—— 自动创建设备节点
- Linux字符驱动中动态分配设备号与动态生成设备节点