cregit-Linux how code gets into the kernel

Release 4.11 drivers/input/sparse-keymap.c

Directory: drivers/input
/*
 * Generic support for sparse keymaps
 *
 * Copyright (c) 2009 Dmitry Torokhov
 *
 * Derived from wistron button driver:
 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
 *
 * 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/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/module.h>
#include <linux/slab.h>

MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("Generic support for sparse keymaps");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");


static unsigned int sparse_keymap_get_key_index(struct input_dev *dev, const struct key_entry *k) { struct key_entry *key; unsigned int idx = 0; for (key = dev->keycode; key->type != KE_END; key++) { if (key->type == KE_KEY) { if (key == k) break; idx++; } } return idx; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov71100.00%1100.00%
Total71100.00%1100.00%


static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev, unsigned int index) { struct key_entry *key; unsigned int key_cnt = 0; for (key = dev->keycode; key->type != KE_END; key++) if (key->type == KE_KEY) if (key_cnt++ == index) return key; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov66100.00%1100.00%
Total66100.00%1100.00%

/** * sparse_keymap_entry_from_scancode - perform sparse keymap lookup * @dev: Input device using sparse keymap * @code: Scan code * * This function is used to perform &struct key_entry lookup in an * input device using sparse keymap. */
struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev, unsigned int code) { struct key_entry *key; for (key = dev->keycode; key->type != KE_END; key++) if (code == key->code) return key; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov52100.00%1100.00%
Total52100.00%1100.00%

EXPORT_SYMBOL(sparse_keymap_entry_from_scancode); /** * sparse_keymap_entry_from_keycode - perform sparse keymap lookup * @dev: Input device using sparse keymap * @keycode: Key code * * This function is used to perform &struct key_entry lookup in an * input device using sparse keymap. */
struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, unsigned int keycode) { struct key_entry *key; for (key = dev->keycode; key->type != KE_END; key++) if (key->type == KE_KEY && keycode == key->keycode) return key; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov58100.00%1100.00%
Total58100.00%1100.00%

EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
static struct key_entry *sparse_keymap_locate(struct input_dev *dev, const struct input_keymap_entry *ke) { struct key_entry *key; unsigned int scancode; if (ke->flags & INPUT_KEYMAP_BY_INDEX) key = sparse_keymap_entry_by_index(dev, ke->index); else if (input_scancode_to_scalar(ke, &scancode) == 0) key = sparse_keymap_entry_from_scancode(dev, scancode); else key = NULL; return key; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov77100.00%3100.00%
Total77100.00%3100.00%


static int sparse_keymap_getkeycode(struct input_dev *dev, struct input_keymap_entry *ke) { const struct key_entry *key; if (dev->keycode) { key = sparse_keymap_locate(dev, ke); if (key && key->type == KE_KEY) { ke->keycode = key->keycode; if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) ke->index = sparse_keymap_get_key_index(dev, key); ke->len = sizeof(key->code); memcpy(ke->scancode, &key->code, sizeof(key->code)); return 0; } } return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov118100.00%3100.00%
Total118100.00%3100.00%


static int sparse_keymap_setkeycode(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *old_keycode) { struct key_entry *key; if (dev->keycode) { key = sparse_keymap_locate(dev, ke); if (key && key->type == KE_KEY) { *old_keycode = key->keycode; key->keycode = ke->keycode; set_bit(ke->keycode, dev->keybit); if (!sparse_keymap_entry_from_keycode(dev, *old_keycode)) clear_bit(*old_keycode, dev->keybit); return 0; } } return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov110100.00%4100.00%
Total110100.00%4100.00%

/** * sparse_keymap_setup - set up sparse keymap for an input device * @dev: Input device * @keymap: Keymap in form of array of &key_entry structures ending * with %KE_END type entry * @setup: Function that can be used to adjust keymap entries * depending on device's deeds, may be %NULL * * The function calculates size and allocates copy of the original * keymap after which sets up input device event bits appropriately. * Before destroying input device allocated keymap should be freed * with a call to sparse_keymap_free(). */
int sparse_keymap_setup(struct input_dev *dev, const struct key_entry *keymap, int (*setup)(struct input_dev *, struct key_entry *)) { size_t map_size = 1; /* to account for the last KE_END entry */ const struct key_entry *e; struct key_entry *map, *entry; int i; int error; for (e = keymap; e->type != KE_END; e++) map_size++; map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL); if (!map) return -ENOMEM; memcpy(map, keymap, map_size * sizeof(struct key_entry)); for (i = 0; i < map_size; i++) { entry = &map[i]; if (setup) { error = setup(dev, entry); if (error) goto err_out; } switch (entry->type) { case KE_KEY: __set_bit(EV_KEY, dev->evbit); __set_bit(entry->keycode, dev->keybit); break; case KE_SW: case KE_VSW: __set_bit(EV_SW, dev->evbit); __set_bit(entry->sw.code, dev->swbit); break; } } if (test_bit(EV_KEY, dev->evbit)) { __set_bit(KEY_UNKNOWN, dev->keybit); __set_bit(EV_MSC, dev->evbit); __set_bit(MSC_SCAN, dev->mscbit); } dev->keycode = map; dev->keycodemax = map_size; dev->getkeycode = sparse_keymap_getkeycode; dev->setkeycode = sparse_keymap_setkeycode; return 0; err_out: kfree(map); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov25686.20%350.00%
Seth Forshee4013.47%233.33%
Yong Wang10.34%116.67%
Total297100.00%6100.00%

EXPORT_SYMBOL(sparse_keymap_setup); /** * sparse_keymap_free - free memory allocated for sparse keymap * @dev: Input device using sparse keymap * * This function is used to free memory allocated by sparse keymap * in an input device that was set up by sparse_keymap_setup(). * NOTE: It is safe to cal this function while input device is * still registered (however the drivers should care not to try to * use freed keymap and thus have to shut off interrupts/polling * before freeing the keymap). */
void sparse_keymap_free(struct input_dev *dev) { unsigned long flags; /* * Take event lock to prevent racing with input_get_keycode() * and input_set_keycode() if we are called while input device * is still registered. */ spin_lock_irqsave(&dev->event_lock, flags); kfree(dev->keycode); dev->keycode = NULL; dev->keycodemax = 0; spin_unlock_irqrestore(&dev->event_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov54100.00%2100.00%
Total54100.00%2100.00%

EXPORT_SYMBOL(sparse_keymap_free); /** * sparse_keymap_report_entry - report event corresponding to given key entry * @dev: Input device for which event should be reported * @ke: key entry describing event * @value: Value that should be reported (ignored by %KE_SW entries) * @autorelease: Signals whether release event should be emitted for %KE_KEY * entries right after reporting press event, ignored by all other * entries * * This function is used to report input event described by given * &struct key_entry. */
void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, unsigned int value, bool autorelease) { switch (ke->type) { case KE_KEY: input_event(dev, EV_MSC, MSC_SCAN, ke->code); input_report_key(dev, ke->keycode, value); input_sync(dev); if (value && autorelease) { input_report_key(dev, ke->keycode, 0); input_sync(dev); } break; case KE_SW: value = ke->sw.value; /* fall through */ case KE_VSW: input_report_switch(dev, ke->sw.code, value); break; } }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov10488.89%150.00%
Seth Forshee1311.11%150.00%
Total117100.00%2100.00%

EXPORT_SYMBOL(sparse_keymap_report_entry); /** * sparse_keymap_report_event - report event corresponding to given scancode * @dev: Input device using sparse keymap * @code: Scan code * @value: Value that should be reported (ignored by %KE_SW entries) * @autorelease: Signals whether release event should be emitted for %KE_KEY * entries right after reporting press event, ignored by all other * entries * * This function is used to perform lookup in an input device using sparse * keymap and report corresponding event. Returns %true if lookup was * successful and %false otherwise. */
bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, unsigned int value, bool autorelease) { const struct key_entry *ke = sparse_keymap_entry_from_scancode(dev, code); struct key_entry unknown_ke; if (ke) { sparse_keymap_report_entry(dev, ke, value, autorelease); return true; } /* Report an unknown key event as a debugging aid */ unknown_ke.type = KE_KEY; unknown_ke.code = code; unknown_ke.keycode = KEY_UNKNOWN; sparse_keymap_report_entry(dev, &unknown_ke, value, true); return false; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov5761.96%150.00%
Seth Forshee3538.04%150.00%
Total92100.00%2100.00%

EXPORT_SYMBOL(sparse_keymap_report_event);

Overall Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov108591.87%650.00%
Seth Forshee887.45%216.67%
Tejun Heo30.25%18.33%
Paul Gortmaker30.25%18.33%
Yong Wang10.08%18.33%
Masanari Iida10.08%18.33%
Total1181100.00%12100.00%
Directory: drivers/input
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.