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/init.h>
  29#include <linux/input.h>
  30#include <linux/types.h>
  31#include <asm/uaccess.h>
  32#include <acpi/acpi_drivers.h>
  33
  34#define ACPI_ATLAS_NAME         "Atlas ACPI"
  35#define ACPI_ATLAS_CLASS        "Atlas"
  36
  37static unsigned short atlas_keymap[16];
  38static struct input_dev *input_dev;
  39
  40/* button handling code */
  41static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
  42                    u32 function, void *handler_context, void **return_context)
  43{
  44        *return_context =
  45                (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
  46
  47        return AE_OK;
  48}
  49
  50static acpi_status acpi_atlas_button_handler(u32 function,
  51                      acpi_physical_address address,
  52                      u32 bit_width, u64 *value,
  53                      void *handler_context, void *region_context)
  54{
  55        acpi_status status;
  56
  57        if (function == ACPI_WRITE) {
  58                int code = address & 0x0f;
  59                int key_down = !(address & 0x10);
  60
  61                input_event(input_dev, EV_MSC, MSC_SCAN, code);
  62                input_report_key(input_dev, atlas_keymap[code], key_down);
  63                input_sync(input_dev);
  64
  65                status = AE_OK;
  66        } else {
  67                pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
  68                        function, (unsigned long)address, (u32)*value);
  69                status = AE_BAD_PARAMETER;
  70        }
  71
  72        return status;
  73}
  74
  75static int atlas_acpi_button_add(struct acpi_device *device)
  76{
  77        acpi_status status;
  78        int i;
  79        int err;
  80
  81        input_dev = input_allocate_device();
  82        if (!input_dev) {
  83                pr_err("unable to allocate input device\n");
  84                return -ENOMEM;
  85        }
  86
  87        input_dev->name = "Atlas ACPI button driver";
  88        input_dev->phys = "ASIM0000/atlas/input0";
  89        input_dev->id.bustype = BUS_HOST;
  90        input_dev->keycode = atlas_keymap;
  91        input_dev->keycodesize = sizeof(unsigned short);
  92        input_dev->keycodemax = ARRAY_SIZE(atlas_keymap);
  93
  94        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
  95        __set_bit(EV_KEY, input_dev->evbit);
  96        for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) {
  97                if (i < 9) {
  98                        atlas_keymap[i] = KEY_F1 + i;
  99                        __set_bit(KEY_F1 + i, input_dev->keybit);
 100                } else
 101                        atlas_keymap[i] = KEY_RESERVED;
 102        }
 103
 104        err = input_register_device(input_dev);
 105        if (err) {
 106                pr_err("couldn't register input device\n");
 107                input_free_device(input_dev);
 108                return err;
 109        }
 110
 111        /* hookup button handler */
 112        status = acpi_install_address_space_handler(device->handle,
 113                                0x81, &acpi_atlas_button_handler,
 114                                &acpi_atlas_button_setup, device);
 115        if (ACPI_FAILURE(status)) {
 116                pr_err("error installing addr spc handler\n");
 117                input_unregister_device(input_dev);
 118                err = -EINVAL;
 119        }
 120
 121        return err;
 122}
 123
 124static int atlas_acpi_button_remove(struct acpi_device *device, int type)
 125{
 126        acpi_status status;
 127
 128        status = acpi_remove_address_space_handler(device->handle,
 129                                0x81, &acpi_atlas_button_handler);
 130        if (ACPI_FAILURE(status))
 131                pr_err("error removing addr spc handler\n");
 132
 133        input_unregister_device(input_dev);
 134
 135        return 0;
 136}
 137
 138static const struct acpi_device_id atlas_device_ids[] = {
 139        {"ASIM0000", 0},
 140        {"", 0},
 141};
 142MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 143
 144static struct acpi_driver atlas_acpi_driver = {
 145        .name   = ACPI_ATLAS_NAME,
 146        .class  = ACPI_ATLAS_CLASS,
 147        .owner  = THIS_MODULE,
 148        .ids    = atlas_device_ids,
 149        .ops    = {
 150                .add    = atlas_acpi_button_add,
 151                .remove = atlas_acpi_button_remove,
 152        },
 153};
 154
 155static int __init atlas_acpi_init(void)
 156{
 157        if (acpi_disabled)
 158                return -ENODEV;
 159
 160        return acpi_bus_register_driver(&atlas_acpi_driver);
 161}
 162
 163static void __exit atlas_acpi_exit(void)
 164{
 165        acpi_bus_unregister_driver(&atlas_acpi_driver);
 166}
 167
 168module_init(atlas_acpi_init);
 169module_exit(atlas_acpi_exit);
 170
 171MODULE_AUTHOR("Jaya Kumar");
 172MODULE_LICENSE("GPL");
 173MODULE_DESCRIPTION("Atlas button driver");
 174
 175