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