采用创建input的方式

可以通过 cat /proc/bus/input/devices 查看生成的input设备对应的event句柄,比如

I: Bus=0019 Vendor=0001 Product=0001 Version=0100

N: Name="gpio-keys"

P: Phys=gpio-keys/input0

S: Sysfs=/devices/platform/gpio-keys/input/input5

U: Uniq=

H: Handlers=kbd event5

B: PROP=0

B: EV=3

B: KEY=18

可以知道,创建的gpio-keys设备对应 event5

/*

* Driver for keys on GPIO lines capable of generating interrupts.

*

* Copyright 2005 Phil Blundell

* Copyright 2010, 2011 David Jander <david@protonic.nl>

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation.

*/

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/interrupt.h>

#include <linux/irq.h>

#include <linux/sched.h>

#include <linux/pm.h>

#include <linux/slab.h>

#include <linux/sysctl.h>

#include <linux/proc_fs.h>

#include <linux/delay.h>

#include <linux/platform_device.h>

#include <linux/input.h>

#include <linux/gpio_keys.h>

#include <linux/workqueue.h>

#include <linux/gpio.h>

#include <linux/of_platform.h>

#include <linux/of_gpio.h>

#include <linux/spinlock.h>

///add by zjf 2017.11.30

#include <linux/sys_config.h>

struct gpio_button_data {

const struct gpio_keys_button *button;

struct input_dev *input;

struct timer_list timer;

struct work_struct work;

unsigned int timer_debounce; /* in msecs */

unsigned int irq;

spinlock_t lock;

bool disabled;

bool key_pressed;

};

struct gpio_keys_drvdata {

const struct gpio_keys_platform_data *pdata;

struct input_dev *input;

struct mutex disable_lock;

struct gpio_button_data data[0];

};

/*

* SYSFS interface for enabling/disabling keys and switches:

*

* There are 4 attributes under /sys/devices/platform/gpio-keys/

* keys [ro]              - bitmap of keys (EV_KEY) which can be

*                          disabled

* switches [ro]          - bitmap of switches (EV_SW) which can be

*                          disabled

* disabled_keys [rw]     - bitmap of keys currently disabled

* disabled_switches [rw] - bitmap of switches currently disabled

*

* Userland can change these values and hence disable event generation

* for each key (or switch). Disabling a key means its interrupt line

* is disabled.

*

* For example, if we have following switches set up as gpio-keys:

* SW_DOCK = 5

* SW_CAMERA_LENS_COVER = 9

* SW_KEYPAD_SLIDE = 10

* SW_FRONT_PROXIMITY = 11

* This is read from switches:

* 11-9,5

* Next we want to disable proximity (11) and dock (5), we write:

* 11,5

* to file disabled_switches. Now proximity and dock IRQs are disabled.

* This can be verified by reading the file disabled_switches:

* 11,5

* If we now want to enable proximity (11) switch we write:

* 5

* to disabled_switches.

*

* We can disable only those keys which don't allow sharing the irq.

*/

/**

* get_n_events_by_type() - returns maximum number of events per @type

* @type: type of button (%EV_KEY, %EV_SW)

*

* Return value of this function can be used to allocate bitmap

* large enough to hold all bits for given type.

*/

static inline int get_n_events_by_type(int type)

{

BUG_ON(type != EV_SW && type != EV_KEY);

return (type == EV_KEY) ? KEY_CNT : SW_CNT;

}

/**

* gpio_keys_disable_button() - disables given GPIO button

* @bdata: button data for button to be disabled

*

* Disables button pointed by @bdata. This is done by masking

* IRQ line. After this function is called, button won't generate

* input events anymore. Note that one can only disable buttons

* that don't share IRQs.

*

* Make sure that @bdata->disable_lock is locked when entering

* this function to avoid races when concurrent threads are

* disabling buttons at the same time.

*/

static void gpio_keys_disable_button(struct gpio_button_data *bdata)

{

if (!bdata->disabled) {

/*

* Disable IRQ and possible debouncing timer.

*/

disable_irq(bdata->irq);

if (bdata->timer_debounce)

del_timer_sync(&bdata->timer);

bdata->disabled = true;

}

}

/**

* gpio_keys_enable_button() - enables given GPIO button

* @bdata: button data for button to be disabled

*

* Enables given button pointed by @bdata.

*

* Make sure that @bdata->disable_lock is locked when entering

* this function to avoid races with concurrent threads trying

* to enable the same button at the same time.

*/

