linux/drivers/input/misc/atlas_btns.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
   4 *
   5 *  Copyright (C) 2006 Jaya Kumar
   6 *  Based on Toshiba ACPI by John Belmonte and ASUS ACPI
   7 *  This work was sponsored by CIS(M) Sdn Bhd.
   8 */
   9
  10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/input.h>
  15#include <linux/types.h>
  16#include <linux/acpi.h>
  17#include <linux/uaccess.h>
  18
  19#define ACPI_ATLAS_NAME         "Atlas ACPI"
  20#define ACPI_ATLAS_CLASS        "Atlas"
  21
  22static unsigned short atlas_keymap[16];
  23static struct input_dev *input_dev;
  24
  25/* button handling code */
  26static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
  27                    u32 function, void *handler_context, void **return_context)
  28{
  29        *return_context =
  30                (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
  31
  32        return AE_OK;
  33}
  34
  35static acpi_status acpi_atlas_button_handler(u32 function,
  36                      acpi_physical_address address,
  37                      u32 bit_width, u64 *value,
  38                      void *handler_context, void *region_context)
  39{
  40        acpi_status status;
  41
  42        if (function == ACPI_WRITE) {
  43                int code = address & 0x0f;
  44                int key_down = !(address & 0x10);
  45
  46                input_event(input_dev, EV_MSC, MSC_SCAN, code);
  47                input_report_key(input_dev, atlas_keymap[code], key_down);
  48                input_sync(input_dev);
  49
  50                status = AE_OK;
  51        } else {
  52                pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
  53                        function, (unsigned long)address, (u32)*value);
  54                status = AE_BAD_PARAMETER;
  55        }
  56
  57        return status;
  58}
  59
  60static int atlas_acpi_button_add(struct acpi_device *device)
  61{
  62        acpi_status status;
  63        int i;
  64        int err;
  65
  66        input_dev = input_allocate_device();
  67        if (!input_dev) {
  68                pr_err("unable to allocate input device\n");
  69                return -ENOMEM;
  70        }
  71
  72        input_dev->name = "Atlas ACPI button driver";
  73        input_dev->phys = "ASIM0000/atlas/input0";
  74        input_dev->id.bustype = BUS_HOST;
  75        input_dev->keycode = atlas_keymap;
  76        input_dev->keycodesize = sizeof(unsigned short);
  77        input_dev->keycodemax = ARRAY_SIZE(atlas_keymap);
  78
  79        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
  80        __set_bit(EV_KEY, input_dev->evbit);
  81        for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) {
  82                if (i < 9) {
  83                        atlas_keymap[i] = KEY_F1 + i;
  84                        __set_bit(KEY_F1 + i, input_dev->keybit);
  85                } else
  86                        atlas_keymap[i] = KEY_RESERVED;
  87        }
  88
  89        err = input_register_device(input_dev);
  90        if (err) {
  91                pr_err("couldn't register input device\n");
  92                input_free_device(input_dev);
  93                return err;
  94        }
  95
  96        /* hookup button handler */
  97        status = acpi_install_address_space_handler(device->handle,
  98                                0x81, &acpi_atlas_button_handler,
  99                                &acpi_atlas_button_setup, device);
 100        if (ACPI_FAILURE(status)) {
 101                pr_err("error installing addr spc handler\n");
 102                input_unregister_device(input_dev);
 103                err = -EINVAL;
 104        }
 105
 106        return err;
 107}
 108
 109static int atlas_acpi_button_remove(struct acpi_device *device)
 110{
 111        acpi_status status;
 112
 113        status = acpi_remove_address_space_handler(device->handle,
 114                                0x81, &acpi_atlas_button_handler);
 115        if (ACPI_FAILURE(status))
 116                pr_err("error removing addr spc handler\n");
 117
 118        input_unregister_device(input_dev);
 119
 120        return 0;
 121}
 122
 123static const struct acpi_device_id atlas_device_ids[] = {
 124        {"ASIM0000", 0},
 125        {"", 0},
 126};
 127MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 128
 129static struct acpi_driver atlas_acpi_driver = {
 130        .name   = ACPI_ATLAS_NAME,
 131        .class  = ACPI_ATLAS_CLASS,
 132        .owner  = THIS_MODULE,
 133        .ids    = atlas_device_ids,
 134        .ops    = {
 135                .add    = atlas_acpi_button_add,
 136                .remove = atlas_acpi_button_remove,
 137        },
 138};
 139module_acpi_driver(atlas_acpi_driver);
 140
 141MODULE_AUTHOR("Jaya Kumar");
 142MODULE_LICENSE("GPL");
 143MODULE_DESCRIPTION("Atlas button driver");
 144
 145