第一个字符驱动操作及代码分析

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#include <linux/slab.h>
#include <linux/device.h>
 
#define CDEVDEMO_MAJOR 255  /*预设cdevdemo的主设备号*/
 
static int cdevdemo_major = CDEVDEMO_MAJOR;
 
/*设备结构体,此结构体可以封装设备相关的一些信息等
  信号量等也可以封装在此结构中,后续的设备模块一般都
  应该封装一个这样的结构体,但此结构体中必须包含某些
  成员,对于字符设备来说,我们必须包含struct cdev cdev*/
struct cdevdemo_dev    
{
    struct cdev cdev;
};
 
struct cdevdemo_dev *cdevdemo_devp;    /*设备结构体指针*/
 
/*文件打开函数,上层对此设备调用open时会执行*/
int cdevdemo_open(struct inode *inode, struct file *filp)    
{
    printk(KERN_NOTICE "======== cdevdemo_open ");
    return 0;
}
 
/*文件释放,上层对此设备调用close时会执行*/
int cdevdemo_release(struct inode *inode, struct file *filp)    
{
    printk(KERN_NOTICE "======== cdevdemo_release ");    
    return 0;
}
 
/*文件的读操作,上层对此设备调用read时会执行*/
static ssize_t cdevdemo_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
    printk(KERN_NOTICE "======== cdevdemo_read ");    
}
 
/* 文件操作结构体,文中已经讲过这个结构*/
static const struct file_operations cdevdemo_fops =
{
    .owner = THIS_MODULE,
    .open = cdevdemo_open,
    .release = cdevdemo_release,
    .read = cdevdemo_read,
};
 
/*初始化并注册cdev*/
static void cdevdemo_setup_cdev(struct cdevdemo_dev *dev, int index)
{
    printk(KERN_NOTICE "======== cdevdemo_setup_cdev 1");    
    int err, devno = MKDEV(cdevdemo_major, index);
    printk(KERN_NOTICE "======== cdevdemo_setup_cdev 2");
 
    /*初始化一个字符设备,设备所支持的操作在cdevdemo_fops中*/    
    cdev_init(&dev->cdev, &cdevdemo_fops);
    printk(KERN_NOTICE "======== cdevdemo_setup_cdev 3");    
    dev->cdev.owner = THIS_MODULE;
    dev->cdev.ops = &cdevdemo_fops;
    printk(KERN_NOTICE "======== cdevdemo_setup_cdev 4");    
    err = cdev_add(&dev->cdev, devno, 1);
    printk(KERN_NOTICE "======== cdevdemo_setup_cdev 5");
    if(err)
    {
        printk(KERN_NOTICE "Error %d add cdevdemo %d", err, index);    
    }
}
 
int cdevdemo_init(void)
{
    printk(KERN_NOTICE "======== cdevdemo_init ");    
    int ret;
    dev_t devno = MKDEV(cdevdemo_major, 0);
 
    struct class *cdevdemo_class;
    /*申请设备号,如果申请失败采用动态申请方式*/
    if(cdevdemo_major)
    {
        printk(KERN_NOTICE "======== cdevdemo_init 1");
        ret = register_chrdev_region(devno, 1, "cdevdemo");
    }else
    {
        printk(KERN_NOTICE "======== cdevdemo_init 2");
        ret = alloc_chrdev_region(&devno,0,1,"cdevdemo");
        cdevdemo_major = MAJOR(devno);
    }
    if(ret < 0)
    {
        printk(KERN_NOTICE "======== cdevdemo_init 3");
        return ret;
    }
    /*动态申请设备结构体内存*/
    cdevdemo_devp = kmalloc(sizeof(struct cdevdemo_dev), GFP_KERNEL);
    if(!cdevdemo_devp)    /*申请失败*/
    {
        ret = -ENOMEM;
        printk(KERN_NOTICE "Error add cdevdemo");    
        goto fail_malloc;
    }
 
    memset(cdevdemo_devp,0,sizeof(struct cdevdemo_dev));
    printk(KERN_NOTICE "======== cdevdemo_init 3");
    cdevdemo_setup_cdev(cdevdemo_devp, 0);
 
    /*下面两行是创建了一个总线类型,会在/sys/class下生成cdevdemo目录
      这里的还有一个主要作用是执行device_create后会在/dev/下自动生成
      cdevdemo设备节点。而如果不调用此函数,如果想通过设备节点访问设备
      需要手动mknod来创建设备节点后再访问。*/
    cdevdemo_class = class_create(THIS_MODULE, "cdevdemo");
    device_create(cdevdemo_class, NULL, MKDEV(cdevdemo_major, 0), NULL, "cdevdemo");
 
    printk(KERN_NOTICE "======== cdevdemo_init 4");
    return 0;
 
    fail_malloc:
        unregister_chrdev_region(devno,1);
}
 
void cdevdemo_exit(void)    /*模块卸载*/
{
    printk(KERN_NOTICE "End cdevdemo");    
    cdev_del(&cdevdemo_devp->cdev);    /*注销cdev*/
    kfree(cdevdemo_devp);        /*释放设备结构体内存*/
    unregister_chrdev_region(MKDEV(cdevdemo_major,0),1);    //释放设备号
}
 
MODULE_LICENSE("Dual BSD/GPL");
module_param(cdevdemo_major, int, S_IRUGO);
module_init(cdevdemo_init);
module_exit(cdevdemo_exit);

 

cat /proc/devices

查看主设备号

insmod cdevdemo.ko

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值