zoukankan      html  css  js  c++  java
  • 树莓派 -- 输入设备驱动 (key)

    输入设备(如按键,键盘,触摸屏等)是典型的字符设备,其一般工作原理是底层在按键或触摸等动作发生时产生一个中断,然后CPU通过SPI,I2C总线读取键值。
    在这些工作中之后中断和读键值是与设备相关的,而输入事件的缓冲区管理,字符设备驱动的file_operations接口则对输入设备是通用的。因此内核设计了输入子系统,由核心层处理公共的工作。

    先看gpio-keys platform_driver驱动代码, 源码
    drivers/input/keyboard/gpio_keys.c

    static int gpio_keys_probe(struct platform_device *pdev)
    {
        struct device *dev = &pdev->dev;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
        struct fwnode_handle *child = NULL;
        struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
        size_t size;
        int i, error;
        int wakeup = 0;
        if (!pdata) {
            pdata = gpio_keys_get_devtree_pdata(dev);
            if (IS_ERR(pdata))
                return PTR_ERR(pdata);
        }
        size = sizeof(struct gpio_keys_drvdata) +
                pdata->nbuttons * sizeof(struct gpio_button_data);
        ddata = devm_kzalloc(dev, size, GFP_KERNEL);
        if (!ddata) {
            dev_err(dev, "failed to allocate state
    ");
            return -ENOMEM;
        }
        ddata->keymap = devm_kcalloc(dev,
                         pdata->nbuttons, sizeof(ddata->keymap[0]),
                         GFP_KERNEL);
        if (!ddata->keymap)
            return -ENOMEM;
        //分配输入设备
        input = devm_input_allocate_device(dev);
        if (!input) {
            dev_err(dev, "failed to allocate input device
    ");
            return -ENOMEM;
        }
        ddata->pdata = pdata;
        ddata->input = input;
        mutex_init(&ddata->disable_lock);
        platform_set_drvdata(pdev, ddata);
        input_set_drvdata(input, ddata);
        input->name = pdata->name ? : pdev->name;
        input->phys = "gpio-keys/input0";
        input->dev.parent = dev;
        input->open = gpio_keys_open;
        input->close = gpio_keys_close;
        input->id.bustype = BUS_HOST;
        input->id.vendor = 0x0001;
        input->id.product = 0x0001;
        input->id.version = 0x0100;
        input->keycode = ddata->keymap;
        input->keycodesize = sizeof(ddata->keymap[0]);
        input->keycodemax = pdata->nbuttons;
        /* Enable auto repeat feature of Linux input subsystem */
        if (pdata->rep)
            __set_bit(EV_REP, input->evbit);
        for (i = 0; i < pdata->nbuttons; i++) {
            const struct gpio_keys_button *button = &pdata->buttons[i];
            if (!dev_get_platdata(dev)) {
                child = device_get_next_child_node(dev, child);
                if (!child) {
                    dev_err(dev,
                        "missing child device node for entry %d
    ",
                        i);
                    return -EINVAL;
                }
            }
            error = gpio_keys_setup_key(pdev, input, ddata,
                            button, i, child);
            if (error) {
                fwnode_handle_put(child);
                return error;
            }
            if (button->wakeup)
                wakeup = 1;
        }
        fwnode_handle_put(child);
        error = devm_device_add_group(dev, &gpio_keys_attr_group);
        if (error) {
            dev_err(dev, "Unable to export keys/switches, error: %d
    ",
                error);
            return error;
        }
        //注册输入设备
        error = input_register_device(input);
        if (error) {
            dev_err(dev, "Unable to register input device, error: %d
    ",
                error);
            return error;
        }
        device_init_wakeup(dev, wakeup);
        return 0;
    }

    key的硬件配置信息由设备树传入。
    我们再看看设备树input的描述
    Documentationdevicetreeindingsinputgpio-keys.txt中给出的例子

    Subnode properties:
    
        - gpios: OF device-tree gpio specification.
        - interrupts: the interrupt line for that input.
        - label: Descriptive name of the key.
        - linux,code: Keycode to emit.
    
    Example nodes:
    
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
    
                up {
                    label = "GPIO Key UP";
                    linux,code = <103>;
                    gpios = <&gpio1 0 1>;
                };
    
                down {
                    label = "GPIO Key DOWN";
                    linux,code = <108>;
                    interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
                };
                ...
    

    打算使用Interrupts的方式。
    首先看一下RaspberryPi 3-b的中断在设备树中的描述
    archarmootdtscm283x.dtsi

    interrupt-parent = <&intc>;
        soc {
            compatible = "simple-bus";
            //...
            intc: interrupt-controller@7e00b200 {
                compatible = "brcm,bcm2835-armctrl-ic";
                reg = <0x7e00b200 0x200>;
                interrupt-controller;
                #interrupt-cells = <2>;
            };
    
            //...
            gpio: gpio@7e200000 {
                compatible = "brcm,bcm2835-gpio";
                reg = <0x7e200000 0xb4>;
                interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
    
                gpio-controller;
                #gpio-cells = <2>;
    
                interrupt-controller;
                #interrupt-cells = <2>;
    
                //...

    archarmootdtscm2837.dtsi

        soc {
            //...
            local_intc: local_intc@40000000 {
                compatible = "brcm,bcm2836-l1-intc";
                reg = <0x40000000 0x100>;
                interrupt-controller;
                #interrupt-cells = <1>;
                interrupt-parent = <&local_intc>;
            };
        };
    /* Make the BCM2835-style global interrupt controller be a child of the
     * CPU-local interrupt controller.
     */
    &intc {
        compatible = "brcm,bcm2836-armctrl-ic";
        reg = <0x7e00b200 0x200>;
        interrupt-parent = <&local_intc>;
        interrupts = <8>;
    };

    archarmootdtscm270x.dtsi

        soc: soc {
            //...
    
            gpio@7e200000 { /* gpio */
                interrupts = <2 17>, <2 18>;
            };

    在archarmootdtscm2708-rpi.dtsi中添加gpio_keys nodes.

        gpio_keys: gpio_keys {
            compatible = "gpio-keys";
        };

    在archarmootdtscm2710-rpi-3-b.dts中添加gpio_keys nodes.

    &gpio_keys {
        pinctrl-names = "default";
    
        key1_key: key1 {
          interrupt-parent = <&gpio>;
          interrupts = <2 20>;
          gpios = <&gpio 20 GPIO_ACTIVE_LOW>;
          linux,code = <100>;
          label = "key1";
          debounce-interval = <10>;
          wakeup-source;
        };
    };

    重新编译设备树

    $ make bcm2709_defconfig
    $ make dtbs

    并将新的设备树copy到SD卡boot下, 启动raspberryPi
    查看platform devices

    pi@raspberrypi:/sys/devices/platform $ cd gpio_keys/
    pi@raspberrypi:/sys/devices/platform/gpio_keys $ ls
    disabled_keys      driver           input  modalias  power      switches
    disabled_switches  driver_override  keys   of_node   subsystem  uevent
    pi@raspberrypi:/sys/devices/platform/gpio_keys $ cd driver
    pi@raspberrypi:/sys/devices/platform/gpio_keys/driver $ ls
    bind  gpio_keys  module  uevent  unbind
    pi@raspberrypi:/sys/devices/platform/gpio_keys/driver $ 
  • 相关阅读:
    基于YIIFRAMEWORK框架开发学习(一)
    Android学习系列(24)App代码规范之使用CheckStyle
    64为操作系统,64位IIS,运行32位应用程序的问题
    IE下设置网页为 首页,收藏
    部分.net 目录
    强大的ldd
    (原创)初试Robotium
    在solaris上安装iperf
    (原创)LoadRunner 中 调用dll
    (原创)学习NotesList(Robotium自带的例子)
  • 原文地址:https://www.cnblogs.com/feiwatson/p/9478209.html
Copyright © 2011-2022 走看看