static void gpio_keys_enable_button(struct gpio_button_data *bdata)

{

if (bdata->disabled) {

enable_irq(bdata->irq);

bdata->disabled = false;

}

}

/**

* gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons

* @ddata: pointer to drvdata

* @buf: buffer where stringified bitmap is written

* @type: button type (%EV_KEY, %EV_SW)

* @only_disabled: does caller want only those buttons that are

*                 currently disabled or all buttons that can be

*                 disabled

*

* This function writes buttons that can be disabled to @buf. If

* @only_disabled is true, then @buf contains only those buttons

* that are currently disabled. Returns 0 on success or negative

* errno on failure.

*/

static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,

char *buf, unsigned int type,

bool only_disabled)

{

int n_events = get_n_events_by_type(type);

unsigned long *bits;

ssize_t ret;

int i;

bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);

if (!bits)

return -ENOMEM;

for (i = 0; i < ddata->pdata->nbuttons; i++) {

struct gpio_button_data *bdata = &ddata->data[i];

if (bdata->button->type != type)

continue;

if (only_disabled && !bdata->disabled)

continue;

__set_bit(bdata->button->code, bits);

}

ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);

buf[ret++] = '\n';

buf[ret] = '\0';

kfree(bits);

return ret;

}

/**

* gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap

* @ddata: pointer to drvdata

* @buf: buffer from userspace that contains stringified bitmap

* @type: button type (%EV_KEY, %EV_SW)

*

* This function parses stringified bitmap from @buf and disables/enables

* GPIO buttons accordingly. Returns 0 on success and negative error

* on failure.

*/

static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,

const char *buf, unsigned int type)

{

int n_events = get_n_events_by_type(type);

unsigned long *bits;

ssize_t error;

int i;

bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);

if (!bits)

return -ENOMEM;

error = bitmap_parselist(buf, bits, n_events);

if (error)

goto out;

/* First validate */

for (i = 0; i < ddata->pdata->nbuttons; i++) {

struct gpio_button_data *bdata = &ddata->data[i];

if (bdata->button->type != type)

continue;

if (test_bit(bdata->button->code, bits) &&

!bdata->button->can_disable) {

error = -EINVAL;

goto out;

}

}

mutex_lock(&ddata->disable_lock);

for (i = 0; i < ddata->pdata->nbuttons; i++) {

struct gpio_button_data *bdata = &ddata->data[i];

if (bdata->button->type != type)

continue;

if (test_bit(bdata->button->code, bits))

gpio_keys_disable_button(bdata);

else

gpio_keys_enable_button(bdata);

}

mutex_unlock(&ddata->disable_lock);

out:

kfree(bits);

return error;

}

#define ATTR_SHOW_FN(name, type, only_disabled) \

static ssize_t gpio_keys_show_##name(struct device *dev, \

struct device_attribute *attr, \

char *buf) \

{ \

struct platform_device *pdev = to_platform_device(dev); \

struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \

\

return gpio_keys_attr_show_helper(ddata, buf, \

type, only_disabled); \

}

ATTR_SHOW_FN(keys, EV_KEY, false);

ATTR_SHOW_FN(switches, EV_SW, false);

ATTR_SHOW_FN(disabled_keys, EV_KEY, true);

ATTR_SHOW_FN(disabled_switches, EV_SW, true);

/*

* ATTRIBUTES:

*

* /sys/devices/platform/gpio-keys/keys [ro]

* /sys/devices/platform/gpio-keys/switches [ro]

*/

static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);

static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);

#define ATTR_STORE_FN(name, type) \

static ssize_t gpio_keys_store_##name(struct device *dev, \

struct device_attribute *attr, \

const char *buf, \

size_t count) \

{ \

struct platform_device *pdev = to_platform_device(dev); \

struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \

ssize_t error; \

\

error = gpio_keys_attr_store_helper(ddata, buf, type); \

if (error) \

return error; \

\

return count; \

}

ATTR_STORE_FN(disabled_keys, EV_KEY);

ATTR_STORE_FN(disabled_switches, EV_SW);

/*

* ATTRIBUTES:

*

* /sys/devices/platform/gpio-keys/disabled_keys [rw]

* /sys/devices/platform/gpio-keys/disables_switches [rw]

*/

static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,

gpio_keys_show_disabled_keys,

