Android 驱动-点灯

本文详细介绍了如何使用设备树在Android驱动中配置LED,包括通过设备树属性设置GPIO和通过引脚控制LED的方法。提供了完整的代码示例,展示了设备树节点的定义,以及在驱动中解析和操作这些配置的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 驱动-点灯

通过设备树属性

1. 设备树

&leds_test_node
{
    compatible = "leds_test";
    status = "disable";
    // 添加属性 of_get_name_gpio(node, "gpios1", 0)
    gpios1 = <&gpl2 0 GPIO_ACTIVE_HIGH>;
    gpios2 = <&gpk1 1 GPIO_ACTIVE_HIGH>;
}

2. 解析设备树

int gpio_pin[2] = {-1, -1};

static int leds_probe(struct platform_device *pdev)
{
    int ret;
    struct pinctl *pinctl;
    struct device *dev = &pdev->dev;

    pinctl = devm_pinctl_get_select_default(dev);

    // gpio编号
    gpio_pin[0] = of_get_name_gpio(node, "gpios1", 0);
    gpio_pin[1] = of_get_name_gpio(node, "gpios2", 0);

    // 申请
    ret = gpio_request(gpio_pin[0], "led1");
    if (ret != 0)
    {
        printk("gpio request failed\n");
        return ret;
    }

    ret = gpio_request(gpio_pin[1], "led2");
    if (ret != 0)
    {
        printk("gpio request failed\n");
        return ret;
    }

    gpio_free(gpio_pin[0]);
    gpio_free(gpio_pin[1]);

    gpio_direction_output(gpio_pin[0], 0);
    gpio_set_value(gpio_pin[0], 1);

    gpio_direction_output(gpio_pin[1], 0);
    gpio_set_value(gpio_pin[1], 1);
    return 0;
}

通过设备树引脚

1. 设备树

&leds_test_node
{
    status = "okay";
    pinctrl - names = "itop-leds1-on", "itop-leds1-off";
    pinctrl - 0 = <&leds_gpios1_on>;
    pinctrl - 1 = <&leds_gpios1_off>;
};

2. 解析设备树

static int leds_probe(struct platform_device *pdev)
{
    int ret;
    struct pinctl *pinctl;
    struct pinctl_state *state;
    struct device *dev = &pdev->dev;

    pinctl = devm_pinctl_get();
    if (IS_ERR(pinctl))
    {
        printk("%d\n", PTR_ERR(pinctl));
    }

    state = pinctl_lookup_state(pinctl, "itop-leds1-on");
    if (IS_ERR(state))
    {
        printk("%d\n", PTR_ERR(state));
    }

    ret = pinctl_select_state(pinctl, state);
    if (ret < 0)
    {
    }

    // 释放句柄
    devm_pinctl_put(pinctl);

    // pinctl = devm_pinctl_get_select_default(&pdev->dev);
    return 0;
}

完整代码

#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/pinctl/consumer.h>

#define DEVICE_NAME "leds_test"

int gpio_pin[2] = {-1, -1};

int leds_open(struct inode *inode, struct file *filp)
{
    printk("open\n");
    return nonseekable_open(inode, filp);
}

int leds_release(struct inode *inode, struct file *silp)
{
    printk("close\n");
    return 0;
}

long leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    printk("ioctl\n");
    switch (cmd)
    {
    case 0:
    case 1:
        gpio_set_value(gpio_pin[arg], cmd);
        break;
    default:
        return -1;
    }
    return 0;
}

static struct file_operations leds_ops = {
    .owner = THIS_MODULE,
    .open = leds_open,
    .release = leds_release,
    .unlocked_ioctl = leds_ioctl,
};

// static struct miscdevice leds_dev = {
//     .minor = MISC_DYNAMIC_MINOR,
//     .fops = &leds_ops,
//     .name = DRIVER_NAME,
// };

