14 在H5上实现的矩阵键盘驱动

矩阵键盘工作原理参考: http://blog.csdn.net/jklinux/article/details/73649292

实现一个2x2的矩阵键盘驱动, 在设备树里的描述:

    mykeypad  {
        compatible = "mykeypad";
        /* 行线的io口, 以数组的形式列出 */
        row-gpios = <&pio 0  12 GPIO_ACTIVE_HIGH>, <&pio 0 11 GPIO_ACTIVE_HIGH>;

        /* 列线的io口, 以数组的形式列出 */
        col-gpios = <&pio 0  19 GPIO_ACTIVE_HIGH>, <&pio 0 18 GPIO_ACTIVE_HIGH>;

    /* 按键顺序对应的键码 */
    keycodes = <KEY_L, KEY_S, KEY_ENTER, KEY_UP>;
    }; 


驱动源码:

/* mydrv.c */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/input.h>


typedef struct {
    struct gpio_descs *rows; //存放行线io口信息
    struct gpio_descs *cols; //存放列线io口信息

    struct input_dev *idev; 
    int    *keycodes; //存放设备树提供的键码
    int    key_pressed; //记录第几个按钮已按下,用于在松手中断时汇报键松手
}mypdata;


irqreturn_t irq_func(int irqno, void *arg)
{
    mypdata *pdata = (mypdata *)arg;
    int r = -1, i, c = -1;

    //找出哪一行发生中断
    for (i = 0; i < pdata->rows->ndescs; i++)
    {
        if (irqno == gpiod_to_irq(pdata->rows->desc[i]))
        {
            r = i;
            break;
        }
    }
    if (r < 0)
        return IRQ_HANDLED;

    //先把行线的中断暂时关闭
    disable_irq_nosync(irqno);

    if (gpiod_get_value(pdata->rows->desc[r])) //松手
    {
        //如果有记录键已按下,则汇报键松手
        if (pdata->key_pressed >= 0)
        {
            input_report_key(pdata->idev, pdata->keycodes[pdata->key_pressed], 0);
            input_sync(pdata->idev);

            pdata->key_pressed = -1;
        }
        goto out;
    }   
    else
    {
        //轮流让每一个列线输出高电平
        for (i  = 0; i < pdata->cols->ndescs; i++)
        {
            gpiod_set_value(pdata->cols->desc[i], 1);
            if (gpiod_get_value(pdata->rows->desc[r]))
            {
                gpiod_set_value(pdata->cols->desc[i], 0);
                c = i;
                break;
            }
            gpiod_set_value(pdata->cols->desc[i], 0);
        }

        if (c < 0)
            goto out;

        //汇报键按下
        pdata->key_pressed = r*pdata->cols->ndescs+c;
        input_report_key(pdata->idev, pdata->keycodes[pdata->key_pressed], 1);
        input_sync(pdata->idev);
    }

out:
    msleep(100); //防止抖动
    enable_irq(irqno); //恢复行线的中断功能

    return IRQ_HANDLED;
}

int myprobe(struct platform_device *pdev)
{
    mypdata *pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
    int ret = -ENODEV;
    int i;

    //获取列线col-gpios的io口信息 */
    pdata->cols = devm_gpiod_get_array(&pdev->dev, "col", GPIOD_OUT_LOW);
    if (IS_ERR(pdata->cols))
    {
        printk("rows gpio failed\n");
        goto err0;
    }

    //获取行线row-gpios的io口信息 */
    pdata->rows = devm_gpiod_get_array(&pdev->dev, "row", GPIOD_IN);
    if (IS_ERR(pdata->rows))
    {
        printk("cols gpio failed\n");
        goto err1;
    }
    //准备存放键码的空间
    pdata->keycodes = devm_kzalloc(&pdev->dev, sizeof(int)*pdata->rows->ndescs*pdata->cols->ndescs, GFP_KERNEL);

    //获取设备树里的键码信息
    device_property_read_u32_array(&pdev->dev, "keycodes", pdata->keycodes, pdata->rows->ndescs*pdata->cols->ndescs);
    pdata->key_pressed = -1;

     input dev 
    pdata->idev = input_allocate_device();
    pdata->idev->name = pdev->name;

    set_bit(EV_KEY, pdata->idev->evbit);
    set_bit(EV_REP, pdata->idev->evbit);
    for (i = 0; i < pdata->rows->ndescs * pdata->cols->ndescs; i++)
        set_bit(pdata->keycodes[i], pdata->idev->keybit);

    ret = input_register_device(pdata->idev);
    if (ret < 0)
        goto err2;
        

    //请求中断
    for (i  = 0; i < pdata->rows->ndescs; i++)
    {
        ret = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(pdata->rows->desc[i]),
        NULL, irq_func, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING|IRQF_ONESHOT, pdev->name, pdata);
        if (ret < 0)
            goto err3;
    }

    platform_set_drvdata(pdev, pdata);
    printk("in myprobe\n");
    return 0;