gpio_keys_store_disabled_keys);

static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,

gpio_keys_show_disabled_switches,

gpio_keys_store_disabled_switches);

static struct attribute *gpio_keys_attrs[] = {

&dev_attr_keys.attr,

&dev_attr_switches.attr,

&dev_attr_disabled_keys.attr,

&dev_attr_disabled_switches.attr,

NULL,

};

static struct attribute_group gpio_keys_attr_group = {

.attrs = gpio_keys_attrs,

};

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)

{

const struct gpio_keys_button *button = bdata->button;

struct input_dev *input = bdata->input;

unsigned int type = button->type ?: EV_KEY;

int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;

if (type == EV_ABS) {

if (state)

input_event(input, type, button->code, button->value);

} else {

input_event(input, type, button->code, !!state);

}

input_sync(input);

}

static void gpio_keys_gpio_work_func(struct work_struct *work)

{

struct gpio_button_data *bdata =

container_of(work, struct gpio_button_data, work);

gpio_keys_gpio_report_event(bdata);

if (bdata->button->wakeup)

pm_relax(bdata->input->dev.parent);

}

static void gpio_keys_gpio_timer(unsigned long _data)

{

struct gpio_button_data *bdata = (struct gpio_button_data *)_data;

schedule_work(&bdata->work);

}

static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)

{

struct gpio_button_data *bdata = dev_id;

BUG_ON(irq != bdata->irq);

if (bdata->button->wakeup)

pm_stay_awake(bdata->input->dev.parent);

if (bdata->timer_debounce)

mod_timer(&bdata->timer,

jiffies + msecs_to_jiffies(bdata->timer_debounce));

else

schedule_work(&bdata->work);

return IRQ_HANDLED;

}

static void gpio_keys_irq_timer(unsigned long _data)

{

struct gpio_button_data *bdata = (struct gpio_button_data *)_data;

struct input_dev *input = bdata->input;

unsigned long flags;

spin_lock_irqsave(&bdata->lock, flags);

if (bdata->key_pressed) {

input_event(input, EV_KEY, bdata->button->code, 0);

input_sync(input);

bdata->key_pressed = false;

}

spin_unlock_irqrestore(&bdata->lock, flags);

}

static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)

{

struct gpio_button_data *bdata = dev_id;

const struct gpio_keys_button *button = bdata->button;

struct input_dev *input = bdata->input;

unsigned long flags;

BUG_ON(irq != bdata->irq);

spin_lock_irqsave(&bdata->lock, flags);

if (!bdata->key_pressed) {

if (bdata->button->wakeup)

pm_wakeup_event(bdata->input->dev.parent, 0);

input_event(input, EV_KEY, button->code, 1);

input_sync(input);

if (!bdata->timer_debounce) {

input_event(input, EV_KEY, button->code, 0);

input_sync(input);

goto out;

}

bdata->key_pressed = true;

}

if (bdata->timer_debounce)

mod_timer(&bdata->timer,

jiffies + msecs_to_jiffies(bdata->timer_debounce));

out:

spin_unlock_irqrestore(&bdata->lock, flags);

return IRQ_HANDLED;

}

static int gpio_keys_setup_key(struct platform_device *pdev,

struct input_dev *input,

struct gpio_button_data *bdata,

const struct gpio_keys_button *button)

{

const char *desc = button->desc ? button->desc : "gpio_keys";

struct device *dev = &pdev->dev;

irq_handler_t isr;

unsigned long irqflags;

int irq, error;

bdata->input = input;

bdata->button = button;

spin_lock_init(&bdata->lock);

if (gpio_is_valid(button->gpio)) {

error = gpio_request_one(button->gpio, GPIOF_IN, desc);

if (error < 0) {

dev_err(dev, "Failed to request GPIO %d, error %d\n",

button->gpio, error);

return error;

}

if (button->debounce_interval) {

error = gpio_set_debounce(button->gpio,

button->debounce_interval * 1000);

/* use timer if gpiolib doesn't provide debounce */

if (error < 0)

bdata->timer_debounce =

button->debounce_interval;

}

irq = gpio_to_irq(button->gpio);

if (irq < 0) {

error = irq;

dev_err(dev,

"Unable to get irq number for GPIO %d, error %d\n",

button->gpio, error);

goto fail;

}

bdata->irq = irq;

INIT_WORK(&bdata->work, gpio_keys_gpio_work_func);

setup_timer(&bdata->timer,

gpio_keys_gpio_timer, (unsigned long)bdata);

isr = gpio_keys_gpio_isr;

irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;

} else {

if (!button->irq) {

dev_err(dev, "No IRQ specified\n");

return -EINVAL;

}

bdata->irq = button->irq;

if (button->type && button->type != EV_KEY) {

dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");

return -EINVAL;

}

bdata->timer_debounce = button->debounce_interval;

setup_timer(&bdata->timer,

gpio_keys_irq_timer, (unsigned long)bdata);

isr = gpio_keys_irq_isr;

irqflags = 0;

}

input_set_capability(input, button->type ?: EV_KEY, button->code);

/*

* If platform has specified that the button can be disabled,

* we don't want it to share the interrupt line.

*/

if (!button->can_disable)

irqflags |= IRQF_SHARED;

error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);