static int leds_probe(struct platform_device *pdev)
{
    // struct device_node *node = pdev->dev.of_node;
    int ret;
    struct pinctl *pinctl;
    struct pinctl_state *state;
    printk("probe\n");

    struct device *dev = &pdev->dev;
    pinctl = devm_pinctl_get();
    if (IS_ERR(pinctl))
    {
        printk("%d\n", PTR_ERR(pinctl));
    }

    state = pinctl_lookup_state(pinctl, "itop-leds1-on");
    if (IS_ERR(state))
    {
        printk("%d\n", PTR_ERR(state));
    }

    ret = pinctl_select_state(pinctl, state);
    if (ret < 0)
    {
    }

    // 释放句柄
    devm_pinctl_put(pinctl);

    // pinctl = devm_pinctl_get_select_default(&pdev->dev);

    // // gpio编号
    // gpio_pin[0] = of_get_name_gpio(node, "gpios1", 0);
    // gpio_pin[1] = of_get_name_gpio(node, "gpios2", 0);

    // // 申请
    // ret = gpio_request(gpio_pin[0], "led1");
    // if (ret != 0)
    // {
    //     printk("gpio request failed\n");
    //     return ret;
    // }

    // ret = gpio_request(gpio_pin[1], "led2");
    // if (ret != 0)
    // {
    //     printk("gpio request failed\n");
    //     return ret;
    // }

    // gpio_free(gpio_pin[0]);
    // gpio_free(gpio_pin[1]);

    // gpio_direction_output(gpio_pin[0], 0);
    // gpio_set_value(gpio_pin[0], 1);

    // gpio_direction_output(gpio_pin[1], 0);
    // gpio_set_value(gpio_pin[1], 1);

    // 杂项设备注冊
    // ret = misc_register(&leds_dev);
    // if (ret < 0)
    // {
    //     printk("register error\n");
    //     goto exit;
    // }

    printk("probe ok\n");
    return 0;
    // exit:
    //     misc_deregister(&leds_dev);
    //     return ret;
}

static int leds_remove(struct platform_device *pdev)
{
    // misc_deregister(&leds_dev);
    return 0;
}

// 平台设备驱动
static struct of_device_id of_my_match[] = {
    {.compatible = "myled"},
    {}};

static struct platform_device my_platform_device = {
    .remove = leds_release,
    .probe = leds_probe,
    .driver = {
        .name = "myled",
        .owner = THIS_MODULE,
        .of_match_table = of_my_match,
    },
};

static int __init led_module_init(void)
{
    printk("%s\n", __FUNCTION__)
        platform_device_register(&my_platform_device);
    return 0;
}

static void __exit led_module_cleanup(void)
{
    platform_device_unregister(&my_platform_device);
}

subys_initcall(led_module_init);
module_init(led_module_init);
module_exit(led_module_cleanup);
MODULE_LICENSE("GPL");

备注


作者 [@lhgcs]
2020 年 07月 28日

### 实现点灯功能的JNI层设计 在Android平台中,通过JNI(Java Native Interface)可以实现在C/C++层面操作硬件资源的功能。对于LED的操作而言,`LightImpl` 类继承自 `Light` 并实现了具体的方法用于控制LED的状态变化[^1]。 当涉及到实际的底层交互时,则依赖于JNI提供的机制来桥接Java与原生代码之间的通信。这通常始于 `JNI_OnLoad()` 函数,在此函数内部初始化阶段获取到了指向当前线程环境(`JNIEnv`) 的指针之后就可以执行进一步的动作了,比如利用 `FindClass` 来定位目标类并建立相应的关联映射表以便后续调用[^2]。 为了完成具体的点亮动作,还需要考虑到底层驱动的支持情况。如果采用的是Linux内核中的GPIO接口作为基础支持的话,那么可以在设备树源(DTS) 文件或者其它适当位置指定好对应的配置参数以确保能够正确识别和管理所连接的LED设备[^3]。 下面给出一段简化版的例子展示如何编写这样的JNI接口: ```c #include <jni.h> #include <hardware/lights.h> // 假设这是由DTS定义好的节点名称 #define LED_NAME "my_led" extern int set_gpio_value(int gpio, int value); JNIEXPORT void JNICALL Java_com_example_LightImpl_setLight_native(JNIEnv *env, jobject obj, jint brightness) { // 这里的逻辑应该依据实际情况调整,例如读取特定属性获得GPIO编号等 const char* node_path = "/sys/class/leds/" LED_NAME; FILE* fp = fopen(node_path, "r+"); if (!fp) { __android_log_print(ANDROID_LOG_ERROR, "LIGHT", "Failed to open led device"); return; } fprintf(fp, "%d\n", brightness); fclose(fp); } ``` 这段代码展示了怎样创建一个名为 `setLight_native` 的本地方法,它接收来自高层应用传递下来的亮度值并通过写入系统文件的方式改变LED状态。需要注意的是这里假设已经存在了一个有效的路径可以直接访问到LED控制器;而在真实环境中可能需要更复杂的处理流程才能达到同样的效果。 #### 注册本地方法 为了让上述实现生效,还需修改或新增一份包含如下内容的 C 文件用来注册这些本地方法给 JVM 使用: ```c static JNINativeMethod gMethods[] = { {"setLight_native", "(I)V", (void*)Java_com_example_LightImpl_setLight_native}, }; jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK || !env) { return -1; } jclass clazz = (*env)->FindClass(env, "com/example/LightImpl"); if (clazz && (*env)->RegisterNatives(env, clazz, gMethods, sizeof(gMethods)/sizeof(JNINativeMethod)) >= 0){ return JNI_VERSION_1_6; } else { return -1; } } ``` 以上就是关于如何基于JNI技术栈开发针对Android系统的简单LED控制程序的大致思路和技术要点介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值