驱动报告uevent示例

代码功能:
底层向上层报告uevent的功能,例如底层有按键按下或者电池充电状态发生改变,的时候发出uevent事件,应用程序获取这一事件。
细节问题:uevent必须依附一个kobj;底半部最好用工作队列,而不是软中断.

转载 https://blog.csdn.net/Hsu_smile/article/details/51027103?utm_source=blogxgwz7

#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <asm/irq.h>
#include <mach/fp8102_det.h>

int irqnum = 0;
struct uevent_platform_data* uinfo = NULL;
static struct kset *uevent_kset = NULL;
static struct work_struct uevent_wq;

static char charged_str[] = "fully-charged";
static char charging_str[] = "charging";

struct uevent_obj {
    struct kobject kobj;
    int val;
};
struct uevent_obj *uobj;

struct uevent_attribute {
    struct attribute attr;
    ssize_t (*show)(struct uenent_obj *uobj, struct attribute *attr, char *buf);
    ssize_t (*store)(struct uevent_obj *uobj, struct attribute *attr,
            const char *buf, size_t count);
};

static ssize_t uevent_attr_show(struct kobject *kobj,
            struct attribute *attr,
            char *buf)
{
    ssize_t count;
    if (gpio_get_value(uinfo->detect_pin) ^ uinfo->charge_active_low)
        count = sprintf(buf, "%s\n", charging_str);
    else
        count = sprintf(buf, "%s\n", charged_str);
    return  count;
}

static ssize_t uevent_attr_store(struct kobject *kobj,
            struct attribute *attr,
            const char *buf, size_t len)
{
    return 0;
}

static const struct sysfs_ops uevent_sysfs_ops = {
    .show = uevent_attr_show,
    .store = uevent_attr_store,
};

static void uevent_release(struct kobject *kobj)
{
    kfree(uobj);
}

static ssize_t uevent_show(struct uevent_obj *uevent_obj, struct attribute *attr,
            char *buf)
{
    /*do nothing*/
    return  0;
}

static ssize_t uevent_store(struct uvent_obj *uevent_obj, struct attribute *attr,
             const char *buf, size_t count)
{
    /*do nothing*/
    return  0;
}

static struct uevent_attribute fp8102_uevent_attr =
    __ATTR(uevent, 0666, uevent_show, uevent_store);

static struct attribute *uevent_default_attrs[] = {
    &fp8102_uevent_attr.attr,
    NULL,
};

static struct kobj_type uevent_ktype = {
    .sysfs_ops = &uevent_sysfs_ops,
    .release = uevent_release,
    .default_attrs = uevent_default_attrs,
};

static void destroy_uevent_obj(struct uevent_obj *ub)
{
    kobject_put(&ub->kobj);
    kfree(&ub->kobj);
}

void uevent_do_work(struct work_struct *work)
{
    char *msg[] = {NULL, NULL};
    if (gpio_get_value(uinfo->detect_pin) ^ uinfo->charge_active_low)
        msg[0] = charging_str;
    else
        msg[0] = charged_str;

    kobject_uevent_env(&uobj->kobj, KOBJ_CHANGE, msg);
}

static irqreturn_t interrupt_isr(int irq, void *data)
{
    schedule_work(&uevent_wq);
    return IRQ_HANDLED;
}

static int fp8102_det_probe( struct platform_device *pdev)
{
    int ret = 0;
    uinfo = pdev->dev.platform_data;
    if(!uinfo){
        printk("get uevent pdata failed \n");
        return -EINVAL;
    }

    uevent_kset = kset_create_and_add("uevent_report", NULL, kernel_kobj);
    if (!uevent_kset){
        return -ENOMEM;
    }
    uobj = kzalloc(sizeof(*uobj), GFP_KERNEL);
    if (!uobj){
        goto kset_error;
    }

    INIT_WORK(&uevent_wq, uevent_do_work);

    uobj->kobj.kset = uevent_kset;
    ret = kobject_init_and_add(&uobj->kobj, &uevent_ktype, NULL, "%s", "uevent_report");
    if (ret){
        goto uevent_error;
    }

    ret = gpio_request(uinfo->detect_pin, "uevent_report");
    if (ret){
        printk("gpio reuest for uevent report failed\n");
        goto uevent_error;
    }

    irqnum = gpio_to_irq(uinfo->detect_pin);
    if (request_irq(irqnum, interrupt_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "uevent_report", NULL)) {
        printk(KERN_ERR "uevent.c: Can't allocate irq %d\n", irqnum);
        goto gpio_error;
    }

    return 0;

gpio_error:
    gpio_free(uinfo->detect_pin);
uevent_error:
    destroy_uevent_obj(uobj);
kset_error:
    kset_unregister(uevent_kset);
    return -EINVAL;
}

static int fp8102_det_remove(struct platform_device *dev)
{
    destroy_uevent_obj(uobj);
    kset_unregister(uevent_kset);
    free_irq(irqnum, NULL);
    gpio_free(uinfo->detect_pin);
    return 0;
}

static struct platform_driver fp8102_det_driver = {
    .driver = {
        .name = "fp8102_det",
        .owner = THIS_MODULE,
    },
    .probe = fp8102_det_probe,
    .remove = fp8102_det_remove,
};

static int __init fp8102_det_init(void)
{
    return platform_driver_register(&fp8102_det_driver);
}

static void __exit fp8102_det_exit(void)
{
    platform_driver_unregister(&fp8102_det_driver);
}

module_init(fp8102_det_init);
module_exit(fp8102_det_exit);

MODULE_DESCRIPTION("fp8102 charge status report");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Bing");
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值