if (error < 0) {

dev_err(dev, "Unable to claim irq %d; error %d\n",

bdata->irq, error);

goto fail;

}

return 0;

fail:

if (gpio_is_valid(button->gpio))

gpio_free(button->gpio);

return error;

}

static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)

{

struct input_dev *input = ddata->input;

int i;

for (i = 0; i < ddata->pdata->nbuttons; i++) {

struct gpio_button_data *bdata = &ddata->data[i];

if (gpio_is_valid(bdata->button->gpio))

gpio_keys_gpio_report_event(bdata);

}

input_sync(input);

}

static int gpio_keys_open(struct input_dev *input)

{

struct gpio_keys_drvdata *ddata = input_get_drvdata(input);

const struct gpio_keys_platform_data *pdata = ddata->pdata;

int error;

if (pdata->enable) {

error = pdata->enable(input->dev.parent);

if (error)

return error;

}

/* Report current state of buttons that are connected to GPIOs */

gpio_keys_report_state(ddata);

return 0;

}

static void gpio_keys_close(struct input_dev *input)

{

struct gpio_keys_drvdata *ddata = input_get_drvdata(input);

const struct gpio_keys_platform_data *pdata = ddata->pdata;

if (pdata->disable)

pdata->disable(input->dev.parent);

}

/*

* Handlers for alternative sources of platform_data

*/

#ifdef CONFIG_OF

/*

* Translate OpenFirmware node properties into platform_data

*/

static struct gpio_keys_platform_data *

gpio_keys_get_devtree_pdata(struct device *dev)

{

struct device_node *node, *pp;

struct gpio_keys_platform_data *pdata;

struct gpio_keys_button *button;

int error;

int nbuttons;

int i;

node = dev->of_node;

if (!node) {

error = -ENODEV;

goto err_out;

}

nbuttons = of_get_child_count(node);

if (nbuttons == 0) {

error = -ENODEV;

goto err_out;

}

pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),

GFP_KERNEL);

if (!pdata) {

error = -ENOMEM;

goto err_out;

}

pdata->buttons = (struct gpio_keys_button *)(pdata + 1);

pdata->nbuttons = nbuttons;

pdata->rep = !!of_get_property(node, "autorepeat", NULL);

i = 0;

for_each_child_of_node(node, pp) {

int gpio;

enum of_gpio_flags flags;

if (!of_find_property(pp, "gpios", NULL)) {

pdata->nbuttons--;

dev_warn(dev, "Found button without gpios\n");

continue;

}

gpio = of_get_gpio_flags(pp, 0, &flags);

if (gpio < 0) {

error = gpio;

if (error != -EPROBE_DEFER)

dev_err(dev,

"Failed to get gpio flags, error: %d\n",

error);

goto err_free_pdata;

}

button = &pdata->buttons[i++];

button->gpio = gpio;

button->active_low = flags & OF_GPIO_ACTIVE_LOW;

if (of_property_read_u32(pp, "linux,code", &button->code)) {

dev_err(dev, "Button without keycode: 0x%x\n",

button->gpio);

error = -EINVAL;

goto err_free_pdata;

}

button->desc = of_get_property(pp, "label", NULL);

if (of_property_read_u32(pp, "linux,input-type", &button->type))

button->type = EV_KEY;

button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);

if (of_property_read_u32(pp, "debounce-interval",

&button->debounce_interval))

button->debounce_interval = 5;

}

if (pdata->nbuttons == 0) {

error = -EINVAL;

goto err_free_pdata;

}

return pdata;

err_free_pdata:

kfree(pdata);