err3:
    while (i)
        devm_free_irq(&pdev->dev, gpiod_to_irq(pdata->rows->desc[--i]), pdata);
err2:
    input_unregister_device(pdata->idev);
    devm_kfree(&pdev->dev, pdata->keycodes);    

    devm_gpiod_put_array(&pdev->dev, pdata->rows);
err1:
    devm_gpiod_put_array(&pdev->dev, pdata->cols);
err0:
    return ret;
}

int myremove(struct platform_device *pdev)
{
    mypdata *pdata = platform_get_drvdata(pdev);
    int i;

    input_unregister_device(pdata->idev);
    devm_kfree(&pdev->dev, pdata->keycodes);
    for (i = 0; i < pdata->rows->ndescs; i++)
        devm_free_irq(&pdev->dev, gpiod_to_irq(pdata->rows->desc[i]), pdata);

    devm_gpiod_put_array(&pdev->dev, pdata->rows);
    devm_gpiod_put_array(&pdev->dev, pdata->cols);
    printk("in myremove\n");
    return 0;
}

struct of_device_id ids[] = {
    {.compatible = "mykeypad"},
    {},
};

struct platform_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .driver = {
        .owner = THIS_MODULE,
        .name = "mydrv" ,

        .of_match_table = ids,
    },
};

module_platform_driver(mydrv);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在H5实现点击右上角选择在浏览器打开的功能,可以通过以下步骤实现: 1. 首先,需要获取到点击事件的元素,可以是一个按钮或者其他的可点击元素。可以使用HTML的<a>标签来创建一个链接元素,作为点击事件的触发点,例如:<a id="openBtn">打开链接</a>。 2. 然后,在JavaScript中使用DOM操作获取到这个元素,并给它添加一个点击事件监听器。例如: ```javascript var openBtn = document.getElementById("openBtn"); openBtn.addEventListener("click", openInBrowser); ``` 这里,我们定义了一个名为openInBrowser的函数,作为点击事件的处理器。 3. 在openInBrowser函数内部,使用window.location.href属性获取当前页面的URL,并使用window.open()方法打开一个新的浏览器窗口,这样链接就会在浏览器中打开了。例如: ```javascript function openInBrowser() { var currentURL = window.location.href; window.open(currentURL); } ``` 以上就是实现点击右上角选择在浏览器打开功能的基本步骤。你可以根据实际需求进行相关的修改和扩展,例如可以在点击事件的处理器函数中添加条件判断,根据不同的情况执行不同的操作,或者可以自定义要打开的链接地址等等。 ### 回答2: 在使用H5开发网页时,我们可以通过添加一个按钮,并绑定一个点击事件来实现在浏览器中打开的功能。具体步骤如下: 1. 首先,在网页的HTML代码中添加一个按钮元素,可以使用<button>标签,或其他适合的标签,如<a>标签。 示例代码:<button id="openInBrowser">在浏览器中打开</button> 2. 然后,在JavaScript中为该按钮添加点击事件的侦听器。可以使用addEventListener方法给按钮元素绑定一个"click"事件。 示例代码: var openInBrowserBtn = document.getElementById("openInBrowser"); openInBrowserBtn.addEventListener("click", function() { // 在这里编写打开浏览器的代码 }); 3. 最后,在事件侦听器中编写打开浏览器的功能代码。可以使用window.open()方法来打开新窗口。 示例代码: openInBrowserBtn.addEventListener("click", function() { window.open("http://www.example.com", "_blank"); }); 这样,当用户点击"在浏览器中打开"按钮时,会在新的浏览器标签页或窗口中打开指定的网址(在上面代码示例中为"http://www.example.com")。用户可以选择使用默认浏览器或其他浏览器打开链接。 ### 回答3: H5可以通过使用`<a>`标签的`target="_blank"`属性来实现点击右上角选择在浏览器打开。 具体步骤如下: 1. 在HTML代码中,为需要点击的元素(如按钮、文字等)添加一个`<a>`标签,用于实现链接的功能。 2. 在`<a>`标签中,设置`href`属性,指定要在浏览器中打开的链接地址。 3. 同时,设置`target="_blank"`属性,表示在新的浏览器窗口或标签页中打开链接。 4. 最后,可以根据需要为`<a>`标签添加样式或其他属性,以满足设计需求。 例如,以下是实现点击右上角选择在浏览器打开的示例代码: ```html <a href="https://www.example.com" target="_blank">点击这里在新窗口打开链接</a> ``` 这段代码中,当用户点击"点击这里在新窗口打开链接"的时候,会在新的浏览器窗口或标签页中打开`https://www.example.com`网址。这样就实现了点击右上角选择在浏览器打开的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值