字符设备驱动第十九课---platform3

来源:互联网 发布:rsync指定ssh端口 编辑:程序博客网 时间:2024/06/06 13:11

概述

设备信息来自于设备树的platform驱动

范例

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/of.h>#include <linux/of_irq.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/errno.h>#include <asm/current.h>#include <linux/sched.h>#include <linux/uaccess.h>#include <linux/poll.h>#include <asm/atomic.h>#include <linux/mutex.h>#include <linux/wait.h>#include <linux/device.h>static struct class *cls = NULL;static int major = 0;static int minor = 0;const  int count = 1;#define DEVNAME "fskey"static struct cdev *fskeyp = NULL;static unsigned long irqflags;static int irq;static atomic_t tv;#if 0/{    key@26{        compatible = "fs4412,key";        interrupt-parent = <&gpx1>;        interrupts = <2 2>;    };};#endifstatic irqreturn_t handler_t(int irq, void *dev_id){    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);    return IRQ_HANDLED;}//打开设备static int fskey_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 fskey_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   = fskey_open,    .release= fskey_release,};static int fskey_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 objfskey_init    fskeyp = cdev_alloc();    if(NULL == fskeyp){        return -ENOMEM;    }    //2. init cdev obj    cdev_init(fskeyp, &fops);    ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);    if(ret){        goto ERR_STEP;    }    major = MAJOR(devnum);    //3. register cdev obj    ret = cdev_add(fskeyp, 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(fskeyp);    //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 fskey_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(fskeyp);}static int fskey_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 fskey_init();}static int fskey_remove(struct platform_device *pdev){    printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);    fskey_exit();    return 0;}#ifdef CONFIG_OFstruct of_device_id of_tbl[] = {//设备树中设备ID匹配表    {.compatible = "fs4412,key",},    {},//为空表结束符};MODULE_DEVICE_TABLE(of, of_tbl);#endif//1. alloc objstatic struct platform_driver fskeydrv = {    .probe  = fskey_probe,    .remove = fskey_remove,    .driver = {        .name = DEVNAME,#ifdef CONFIG_OF        .of_match_table = of_tbl,//因为用的设备信息不是来自于C代码中,                                 //而是来自于设备树,所以要定义此匹配表#endif    },};//3. register objmodule_platform_driver(fskeydrv);MODULE_LICENSE("GPL");MODULE_AUTHOR("Farsight");MODULE_DESCRIPTION("Demo for kernel module");
0 0
原创粉丝点击