err_out:

return ERR_PTR(error);

}

static struct of_device_id gpio_keys_of_match[] = {

{ .compatible = "gpio-keys", },

{ },

};

MODULE_DEVICE_TABLE(of, gpio_keys_of_match);

#else

static inline struct gpio_keys_platform_data *

gpio_keys_get_devtree_pdata(struct device *dev)

{

return ERR_PTR(-ENODEV);

}

#endif

static void gpio_remove_key(struct gpio_button_data *bdata)

{

free_irq(bdata->irq, bdata);

if (bdata->timer_debounce)

del_timer_sync(&bdata->timer);

cancel_work_sync(&bdata->work);

if (gpio_is_valid(bdata->button->gpio))

gpio_free(bdata->button->gpio);

}

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 gpio_keys_drvdata *ddata;

struct input_dev *input;

int i, error;

int wakeup = 0;

msleep(5);

if (!pdata) {

pdata = gpio_keys_get_devtree_pdata(dev);

if (IS_ERR(pdata))

return PTR_ERR(pdata);

}

ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +

pdata->nbuttons * sizeof(struct gpio_button_data),

GFP_KERNEL);

input = input_allocate_device();

if (!ddata || !input) {

dev_err(dev, "failed to allocate state\n");

error = -ENOMEM;

goto fail1;

}

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 = &pdev->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;

/* 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];

struct gpio_button_data *bdata = &ddata->data[i];

error = gpio_keys_setup_key(pdev, input, bdata, button);

if (error)

goto fail2;

if (button->wakeup)

wakeup = 1;

}

error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);

if (error) {

dev_err(dev, "Unable to export keys/switches, error: %d\n",

error);

goto fail2;

}

error = input_register_device(input);

if (error) {

dev_err(dev, "Unable to register input device, error: %d\n",

error);

goto fail3;

}

device_init_wakeup(&pdev->dev, wakeup);

return 0;

fail3:

sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);

fail2:

while (--i >= 0)

gpio_remove_key(&ddata->data[i]);

platform_set_drvdata(pdev, NULL);

fail1:

input_free_device(input);

kfree(ddata);

/* If we have no platform data, we allocated pdata dynamically. */

if (!dev_get_platdata(&pdev->dev))

kfree(pdata);

return error;

}

static int gpio_keys_remove(struct platform_device *pdev)

{

struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);

struct input_dev *input = ddata->input;

int i;

sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);

device_init_wakeup(&pdev->dev, 0);

for (i = 0; i < ddata->pdata->nbuttons; i++)

gpio_remove_key(&ddata->data[i]);

input_unregister_device(input);

/* If we have no platform data, we allocated pdata dynamically. */

if (!dev_get_platdata(&pdev->dev))

kfree(ddata->pdata);

kfree(ddata);

return 0;

}

#ifdef CONFIG_PM_SLEEP

static int gpio_keys_suspend(struct device *dev)

{

struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);

struct input_dev *input = ddata->input;

int i;

if (device_may_wakeup(dev)) {

for (i = 0; i < ddata->pdata->nbuttons; i++) {

struct gpio_button_data *bdata = &ddata->data[i];

if (bdata->button->wakeup)

enable_irq_wake(bdata->irq);

}

} else {

mutex_lock(&input->mutex);

if (input->users)

gpio_keys_close(input);

mutex_unlock(&input->mutex);

}

return 0;

}

static int gpio_keys_resume(struct device *dev)

{

struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);

struct input_dev *input = ddata->input;

int error = 0;

int i;

if (device_may_wakeup(dev)) {

for (i = 0; i < ddata->pdata->nbuttons; i++) {

struct gpio_button_data *bdata = &ddata->data[i];

if (bdata->button->wakeup)

disable_irq_wake(bdata->irq);

}

} else {

mutex_lock(&input->mutex);

if (input->users)

error = gpio_keys_open(input);

mutex_unlock(&input->mutex);

}

if (error)

return error;

gpio_keys_report_state(ddata);

return 0;

}

#endif

///add by zjf 2017.11.29

static struct gpio_keys_button sc_buttons[]= {

{

.gpio   = GPIOH(5),   /* K1 */

.code   = 3,

.desc   = "KEY1",

.active_low = 1,

},

{

.gpio   = GPIOH(6),   /* K2 */

.code   = 4,

.desc   = "KEY2",

.active_low = 1,

},

};

