Linux内核API cdev_init

函数cdev_init()用于初始化一个静态分配的cdev结构体变量,函数cdev_init会自动初始化cdev->ops对象,将函数的第二个输入参数赋值给cdev->ops对象,不会初始化cdev->owner对象,因此在经过函数cdev_alloc()和函数cdev_init()处理之后的cdev结构体变量,在应用程序中只需要给cdev->owner对象赋值,此结构变量就可以被插入Linux内核系统了,作为一个可用的字符设备使用。

cdev_init文件包含

#include <linux/cdev.h>

cdev_init函数定义

在内核源码中的位置:linux-3.19.3/fs/char_dev.c

函数定义格式:

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

cdev_init输入参数说明

函数cdev_init()输入两个参数,第一个参数表示一个字符设备,在函数中即将被初始化,此结构体在函数cdev_alloc()分析文档中已说明,详细信息请读者参考极客笔记函数cdev_alloc()分析文档的返回参数说明部分。

第二个输入参数是struct file_operations结构体类型的指针,通过这个结构体中提供的函数完成对设备的操作,其定义见文件linux-3.19.3/include/linux/fs.h,如下所示:

struct file_operations
{
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iterate) (struct file *, struct dir_context *);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    void (*mremap)(struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, loff_t, loff_t, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long,unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t,unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t,unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **, void **);
    long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
    void (*show_fdinfo)(struct seq_file *m, struct file *f);
};

对于一个设备驱动并不需要完成所有函数的映射,可以有选择地进行使用,下面对最常用的几项进行说明:

struct module *owner;

这个域是用来设置指向“拥有”该结构的模块指针,内核使用该指针维护模块的使用计数。

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

read域用来从设备中读数据,需要提供字符串指针。从设备中读取数据时,成功返回所读取的字节数,read等于NULL时,将导致调用失败,并返回-EINVAL。

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

write域用来向字符设备写数据,需要提供所写指针内容。当向设备写入数据时,成功返回实际写入的字节数,write等于NULL时,将导致调用失败,并返回-EINVAL。

int (*open) (struct inode *, struct file *);

open域用来打开设备,并初始化设备,准备进行操作。如果该方法没有实现,系统调用open也会是成功的,但驱动程序得不到任何打开设备的通知。在实现中,可以给出一定的提示信息。

int (*release) (struct inode *, struct file *);

release域用来关闭设备,释放设备资源。当且仅当结构struct file释放时被调用,用来关闭一个文件或设备。

cdev_init返回参数说明

  • 函数cdev_init()的返回值是void类型的变量,即不返回任何值。

cdev_init实例解析

编写测试文件:cdev_init.c

头文件引用、全局变量定义及相关函数声明:

/*头文件引用*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>

MODULE_LICENSE("GPL");
struct cdev *mem_cdev;            //字符设备对象指针
static int mem_open(struct inode *ind, struct file *filp);     //设备打开函数声明
static int mem_release(struct inode *ind, struct file *filp); //设备关闭函数声明

/*设备读函数声明*/
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *fpos);

/*设备写函数声明*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size,loff_t *fpos);
/*定义设备驱动文件结构体*/
struct file_operations mem_fops =
{
    .open = mem_open,              //设备打开函数
    .release = mem_release,        //设备打开函数
    .read = mem_read,              //设备读函数
    .write = mem_write,            //设备写函数
};

模块加载函数定义:

static int __init cdev_init_init (void)
{
    printk("into the cdev_init_init\n");
    mem_cdev = cdev_alloc();    //动态分配一个新的字符设备对象
    if (mem_cdev == NULL)      //检查分配结果
    {
        printk("cdev_alloc failed! \n");
        return -1;
    }

    /*显示字符设备内存空间地址*/
    printk("cdev_alloc success! addr = 0x%x\n", (unsigned int)mem_cdev); if(mem_cdev->ops==NULL)                                 //函数调用之前判断字段ops是否被初始化
    {
        printk("the ops the mem_cdev has not been initialized\n");
    }
    else
    {
        printk("the ops the mem_cdev has been initialized\n");
    }
    cdev_init(mem_cdev, &mem_fops);       //初始化字符设备对象
    if(mem_cdev->ops==NULL)               //函数调用之后判断字段ops是否被初始化
    {
        printk("the ops the mem_cdev has not been initialized\n");
    }
    else
    {
        printk("the ops the mem_cdev has been initialized\n");
    }
    printk("out the cdev_init_init\n");
    return 0;
}

模块退出函数定义:

static void __exit cdev_init_exit (void)
{
    printk("into cdev_init_exit\n");
    if (mem_cdev ! = NULL)
        kfree(mem_cdev);                   //释放字符设备内存空间
    printk("kfree mem_cdev OK! \n");
    printk("out cdev_init_exit\n");
}

相关函数定义:

/*设备打开函数定义*/
int mem_open(struct inode *ind, struct file *filp)
{
    printk("open vmalloc space\n");
    try_module_get(THIS_MODULE);         //模块引用自加
    printk("open vmalloc space success\n");
    return 0;
}

