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