static struct gpio_keys_platform_data sc_button_data = {

.buttons    = sc_buttons,

.nbuttons   =ARRAY_SIZE(sc_buttons),

};

static struct platform_device sc_button_device= {

.name   = "gpio-keys",   /* ??platform driver????×????à?? */

.id = -1,

.dev    = {

.platform_data  =&sc_button_data,

}

};

//static struct platform_device*mini2440_devices[] __initdata = {

//         ????

//   &sc_button_device,

//};

///end

static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);

static struct platform_driver gpio_keys_device_driver = {

.probe = gpio_keys_probe,

.remove = gpio_keys_remove,

.driver = {

.name = "gpio-keys",

.owner = THIS_MODULE,

.pm = &gpio_keys_pm_ops,

.of_match_table = of_match_ptr(gpio_keys_of_match),

}

};

static int __init gpio_keys_init(void)

{

printk("...............\n");

printk("...............\n");

printk("...............\n");

printk("gpio keys init\n");

printk("...............\n");

printk("...............\n");

printk("...............\n");

if (platform_device_register(&sc_button_device)) {

printk("%s: register gpio device failed\n", __func__);

}

if (platform_driver_register(&gpio_keys_device_driver)) {

printk("%s: register gpio driver failed\n", __func__);

}

return 0;

}

static void __exit gpio_keys_exit(void)

{

platform_driver_unregister(&gpio_keys_device_driver);

platform_device_unregister(&sc_button_device);

}

late_initcall(gpio_keys_init);

