linux/drivers/input/misc/atlas_btns.c
<<
>>
Prefs
   1/*
   2 *  atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
   3 *
   4 *  Copyright (C) 2006 Jaya Kumar
   5 *  Based on Toshiba ACPI by John Belmonte and ASUS ACPI
   6 *  This work was sponsored by CIS(M) Sdn Bhd.
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *  GNU General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License
  19 *  along with this program; if not, write to the Free Software
  20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21 *
  22 */
  23
  24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  25
  26#include <linux/kernel.h>
  27#include <linux/module.h>
  28#include <linux/input.h>
  29#include <linux/types.h>
  30#include <linux/acpi.h>
  31#include <linux/uaccess.h>
  32
  33#define ACPI_ATLAS_NAME         "Atlas ACPI"
  34#define ACPI_ATLAS_CLASS        "Atlas"
  35
  36static unsigned short atlas_keymap[16];
  37static struct input_dev *input_dev;
  38
  39/* button handling code */
  40static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
  41                    u32 function, void *handler_context, void **return_context)
  42{
  43        *return_context =
  44                (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
  45
  46        return AE_OK;
  47}
  48
  49static acpi_status acpi_atlas_button_handler(u32 function,
  50                      acpi_physical_address address,
  51                      u32 bit_width, u64 *value,
  52                      void *handler_context, void *region_context)
  53{
  54        acpi_status status;
  55
  56        if (function == ACPI_WRITE) {
  57                int code = address & 0x0f;
  58                int key_down = !(address & 0x10);
  59
  60                input_event(input_dev, EV_MSC, MSC_SCAN, code);
  61                input_report_key(input_dev, atlas_keymap[code], key_down);
  62                input_sync(input_dev);
  63
  64                status = AE_OK;
  65        } else {
  66                pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
  67                        function, (unsigned long)address, (u32)*value);
  68                status = AE_BAD_PARAMETER;
  69        }
  70
  71        return status;
  72}
  73
  74static int atlas_acpi_button_add(struct acpi_device *device)
  75{
  76        acpi_status status;
  77        int i;
  78        int err;
  79
  80        input_dev = input_allocate_device();
  81        if (!input_dev) {
  82                pr_err("unable to allocate input device\n");
  83                return -ENOMEM;
  84        }
  85
  86        input_dev->name = "Atlas ACPI button driver";
  87        input_dev->phys = "ASIM0000/atlas/input0";
  88        input_dev->id.bustype = BUS_HOST;
  89        input_dev->keycode = atlas_keymap;
  90        input_dev->keycodesize = sizeof(unsigned short);
  91        input_dev->keycodemax = ARRAY_SIZE(atlas_keymap);
  92
  93        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
  94        __set_bit(EV_KEY, input_dev->evbit);
  95        for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) {
  96                if (i < 9) {
  97                        atlas_keymap[i] = KEY_F1 + i;
  98                        __set_bit(KEY_F1 + i, input_dev->keybit);
  99                } else
 100                        atlas_keymap[i] = KEY_RESERVED;
 101        }
 102
 103        err = input_register_device(input_dev);
 104        if (err) {
 105                pr_err("couldn't register input device\n");
 106                input_free_device(input_dev);
 107                return err;
 108        }
 109
 110        /* hookup button handler */
 111        status = acpi_install_address_space_handler(device->handle,
 112                                0x81, &acpi_atlas_button_handler,
 113                                &acpi_atlas_button_setup, device);
 114        if (ACPI_FAILURE(status)) {
 115                pr_err("error installing addr spc handler\n");
 116                input_unregister_device(input_dev);
 117                err = -EINVAL;
 118        }
 119
 120        return err;
 121}
 122
 123static int atlas_acpi_button_remove(struct acpi_device *device)
 124{
 125        acpi_status status;
 126
 127        status = acpi_remove_address_space_handler(device->handle,
 128                                0x81, &acpi_atlas_button_handler);
 129        if (ACPI_FAILURE(status))
 130                pr_err("error removing addr spc handler\n");
 131
 132        input_unregister_device(input_dev);
 133
 134        return 0;
 135}
 136
 137static const struct acpi_device_id atlas_device_ids[] = {
 138        {"ASIM0000", 0},
 139        {"", 0},
 140};
 141MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 142
 143static struct acpi_driver atlas_acpi_driver = {
 144        .name   = ACPI_ATLAS_NAME,
 145        .class  = ACPI_ATLAS_CLASS,
 146        .owner  = THIS_MODULE,
 147        .ids    = atlas_device_ids,
 148        .ops    = {
 149                .add    = atlas_acpi_button_add,
 150                .remove = atlas_acpi_button_remove,
 151        },
 152};
 153module_acpi_driver(atlas_acpi_driver);
 154
 155MODULE_AUTHOR("Jaya Kumar");
 156MODULE_LICENSE("GPL");
 157MODULE_DESCRIPTION("Atlas button driver");
 158
 159