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#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/init.h>
  27#include <linux/input.h>
  28#include <linux/types.h>
  29#include <asm/uaccess.h>
  30#include <acpi/acpi_drivers.h>
  31
  32#define ACPI_ATLAS_NAME         "Atlas ACPI"
  33#define ACPI_ATLAS_CLASS        "Atlas"
  34
  35static unsigned short atlas_keymap[16];
  36static struct input_dev *input_dev;
  37
  38/* button handling code */
  39static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
  40                    u32 function, void *handler_context, void **return_context)
  41{
  42        *return_context =
  43                (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
  44
  45        return AE_OK;
  46}
  47
  48static acpi_status acpi_atlas_button_handler(u32 function,
  49                      acpi_physical_address address,
  50                      u32 bit_width, acpi_integer *value,
  51                      void *handler_context, void *region_context)
  52{
  53        acpi_status status;
  54
  55        if (function == ACPI_WRITE) {
  56                int code = address & 0x0f;
  57                int key_down = !(address & 0x10);
  58
  59                input_event(input_dev, EV_MSC, MSC_SCAN, code);
  60                input_report_key(input_dev, atlas_keymap[code], key_down);
  61                input_sync(input_dev);
  62
  63                status = 0;
  64        } else {
  65                printk(KERN_WARNING "atlas: shrugged on unexpected function"
  66                        ":function=%x,address=%lx,value=%x\n",
  67                        function, (unsigned long)address, (u32)*value);
  68                status = -EINVAL;
  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                printk(KERN_ERR "atlas: 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                printk(KERN_ERR "atlas: 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                printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
 116                input_unregister_device(input_dev);
 117                status = -EINVAL;
 118        }
 119
 120        return status;
 121}
 122
 123static int atlas_acpi_button_remove(struct acpi_device *device, int type)
 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                printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
 131                status = -EINVAL;
 132        }
 133
 134        input_unregister_device(input_dev);
 135
 136        return status;
 137}
 138
 139static const struct acpi_device_id atlas_device_ids[] = {
 140        {"ASIM0000", 0},
 141        {"", 0},
 142};
 143MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 144
 145static struct acpi_driver atlas_acpi_driver = {
 146        .name   = ACPI_ATLAS_NAME,
 147        .class  = ACPI_ATLAS_CLASS,
 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        int result;
 158
 159        if (acpi_disabled)
 160                return -ENODEV;
 161
 162        result = acpi_bus_register_driver(&atlas_acpi_driver);
 163        if (result < 0) {
 164                printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
 165                return -ENODEV;
 166        }
 167
 168        return 0;
 169}
 170
 171static void __exit atlas_acpi_exit(void)
 172{
 173        acpi_bus_unregister_driver(&atlas_acpi_driver);
 174}
 175
 176module_init(atlas_acpi_init);
 177module_exit(atlas_acpi_exit);
 178
 179MODULE_AUTHOR("Jaya Kumar");
 180MODULE_LICENSE("GPL");
 181MODULE_DESCRIPTION("Atlas button driver");
 182
 183