module_exit(gpio_keys_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");

MODULE_DESCRIPTION("Keyboard driver for GPIOs");

MODULE_ALIAS("platform:gpio-keys");

应用层的使用:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <sys/types.h>

#include <fcntl.h>

#include <errno.h>

#include <time.h>

#include <linux/input.h>

struct input_event event;

#define RELAY_IOCTL_SET_OPEN        1

#define RELAY_IOCTL_SET_CLOSE       0

#define RELAY_1                     52

#define RELAY_2                     53

int relayfd;

void relay_gpio_ctrl (int on_off, int relay_num)

{

if(on_off == 0)

{

printf("LED_IOCTL_SET_OFF\n");

ioctl(relayfd, RELAY_IOCTL_SET_CLOSE, relay_num);

}

else

{

printf("LED_IOCTL_SET_On\n");

ioctl(relayfd, RELAY_IOCTL_SET_OPEN, relay_num);

}

}

int main(int argc, char **argv)

{

char          name[64];           /* RATS: Use ok, but could be better */

char          buf[256] = { 0, };  /* RATS: Use ok */

unsigned char mask[EV_MAX/8 + 1]; /* RATS: Use ok */

int           version;

int           fd = 0;

int           rc;

int           i, j;

char          *tmp;

#define test_bit(bit) (mask[(bit)/8] & (1 << ((bit)%8)))

for (i = 0; i < 32; i++) {

sprintf(name, "/dev/input/event%d", i);

if ((fd = open(name, O_RDONLY, 0)) >= 0) {

ioctl(fd, EVIOCGVERSION, &version);

ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);

ioctl(fd, EVIOCGBIT(0, sizeof(mask)), mask);

printf("%s\n", name);

printf("    evdev version: %d.%d.%d\n",

version >> 16, (version >> 8) & 0xff, version & 0xff);

printf("    name: %s\n", buf);

printf("    features:");

for (j = 0; j < EV_MAX; j++) {

if (test_bit(j)) {

const char *type = "unknown";

switch(j) {

case EV_KEY: type = "keys/buttons"; break;

case EV_REL: type = "relative";     break;

case EV_ABS: type = "absolute";     break;

case EV_MSC: type = "reserved";     break;

case EV_LED: type = "leds";         break;

case EV_SND: type = "sound";        break;

case EV_REP: type = "repeat";       break;

case EV_FF:  type = "feedback";     break;

}

printf(" %s", type);

}

}

printf("\n");

close(fd);

}

}

relayfd = open("/dev/led", O_SYNC | O_RDWR);

if(relayfd == -1)

{

printf("/dev/led can not open");

return -1;

}

if (argc > 1) {

sprintf(name, "/dev/input/event%d", atoi(argv[1]));

if ((fd = open(name, O_RDWR, 0)) >= 0) {

printf("%s: open, fd = %d\n", name, fd);

for (i = 0; i < LED_MAX; i++) {

event.time.tv_sec  = time(0);

event.time.tv_usec = 0;

event.type         = EV_LED;

event.code         = i;

event.value        = 0;

write(fd, &event, sizeof(event));

}

while ((rc = read(fd, &event, sizeof(event))) > 0) {

printf("%-24.24s.%06lu type 0x%04x; code 0x%04x;"

" value 0x%08x; ",

ctime(&event.time.tv_sec),

event.time.tv_usec,

event.type, event.code, event.value);

switch (event.type) {

case EV_KEY:

if (event.code > BTN_MISC) {

printf("Button %d %s",

event.code & 0xff,

event.value ? "press" : "release");

} else {

printf("Key %d (0x%x) %s",

event.code & 0xff,

event.code & 0xff,

event.value ? "press" : "release");

if(event.code == 3)

{

relay_gpio_ctrl(event.value, RELAY_1);

}

else if(event.code == 4)

{

relay_gpio_ctrl(event.value, RELAY_2);

}

}

break;

case EV_REL:

switch (event.code) {

case REL_X:      tmp = "X";       break;

case REL_Y:      tmp = "Y";       break;

case REL_HWHEEL: tmp = "HWHEEL";  break;

case REL_DIAL:   tmp = "DIAL";    break;

case REL_WHEEL:  tmp = "WHEEL";   break;

case REL_MISC:   tmp = "MISC";    break;

default:         tmp = "UNKNOWN"; break;

}

printf("Relative %s %d", tmp, event.value);

break;

case EV_ABS:

switch (event.code) {

case ABS_X:        tmp = "X";        break;

case ABS_Y:        tmp = "Y";        break;

case ABS_Z:        tmp = "Z";        break;

case ABS_RX:       tmp = "RX";       break;

case ABS_RY:       tmp = "RY";       break;

case ABS_RZ:       tmp = "RZ";       break;

case ABS_THROTTLE: tmp = "THROTTLE"; break;

case ABS_RUDDER:   tmp = "RUDDER";   break;

case ABS_WHEEL:    tmp = "WHEEL";    break;

case ABS_GAS:      tmp = "GAS";      break;

case ABS_BRAKE:    tmp = "BRAKE";    break;

case ABS_HAT0X:    tmp = "HAT0X";    break;

case ABS_HAT0Y:    tmp = "HAT0Y";    break;

case ABS_HAT1X:    tmp = "HAT1X";    break;

case ABS_HAT1Y:    tmp = "HAT1Y";    break;

case ABS_HAT2X:    tmp = "HAT2X";    break;

case ABS_HAT2Y:    tmp = "HAT2Y";    break;

case ABS_HAT3X:    tmp = "HAT3X";    break;

case ABS_HAT3Y:    tmp = "HAT3Y";    break;

case ABS_PRESSURE: tmp = "PRESSURE"; break;

case ABS_DISTANCE: tmp = "DISTANCE"; break;

case ABS_TILT_X:   tmp = "TILT_X";   break;

case ABS_TILT_Y:   tmp = "TILT_Y";   break;

case ABS_MISC:     tmp = "MISC";     break;

default:           tmp = "UNKNOWN";  break;

}

printf("Absolute %s %d", tmp, event.value);

break;

case EV_MSC: printf("Misc"); break;

case EV_LED: printf("Led");  break;

case EV_SND: printf("Snd");  break;

case EV_REP: printf("Rep");  break;

case EV_FF:  printf("FF");   break;

break;

}

printf("\n");

}

printf("rc = %d, (%s)\n", rc, strerror(errno));

close(fd);

}

}

close(relayfd);

return 0;

}

