linux/drivers/input/sparse-keymap.c
<<
>>
Prefs
   1/*
   2 * Generic support for sparse keymaps
   3 *
   4 * Copyright (c) 2009 Dmitry Torokhov
   5 *
   6 * Derived from wistron button driver:
   7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
   8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
   9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
  10 *
  11 * This program is free software; you can redistribute it and/or modify it
  12 * under the terms of the GNU General Public License version 2 as published by
  13 * the Free Software Foundation.
  14 */
  15
  16#include <linux/input.h>
  17#include <linux/input/sparse-keymap.h>
  18#include <linux/slab.h>
  19
  20MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
  21MODULE_DESCRIPTION("Generic support for sparse keymaps");
  22MODULE_LICENSE("GPL v2");
  23MODULE_VERSION("0.1");
  24
  25static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
  26                                                const struct key_entry *k)
  27{
  28        struct key_entry *key;
  29        unsigned int idx = 0;
  30
  31        for (key = dev->keycode; key->type != KE_END; key++) {
  32                if (key->type == KE_KEY) {
  33                        if (key == k)
  34                                break;
  35                        idx++;
  36                }
  37        }
  38
  39        return idx;
  40}
  41
  42static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
  43                                                      unsigned int index)
  44{
  45        struct key_entry *key;
  46        unsigned int key_cnt = 0;
  47
  48        for (key = dev->keycode; key->type != KE_END; key++)
  49                if (key->type == KE_KEY)
  50                        if (key_cnt++ == index)
  51                                return key;
  52
  53        return NULL;
  54}
  55
  56/**
  57 * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
  58 * @dev: Input device using sparse keymap
  59 * @code: Scan code
  60 *
  61 * This function is used to perform &struct key_entry lookup in an
  62 * input device using sparse keymap.
  63 */
  64struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
  65                                                    unsigned int code)
  66{
  67        struct key_entry *key;
  68
  69        for (key = dev->keycode; key->type != KE_END; key++)
  70                if (code == key->code)
  71                        return key;
  72
  73        return NULL;
  74}
  75EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
  76
  77/**
  78 * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
  79 * @dev: Input device using sparse keymap
  80 * @keycode: Key code
  81 *
  82 * This function is used to perform &struct key_entry lookup in an
  83 * input device using sparse keymap.
  84 */
  85struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
  86                                                   unsigned int keycode)
  87{
  88        struct key_entry *key;
  89
  90        for (key = dev->keycode; key->type != KE_END; key++)
  91                if (key->type == KE_KEY && keycode == key->keycode)
  92                        return key;
  93
  94        return NULL;
  95}
  96EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
  97
  98static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
  99                                        const struct input_keymap_entry *ke)
 100{
 101        struct key_entry *key;
 102        unsigned int scancode;
 103
 104        if (ke->flags & INPUT_KEYMAP_BY_INDEX)
 105                key = sparse_keymap_entry_by_index(dev, ke->index);
 106        else if (input_scancode_to_scalar(ke, &scancode) == 0)
 107                key = sparse_keymap_entry_from_scancode(dev, scancode);
 108        else
 109                key = NULL;
 110
 111        return key;
 112}
 113
 114static int sparse_keymap_getkeycode(struct input_dev *dev,
 115                                    struct input_keymap_entry *ke)
 116{
 117        const struct key_entry *key;
 118
 119        if (dev->keycode) {
 120                key = sparse_keymap_locate(dev, ke);
 121                if (key && key->type == KE_KEY) {
 122                        ke->keycode = key->keycode;
 123                        if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
 124                                ke->index =
 125                                        sparse_keymap_get_key_index(dev, key);
 126                        ke->len = sizeof(key->code);
 127                        memcpy(ke->scancode, &key->code, sizeof(key->code));
 128                        return 0;
 129                }
 130        }
 131
 132        return -EINVAL;
 133}
 134
 135static int sparse_keymap_setkeycode(struct input_dev *dev,
 136                                    const struct input_keymap_entry *ke,
 137                                    unsigned int *old_keycode)
 138{
 139        struct key_entry *key;
 140
 141        if (dev->keycode) {
 142                key = sparse_keymap_locate(dev, ke);
 143                if (key && key->type == KE_KEY) {
 144                        *old_keycode = key->keycode;
 145                        key->keycode = ke->keycode;
 146                        set_bit(ke->keycode, dev->keybit);
 147                        if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
 148                                clear_bit(*old_keycode, dev->keybit);
 149                        return 0;
 150                }
 151        }
 152
 153        return -EINVAL;
 154}
 155
 156/**
 157 * sparse_keymap_setup - set up sparse keymap for an input device
 158 * @dev: Input device
 159 * @keymap: Keymap in form of array of &key_entry structures ending
 160 *      with %KE_END type entry
 161 * @setup: Function that can be used to adjust keymap entries
 162 *      depending on device's deeds, may be %NULL
 163 *
 164 * The function calculates size and allocates copy of the original
 165 * keymap after which sets up input device event bits appropriately.
 166 * Before destroying input device allocated keymap should be freed
 167 * with a call to sparse_keymap_free().
 168 */
 169int sparse_keymap_setup(struct input_dev *dev,
 170                        const struct key_entry *keymap,
 171                        int (*setup)(struct input_dev *, struct key_entry *))
 172{
 173        size_t map_size = 1; /* to account for the last KE_END entry */
 174        const struct key_entry *e;
 175        struct key_entry *map, *entry;
 176        int i;
 177        int error;
 178
 179        for (e = keymap; e->type != KE_END; e++)
 180                map_size++;
 181
 182        map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
 183        if (!map)
 184                return -ENOMEM;
 185
 186        memcpy(map, keymap, map_size * sizeof (struct key_entry));
 187
 188        for (i = 0; i < map_size; i++) {
 189                entry = &map[i];
 190
 191                if (setup) {
 192                        error = setup(dev, entry);
 193                        if (error)
 194                                goto err_out;
 195                }
 196
 197                switch (entry->type) {
 198                case KE_KEY:
 199                        __set_bit(EV_KEY, dev->evbit);
 200                        __set_bit(entry->keycode, dev->keybit);
 201                        break;
 202
 203                case KE_SW:
 204                        __set_bit(EV_SW, dev->evbit);
 205                        __set_bit(entry->sw.code, dev->swbit);
 206                        break;
 207                }
 208        }
 209
 210        dev->keycode = map;
 211        dev->keycodemax = map_size;
 212        dev->getkeycode_new = sparse_keymap_getkeycode;
 213        dev->setkeycode_new = sparse_keymap_setkeycode;
 214
 215        return 0;
 216
 217 err_out:
 218        kfree(map);
 219        return error;
 220}
 221EXPORT_SYMBOL(sparse_keymap_setup);
 222
 223/**
 224 * sparse_keymap_free - free memory allocated for sparse keymap
 225 * @dev: Input device using sparse keymap
 226 *
 227 * This function is used to free memory allocated by sparse keymap
 228 * in an input device that was set up by sparse_keymap_setup().
 229 * NOTE: It is safe to cal this function while input device is
 230 * still registered (however the drivers should care not to try to
 231 * use freed keymap and thus have to shut off interrups/polling
 232 * before freeing the keymap).
 233 */
 234void sparse_keymap_free(struct input_dev *dev)
 235{
 236        unsigned long flags;
 237
 238        /*
 239         * Take event lock to prevent racing with input_get_keycode()
 240         * and input_set_keycode() if we are called while input device
 241         * is still registered.
 242         */
 243        spin_lock_irqsave(&dev->event_lock, flags);
 244
 245        kfree(dev->keycode);
 246        dev->keycode = NULL;
 247        dev->keycodemax = 0;
 248
 249        spin_unlock_irqrestore(&dev->event_lock, flags);
 250}
 251EXPORT_SYMBOL(sparse_keymap_free);
 252
 253/**
 254 * sparse_keymap_report_entry - report event corresponding to given key entry
 255 * @dev: Input device for which event should be reported
 256 * @ke: key entry describing event
 257 * @value: Value that should be reported (ignored by %KE_SW entries)
 258 * @autorelease: Signals whether release event should be emitted for %KE_KEY
 259 *      entries right after reporting press event, ignored by all other
 260 *      entries
 261 *
 262 * This function is used to report input event described by given
 263 * &struct key_entry.
 264 */
 265void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
 266                                unsigned int value, bool autorelease)
 267{
 268        switch (ke->type) {
 269        case KE_KEY:
 270                input_report_key(dev, ke->keycode, value);
 271                input_sync(dev);
 272                if (value && autorelease) {
 273                        input_report_key(dev, ke->keycode, 0);
 274                        input_sync(dev);
 275                }
 276                break;
 277
 278        case KE_SW:
 279                value = ke->sw.value;
 280                /* fall through */
 281
 282        case KE_VSW:
 283                input_report_switch(dev, ke->sw.code, value);
 284                break;
 285        }
 286}
 287EXPORT_SYMBOL(sparse_keymap_report_entry);
 288
 289/**
 290 * sparse_keymap_report_event - report event corresponding to given scancode
 291 * @dev: Input device using sparse keymap
 292 * @code: Scan code
 293 * @value: Value that should be reported (ignored by %KE_SW entries)
 294 * @autorelease: Signals whether release event should be emitted for %KE_KEY
 295 *      entries right after reporting press event, ignored by all other
 296 *      entries
 297 *
 298 * This function is used to perform lookup in an input device using sparse
 299 * keymap and report corresponding event. Returns %true if lookup was
 300 * successful and %false otherwise.
 301 */
 302bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
 303                                unsigned int value, bool autorelease)
 304{
 305        const struct key_entry *ke =
 306                sparse_keymap_entry_from_scancode(dev, code);
 307
 308        if (ke) {
 309                sparse_keymap_report_entry(dev, ke, value, autorelease);
 310                return true;
 311        }
 312
 313        return false;
 314}
 315EXPORT_SYMBOL(sparse_keymap_report_event);
 316
 317
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.