Linux Platform驱动模型(三) _platform+cdev

平台总线是一种实现设备信息与驱动方法相分离的方法,利用这种方法,我们可以写出一个更像样一点的字符设备驱动,即使用cdev作为接口,平台总线作为分离方式:

xjkeydrv_init():模块加载函数
└──platform_driver_register()将驱动对象模块注册到平台总线
        └──platform_driver.probe()探测函数,提取相应的信息
                └──xjkey_init():初始化cdev对象,创建设备文件等关于cdev接口创建的工作
                        └──cdev_init():将cdev结构与fops绑定到一起,在fops实现操作接口与控制硬件的逻辑

static struct class *cls = NULL;

static int major = 0;
static int minor = 0;
const  int count = 1;

#define DEVNAME "xjkey"

static struct cdev *xjkeyp = NULL;

static unsigned long irqflags;
static int irq;

static atomic_t tv;

#if 0
/{
    key@26{
        compatible = "xj4412,key";
        interrupt-parent = <&gpx1>;
        interrupts = <2 2>;
    };
};
#endif

static irqreturn_t handler_t(int irq, void *dev_id)
{
    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);
    return IRQ_HANDLED;
}

//打开设备
static int xjkey_open(struct inode *inode, struct file *filp)
{
    //get major and minor from inode
    printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
        imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

    if(!atomic_dec_and_test(&tv)){
        atomic_inc(&tv);
        return -EBUSY;
    }

    return request_irq(irq, handler_t, irqflags, DEVNAME, NULL);
}

//关闭设备
static int xjkey_release(struct inode *inode, struct file *filp)
{
    //get major and minor from irqflagsinode
    printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
        imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

    free_irq(irq, NULL);

    atomic_inc(&tv);
    return 0;
}

static struct file_operations fops = {
    .owner  = THIS_MODULE,
    .open   = xjkey_open,
    .release= xjkey_release,
};

static int xjkey_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 objxjkey_init
    xjkeyp = cdev_alloc();
    if(NULL == xjkeyp){
        return -ENOMEM;
    }

    //2. init cdev obj
    cdev_init(xjkeyp, &fops);

    ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
    if(ret){
        goto ERR_STEP;
    }
    major = MAJOR(devnum);

    //3. register cdev obj
    ret = cdev_add(xjkeyp, 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;
        }
    }

    // init atomic_t
    atomic_set(&tv, 1);

    //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(xjkeyp);

    //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 xjkey_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(xjkeyp);
}

static int xjkey_probe(struct platform_device *pdev)
{
    struct resource *irq_res;
    irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if(irq_res){
        irq = irq_res->start;
        irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
    }else{
        printk(KERN_INFO "No 0 irq\n");
        return -EINVAL;     
    }

    return xjkey_init();
}

static int xjkey_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);
    xjkey_exit();
    return 0;
}

struct of_device_id of_tbl[] = {
    {.compatible = "xj4412,key",},
    {},
};
MODULE_DEVICE_TABLE(of, of_tbl);


//1. alloc obj
static struct platform_driver xjkeydrv = {
    .probe  = xjkey_probe,
    .remove = xjkey_remove,

    .driver = {
        .name = DEVNAME,
        .of_match_table = of_tbl,
    },
};

//3. register obj
module_platform_driver(xjkeydrv);

MODULE_LICENSE("GPL");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值