R40使用GPIO中断实现按键功能【原创】相关推荐

  1. 乐鑫Esp32学习之旅⑦ esp32上利用GPIO中断做一个按键的短按和长按的回调事件,再也无须担心触发源。(附带Demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. 爬坑学习新旅程,虚拟机搭建esp32开发环境,打印 " ...

  2. LPC1768外部中断与GPIO中断

    LPC1768的外部中断严格来说只有四个,分别是EINT0,EINT1,EINT2,EINT3,技术手册上有如下说明 控制这四个外部中断靠以下寄存器 这三个寄存器的0 1 2 3位分别代表中断的0 1 ...

  3. unbalanced enable irq 问题的解决 以及共享的gpio中断引起的问题

    点击打开链接 最近在工作中使用irq时遇到如下问题,根据log显示应该是什么所谓的不平横问题,先前也没有仔细研究这个问题,只是定位到是enable_irq函数调用所致. 因为在项目中使用的中断是gpi ...

  4. Omap3530 的GPIO中断设置

    Omap3530 的GPIO中断设置: 1.配置成GPIO,申请GPIO中断 omap_cfg_reg(OMAP3_KBD_GPIO);配置成gpio if (gpio_request(OMAP3_K ...

  5. OpenWrt 之 MT7628 使用GPIO中断

    在支持设备树的系统中使用中断一般有2种方式. 一.DTS配置interrupt节点 这里有个挺好的博客,链接地址:https://biscuitos.github.io/blog/DTS-interr ...

  6. 树莓派移植SX1278 LoRa通信--使用wiringPi 移植GPIO中断

    一.SX1278 数字接口状态映射 从官方文档可知sx1278的数字接口状态映射明细,移植的代码中主要用查询的方式来判断在连续模式下是否接收和发送完成,因此只需要用到DIO0.如果要用到CAD,则需要 ...

  7. 将5350 i2c clk设置为gpio 中断模式的方法

    5350和我之前用的三星和全志的芯片在中断这块有点差别,三星和全志的都是有专门的外部中断管脚,并且每个中断管脚对应一个中断号,对管脚寄存器的配置即irq_desc里chip变量,都是bsp里自带的,我 ...

  8. IMX6ULL学习笔记(18)——GPIO中断

    一.中断简介 相比 STM32 的 NVIC,IMX6ULL 的中断控制系统更复杂,它的中断管理器使用的是 GIC V2,GIC V2 的实现方式与我们熟知的 NVIC 差别较大. 1.1 GIC G ...

  9. xilinx zynq 7010/7020 中断/中断向量/GIC向量/GPIO中断

    上图所示GIC左边的称为中断请求源,它们产生中断请求.所有的中断请求都可以发送到GIC通用中断控制器,所以它是一个集中式的中断请求中心.GIC根据请求源的属性(enables, disables, m ...

最新文章

  1. 图灵直播 | 25年后我们怎样评价JavaScript?
  2. MySql 隐式转换
  3. 怎么用cmb运行c语言文档,关于化学质量平衡(CMB)受体模型应用中若干技术问题的研究-环境科学专业论文.docx...
  4. PEOPEO中国区总经理于景:当我谈交互设计时我谈些什么
  5. php arcode svg,在react中使用svg的各种方法总结(附代码)
  6. 信息学奥赛一本通 1179:奖学金 | 1938:【07NOIP普及组】奖学金 | OpenJudge NOI 1.10 04 | 洛谷 P1093 [NOIP2007 普及组] 奖学金
  7. Maven - 快速创建Java工程和Web工程
  8. P1217 [USACO1.5]回文质数 Prime Palindromes(技巧+暴力枚举+线性筛)
  9. java中文件和流处理
  10. 破解visio2013记录
  11. 跟我学制作javaEE网上书店销售管理系统(沙箱支付)springboot+vue
  12. C++ RapidXml快速入门
  13. MATLAB机器人可视化运动仿真
  14. 实习期间工作、学习、成长、收获总结
  15. 微信打开网址添加在浏览器中打开提示遮罩
  16. 使​​用Hashicorp Vault管理PKI并颁发证书
  17. 正则表达式-注册表验证
  18. python练习 002 斜边上的高
  19. docker仓库Repository和harbor仓库
  20. draftsight的热补丁

热门文章

  1. Android 系统性能优化(12)---MTK 平台UX性能分析方法
  2. python删除csv某一行_用Python一步从csv中删除特定的行和列
  3. 马斯克的SpaceX星链网遇散热危机,气温过高自动关机
  4. 【AI研究报告】世界顶级投资银行高盛的AI报告:中国人工智能的现状及创新市场...
  5. python做的数据图表怎么在flask中显示_Python:如何在Flask应用程序的表中显示MySQL查询的数据...
  6. 知乎:全球发售2600万股销售股份 每股发售价51.8港元
  7. 史上最大内存!曝iPhone 14 Pro系列运行内存将增至8GB
  8. 亿纬锂能:拟参与竞拍兴华锂盐35.2857%股权 挂牌价1.44亿元
  9. 赔了24亿,干到中国第一!最“不要命”航班,竟让无数人抢着坐?
  10. 社区团购的坑,只有巨头能填?