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 $ 
  • 相关阅读:
    101. Symmetric Tree(js)
    100. Same Tree(js)
    99. Recover Binary Search Tree(js)
    98. Validate Binary Search Tree(js)
    97. Interleaving String(js)
    96. Unique Binary Search Trees(js)
    95. Unique Binary Search Trees II(js)
    94. Binary Tree Inorder Traversal(js)
    93. Restore IP Addresses(js)
    92. Reverse Linked List II(js)
  • 原文地址:https://www.cnblogs.com/feiwatson/p/9478209.html
Copyright © 2011-2022 走看看