驱动注册的时候,以结点的形式添加到系统中,可以在系统中去找到结点的所有信息:在open操做方法中有struct inode指针参数
struct inode {
umode_ti_mode;
unsigned shorti_opflags;
uid_ti_uid;
gid_ti_gid;
unsigned inti_flags;
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl*i_acl;
struct posix_acl*i_default_acl;
#endif
const struct inode_operations*i_op;
struct super_block*i_sb;
struct address_space*i_mapping;
#ifdef CONFIG_SECURITY
void*i_security;
#endif
/* Stat data, not accessed from path walking */
unsigned longi_ino;
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_ti_rdev; /* 设备号:获取到主设备号和次设备号 */
struct timespeci_atime;
struct timespeci_mtime;
struct timespeci_ctime;
spinlock_ti_lock;/* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes;
blkcnt_ti_blocks;
loff_ti_size;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_ti_size_seqcount;
#endif
/* Misc */
unsigned longi_state;
struct mutexi_mutex;
unsigned longdirtied_when;/* jiffies of first dirtying */
struct hlist_nodei_hash;
struct list_headi_wb_list;/* backing dev IO list */
struct list_headi_lru;/* inode LRU list */
struct list_headi_sb_list;
union {
struct list_headi_dentry;
struct rcu_headi_rcu;
};
atomic_ti_count;
unsigned inti_blkbits;
u64i_version;
atomic_ti_dio_count;
atomic_ti_writecount;
const struct file_operations*i_fop;/* former ->i_op->default_file_ops */
struct file_lock*i_flock;
struct address_spacei_data;
#ifdef CONFIG_QUOTA
struct dquot*i_dquot[MAXQUOTAS];
#endif
struct list_headi_devices;
union {
struct pipe_inode_info*i_pipe;
struct block_device*i_bdev;
struct cdev*i_cdev;
};
__u32i_generation;
#ifdef CONFIG_FSNOTIFY
__u32i_fsnotify_mask; /* all events this inode cares about */
struct hlist_headi_fsnotify_marks;
#endif
#ifdef CONFIG_IMA
atomic_ti_readcount; /* struct files open RO */
#endif
void*i_private; /* fs or device private pointer */
};
获取设备号
dev_t dev_num = inode_p->i_rdev; /* 当前打开设备的设备号 */
主设备号: MAJOR(dev_num) 一个驱动所管理的一类设备
次设备号: MINOR(dev_num) 一个驱动中管理的的多个设备中,当前访问设备的编号。
依据次设备访问设备文件
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static dev_t dev_num; /* dev_num存储申请成功的设备号 */
static unsigned int count = 4; /* 次设备的数量 */
static struct cdev *cdev_p; /* 字符设备注册结构体指针 */
static struct class * class_p;
static struct device * device_p;
int my_char_driver_open(struct inode *inode_p, struct file *file_p)
{
dev_t my_dev;
my_dev = inode_p->i_rdev;
printk(KERN_INFO "my char driver open <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));
return 0;
}
int my_char_driver_release(struct inode *inode_p, struct file *file_p)
{
dev_t my_dev;
my_dev = inode_p->i_rdev;
printk(KERN_INFO "my char driver release <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));
return 0;
}
const struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_char_driver_open,
.release= my_char_driver_release
};
/* 定义模块加载入口函数 */
static int __init my_char_driver_init(void)
{
int ret = 0;
register_chrdev_region(dev_t from, unsigned count, const char * name)
/* 1. 申请设备号:手动申请(给定主设备号和起始次设备号)/动态申请(返回设备号) */
ret = alloc_chrdev_region(&dev_num, 0, count, "chrdev"); /* 动态申请设备号 */
if (ret != 0) {
goto err0;
}
/* 2. 注册设备到系统中,由系统统一调度管理 */
/* 2.1 申请字符设备注册结构体空间*/
cdev_p = cdev_alloc();
if (cdev_p == NULL) {
ret = - ENOMEM;
goto err1;
}
/* 2.2 初始化字符数设备结构体空间中的操作方法集 */
cdev_init(cdev_p, &fops);
/* 2.3 添加字符设备结构体到系统中,由系统统一调度管理 */
ret = cdev_add(cdev_p, dev_num, count);
if (ret != 0) {
goto err2;
}
/* 3. 创建设备节点(可选:一般都会加上) */
/* 3.1 创建节点对象 */
class_p = class_create(THIS_MODULE, "mychar");
if (IS_ERR(class_p)) {
ret = - ENOMEM;
goto err3;
}
int i;
for (i = 0; i < count; i++) { /* 由于驱动可以管理多个设备文件,需要循环创建设备文件 */
char drv_name[20] = {0};
sprintf(drv_name, "mychar%d",i);
/* 3.2 创建设备节点 */
device_p = device_create(class_p, NULL, MKDEV(MAJOR(dev_num), i), NULL, drv_name);
if (IS_ERR(device_p)) {
ret = - ENOMEM;
goto err4;
}
}
printk(KERN_INFO "my char driver : <major: %d, minor: %d> init success\n", MAJOR(dev_num), MINOR(dev_num));
return 0;
err4:
/* 释放创建成功的设备节点 */
for (i--; i >= 0; i--)
device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
/* 释放设备节点对象 */
class_destroy(class_p);
err3:
err2:
/* 释放字符设备结构体空间 */
cdev_del(cdev_p);
err1:
/* 释放设备号 */
unregister_chrdev_region(dev_num, count);
err0:
return ret;
}
/* 定义模块卸载入口函数 */
static void __exit my_char_driver_exit(void)
{
/* 释放设备节点 */
int i;
for (i = 0; i < count; i++)
device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
/* 释放设备节点对象 */
class_destroy(class_p);
/* 释放字符设备结构体空间 */
cdev_del(cdev_p);
/* 释放设备号 */
unregister_chrdev_region(dev_num, count);
printk(KERN_INFO "my char driver exit success\n");
}
module_init(my_char_driver_init); /* 声明模块加载入口函数 */
module_exit(my_char_driver_exit); /* 声明模块卸载入口函数 */
MODULE_LICENSE("GPL"); /* 许可证明:采用的GPL协议 */
网友评论