/*设备读函数定义,在此没有实际意义,只是为了初始化mem_fops变量*/
ssize_t mem_read(struct file *filp, char *buf, size_t size, loff_t *lofp)
{
    printk("copy data to the user space\n");
    return 0;
}

/*设备写函数定义,在此没有实际意义,只是为了初始化mem_fops变量*/
ssize_t mem_write(struct file *filp, const char *buf, size_t size, loff_t *lofp)
{
    printk("read data from the user space\n");
    return 0;
}
/*设备关闭函数定义*/
int mem_release(struct inode *ind, struct file *filp)
{
    printk("close vmalloc space\n");
    module_put(THIS_MODULE);              //模块引用自减
    printk("close vmalloc space success\n");
    return 0;
}

模块加载、退出函数调用:

module_init(cdev_init_init);              //模块加载函数调用
module_exit(cdev_init_exit);              //模块卸载函数调用

实例运行结果及分析

首先编译模块,执行命令insmod cdev_init.ko插入内核模块,然后输入命令dmesg -c查看模块插入结果,会出现如图所示的结果。

Linux内核API cdev_init

结果分析:

由图中可以看出函数cdev_init()调用之前字符设备的字段ops没有被初始化,函数调用之后字段ops被初始化了。

赞(0)
未经允许不得转载:极客笔记 » Linux内核API cdev_init

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
Linux内核API 模块机制
Linux内核API 模块机制Linux内核API __module_addressLinux内核API __module_text_addressLinux内核API __print_symbolLinux内核API __symbol_getLinux内核API __symbol_putLinux内核API find_moduleLinux内核API find_symbolLinux内核API module_is_liveLinux内核API module_putLinux内核API module_refcountLinux内核API sprint_symbolLinux内核API symbol_put_addrLinux内核API try_module_get
Linux内核API 进程管理
Linux内核API 进程管理Linux内核API __task_pid_nr_nsLinux内核API find_get_pidLinux内核API find_pid_nsLinux内核API find_vpidLinux内核API get_pidLinux内核API get_task_mmLinux内核API mmputLinux内核API ns_of_pidLinux内核API pid_nrLinux内核API pid_taskLinux内核API pid_vnrLinux内核API put_pidLinux内核API task_active_pid_nsLinux内核API task_tgid_nr_ns
Linux内核API 进程调度
Linux内核API 进程调度Linux内核API __wake_upLinux内核API __wake_up_syncLinux内核API __wake_up_sync_keyLinux内核API abort_exclusive_waitLinux内核API add_wait_queueLinux内核API add_wait_queue_exclusiveLinux内核API autoremove_wake_functionLinux内核API completeLinux内核API complete_allLinux内核API completion_doneLinux内核API current_thread_infoLinux内核API default_wake_functionLinux内核API do_exitLinux内核API finish_waitLinux内核API init_waitqueue_entryLinux内核API init_waitqueue_headLinux内核API kthread_create_on_nodeLinux内核API kthread_stopLinux内核API prepare_to_waitLinux内核API prepare_to_wait_exclusiveLinux内核API remove_wait_queueLinux内核API sched_setschedulerLinux内核API set_cpus_allowed_ptrLinux内核API set_user_niceLinux内核API task_niceLinux内核API try_wait_for_completionLinux内核API wait_for_completionLinux内核API wait_for_completion_interruptible_timeoutLinux内核API wait_for_completion_killableLinux内核API wait_for_completion_timeoutLinux内核API wake_up_processLinux内核API yield
Linux内核API 中断机制
Linux内核API 中断机制Linux内核API __tasklet_hi_scheduleLinux内核API __tasklet_scheduleLinux内核API disable_irqLinux内核API disable_irq_nosyncLinux内核API disable_irq_wakeLinux内核API enable_irqLinux内核API enable_irq_wakeLinux内核API free_irqLinux内核API irq_set_chipLinux内核API irq_set_chip_dataLinux内核API irq_set_irq_typeLinux内核API irq_set_irq_wakeLinux内核API remove_irqLinux内核API request_irqLinux内核API request_threaded_irqLinux内核API setup_irqLinux内核API tasklet_disableLinux内核API tasklet_disable_nosyncLinux内核API tasklet_enableLinux内核API tasklet_hi_scheduleLinux内核API tasklet_initLinux内核API tasklet_killLinux内核API tasklet_scheduleLinux内核API tasklet_trylockLinux内核API tasklet_unlock
Linux内核API 内存管理
Linux内核API 内存管理Linux内核API __free_pagesLinux内核API __get_free_pagesLinux内核API __get_vm_areaLinux内核API __kreallocLinux内核API alloc_pagesLinux内核API alloc_pages_exactLinux内核API find_vmaLinux内核API find_vma_intersectionLinux内核API free_pagesLinux内核API free_pages_exactLinux内核API get_unmapped_areaLinux内核API get_zeroed_pageLinux内核API kcallocLinux内核API kfreeLinux内核API kmallocLinux内核API kmem_cache_allocLinux内核API kmem_cache_createLinux内核API kmem_cache_destroyLinux内核API kmem_cache_freeLinux内核API kmem_cache_zallocLinux内核API kmemdupLinux内核API ksizeLinux内核API kstrdupLinux内核API kstrndupLinux内核API kzallocLinux内核API memdup_userLinux内核API mempool_allocLinux内核API mempool_alloc_pagesLinux内核API mempool_alloc_slabLinux内核API mempool_createLinux内核API mempool_destroyLinux内核API mempool_freeLinux内核API mempool_free_pagesLinux内核API mempool_free_slabLinux内核API mempool_kfreeLinux内核API mempool_kmallocLinux内核API mempool_resizeLinux内核API nr_free_buffer_pagesLinux内核API page_addressLinux内核API page_cache_getLinux内核API page_cache_releaseLinux内核API page_zoneLinux内核API probe_kernel_addressLinux内核API probe_kernel_readLinux内核API vfreeLinux内核API vma_pagesLinux内核API vmallocLinux内核API vmalloc_to_pageLinux内核API vmalloc_to_pfnLinux内核API vmalloc_user
Linux内核API 定时机制
Linux内核API 定时机制Linux内核API __round_jiffiesLinux内核API __round_jiffies_relativeLinux内核API __round_jiffies_upLinux内核API __round_jiffies_up_relativeLinux内核API add_timerLinux内核API current_kernel_timeLinux内核API del_timerLinux内核API del_timer_syncLinux内核API do_gettimeofdayLinux内核API do_settimeofdayLinux内核API get_secondsLinux内核API getnstimeofdayLinux内核API init_timerLinux内核API init_timer_deferrableLinux内核API init_timer_keyLinux内核API init_timer_on_stackLinux内核API init_timer_on_stack_keyLinux内核API mktimeLinux内核API mod_timerLinux内核API mod_timer_pendingLinux内核API ns_to_timespecLinux内核API ns_to_timevalLinux内核API round_jiffiesLinux内核API round_jiffies_relativeLinux内核API round_jiffies_upLinux内核API round_jiffies_up_relativeLinux内核API set_normalized_timespecLinux内核API setup_timerLinux内核API setup_timer_on_stackLinux内核API timer_pendingLinux内核API timespec_add_nsLinux内核API timespec_compareLinux内核API timespec_equalLinux内核API timespec_subLinux内核API timespec_to_nsLinux内核API timeval_compareLinux内核API timeval_to_nsLinux内核API try_to_del_timer_sync
Linux内核API 同步机制
Linux内核API 同步机制Linux内核API atomic_addLinux内核API atomic_add_negativeLinux内核API atomic_add_returnLinux内核API atomic_add_unlessLinux内核API atomic_cmpxchgLinux内核API atomic_decLinux内核API atomic_dec_and_testLinux内核API atomic_incLinux内核API atomic_inc_and_testLinux内核API atomic_readLinux内核API atomic_setLinux内核API atomic_subLinux内核API atomic_sub_and_testLinux内核API atomic_sub_returnLinux内核API downLinux内核API down_interruptibleLinux内核API down_killableLinux内核API down_readLinux内核API down_read_trylockLinux内核API down_timeoutLinux内核API down_trylockLinux内核API down_writeLinux内核API down_write_trylockLinux内核API downgrade_writeLinux内核API init_rwsemLinux内核API read_seqbeginLinux内核API read_seqretryLinux内核API sema_initLinux内核API seqlock_initLinux内核API upLinux内核API up_readLinux内核API up_writeLinux内核API write_seqlockLinux内核API write_sequnlock
Linux内核API 文件系统
Linux内核API 文件系统Linux内核API __mnt_is_readonlyLinux内核API current_umaskLinux内核API d_allocLinux内核API d_find_aliasLinux内核API dputLinux内核API fgetLinux内核API generic_fillattrLinux内核API get_fs_typeLinux内核API get_max_filesLinux内核API get_superLinux内核API have_submountsLinux内核API I_BDEVLinux内核API inode_add_bytesLinux内核API inode_get_bytesLinux内核API inode_set_bytesLinux内核API inode_sub_bytesLinux内核API is_bad_inodeLinux内核API make_bad_inodeLinux内核API may_umountLinux内核API may_umount_treeLinux内核API mnt_want_writeLinux内核API notify_changeLinux内核API put_unused_fdLinux内核API unshare_fs_structLinux内核API vfs_fstatLinux内核API vfs_getattrLinux内核API vfs_statfs
Linux内核API 设备管理
Linux内核API 设备管理Linux内核API __class_createLinux内核API __class_registerLinux内核API cdev_addLinux内核API cdev_allocLinux内核API cdev_delLinux内核API cdev_initLinux内核API class_createLinux内核API class_destroyLinux内核API class_registerLinux内核API class_unregisterLinux内核API device_addLinux内核API device_createLinux内核API device_delLinux内核API device_destroyLinux内核API device_initializeLinux内核API device_registerLinux内核API device_renameLinux内核API device_unregisterLinux内核API get_deviceLinux内核API put_deviceLinux内核API register_chrdevLinux内核API unregister_chrdev