131ea7ff0SJaya Kumar /* 231ea7ff0SJaya Kumar * atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras 331ea7ff0SJaya Kumar * 431ea7ff0SJaya Kumar * Copyright (C) 2006 Jaya Kumar 531ea7ff0SJaya Kumar * Based on Toshiba ACPI by John Belmonte and ASUS ACPI 631ea7ff0SJaya Kumar * This work was sponsored by CIS(M) Sdn Bhd. 731ea7ff0SJaya Kumar * 831ea7ff0SJaya Kumar * This program is free software; you can redistribute it and/or modify 931ea7ff0SJaya Kumar * it under the terms of the GNU General Public License as published by 1031ea7ff0SJaya Kumar * the Free Software Foundation; either version 2 of the License, or 1131ea7ff0SJaya Kumar * (at your option) any later version. 1231ea7ff0SJaya Kumar * 1331ea7ff0SJaya Kumar * This program is distributed in the hope that it will be useful, 1431ea7ff0SJaya Kumar * but WITHOUT ANY WARRANTY; without even the implied warranty of 1531ea7ff0SJaya Kumar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1631ea7ff0SJaya Kumar * GNU General Public License for more details. 1731ea7ff0SJaya Kumar * 1831ea7ff0SJaya Kumar * You should have received a copy of the GNU General Public License 1931ea7ff0SJaya Kumar * along with this program; if not, write to the Free Software 2031ea7ff0SJaya Kumar * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2131ea7ff0SJaya Kumar * 2231ea7ff0SJaya Kumar */ 2331ea7ff0SJaya Kumar 2431ea7ff0SJaya Kumar #include <linux/kernel.h> 2531ea7ff0SJaya Kumar #include <linux/module.h> 2631ea7ff0SJaya Kumar #include <linux/init.h> 2731ea7ff0SJaya Kumar #include <linux/input.h> 2831ea7ff0SJaya Kumar #include <linux/types.h> 2931ea7ff0SJaya Kumar #include <asm/uaccess.h> 3031ea7ff0SJaya Kumar #include <acpi/acpi_drivers.h> 3131ea7ff0SJaya Kumar 3231ea7ff0SJaya Kumar #define ACPI_ATLAS_NAME "Atlas ACPI" 3331ea7ff0SJaya Kumar #define ACPI_ATLAS_CLASS "Atlas" 3431ea7ff0SJaya Kumar 3572341eeaSDmitry Torokhov static unsigned short atlas_keymap[16]; 3631ea7ff0SJaya Kumar static struct input_dev *input_dev; 3731ea7ff0SJaya Kumar 3831ea7ff0SJaya Kumar /* button handling code */ 3931ea7ff0SJaya Kumar static acpi_status acpi_atlas_button_setup(acpi_handle region_handle, 4031ea7ff0SJaya Kumar u32 function, void *handler_context, void **return_context) 4131ea7ff0SJaya Kumar { 4231ea7ff0SJaya Kumar *return_context = 4331ea7ff0SJaya Kumar (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL; 4431ea7ff0SJaya Kumar 4531ea7ff0SJaya Kumar return AE_OK; 4631ea7ff0SJaya Kumar } 4731ea7ff0SJaya Kumar 4831ea7ff0SJaya Kumar static acpi_status acpi_atlas_button_handler(u32 function, 4931ea7ff0SJaya Kumar acpi_physical_address address, 50439913ffSLin Ming u32 bit_width, u64 *value, 5131ea7ff0SJaya Kumar void *handler_context, void *region_context) 5231ea7ff0SJaya Kumar { 5331ea7ff0SJaya Kumar acpi_status status; 5431ea7ff0SJaya Kumar 5531ea7ff0SJaya Kumar if (function == ACPI_WRITE) { 5672341eeaSDmitry Torokhov int code = address & 0x0f; 5772341eeaSDmitry Torokhov int key_down = !(address & 0x10); 5872341eeaSDmitry Torokhov 5972341eeaSDmitry Torokhov input_event(input_dev, EV_MSC, MSC_SCAN, code); 6072341eeaSDmitry Torokhov input_report_key(input_dev, atlas_keymap[code], key_down); 6131ea7ff0SJaya Kumar input_sync(input_dev); 6272341eeaSDmitry Torokhov 6302b5fac1SAxel Lin status = AE_OK; 6431ea7ff0SJaya Kumar } else { 6531ea7ff0SJaya Kumar printk(KERN_WARNING "atlas: shrugged on unexpected function" 6631ea7ff0SJaya Kumar ":function=%x,address=%lx,value=%x\n", 6731ea7ff0SJaya Kumar function, (unsigned long)address, (u32)*value); 6802b5fac1SAxel Lin status = AE_BAD_PARAMETER; 6931ea7ff0SJaya Kumar } 7031ea7ff0SJaya Kumar 7131ea7ff0SJaya Kumar return status; 7231ea7ff0SJaya Kumar } 7331ea7ff0SJaya Kumar 7431ea7ff0SJaya Kumar static int atlas_acpi_button_add(struct acpi_device *device) 7531ea7ff0SJaya Kumar { 7631ea7ff0SJaya Kumar acpi_status status; 7772341eeaSDmitry Torokhov int i; 7831ea7ff0SJaya Kumar int err; 7931ea7ff0SJaya Kumar 8031ea7ff0SJaya Kumar input_dev = input_allocate_device(); 8131ea7ff0SJaya Kumar if (!input_dev) { 8231ea7ff0SJaya Kumar printk(KERN_ERR "atlas: unable to allocate input device\n"); 8331ea7ff0SJaya Kumar return -ENOMEM; 8431ea7ff0SJaya Kumar } 8531ea7ff0SJaya Kumar 8631ea7ff0SJaya Kumar input_dev->name = "Atlas ACPI button driver"; 8731ea7ff0SJaya Kumar input_dev->phys = "ASIM0000/atlas/input0"; 8831ea7ff0SJaya Kumar input_dev->id.bustype = BUS_HOST; 8972341eeaSDmitry Torokhov input_dev->keycode = atlas_keymap; 9072341eeaSDmitry Torokhov input_dev->keycodesize = sizeof(unsigned short); 9172341eeaSDmitry Torokhov input_dev->keycodemax = ARRAY_SIZE(atlas_keymap); 9231ea7ff0SJaya Kumar 9372341eeaSDmitry Torokhov input_set_capability(input_dev, EV_MSC, MSC_SCAN); 9472341eeaSDmitry Torokhov __set_bit(EV_KEY, input_dev->evbit); 9572341eeaSDmitry Torokhov for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) { 9672341eeaSDmitry Torokhov if (i < 9) { 9772341eeaSDmitry Torokhov atlas_keymap[i] = KEY_F1 + i; 9872341eeaSDmitry Torokhov __set_bit(KEY_F1 + i, input_dev->keybit); 9972341eeaSDmitry Torokhov } else 10072341eeaSDmitry Torokhov atlas_keymap[i] = KEY_RESERVED; 10172341eeaSDmitry Torokhov } 10231ea7ff0SJaya Kumar 10331ea7ff0SJaya Kumar err = input_register_device(input_dev); 10431ea7ff0SJaya Kumar if (err) { 10531ea7ff0SJaya Kumar printk(KERN_ERR "atlas: couldn't register input device\n"); 10631ea7ff0SJaya Kumar input_free_device(input_dev); 10731ea7ff0SJaya Kumar return err; 10831ea7ff0SJaya Kumar } 10931ea7ff0SJaya Kumar 11031ea7ff0SJaya Kumar /* hookup button handler */ 11131ea7ff0SJaya Kumar status = acpi_install_address_space_handler(device->handle, 11231ea7ff0SJaya Kumar 0x81, &acpi_atlas_button_handler, 11331ea7ff0SJaya Kumar &acpi_atlas_button_setup, device); 11431ea7ff0SJaya Kumar if (ACPI_FAILURE(status)) { 11531ea7ff0SJaya Kumar printk(KERN_ERR "Atlas: Error installing addr spc handler\n"); 11631ea7ff0SJaya Kumar input_unregister_device(input_dev); 11702b5fac1SAxel Lin err = -EINVAL; 11831ea7ff0SJaya Kumar } 11931ea7ff0SJaya Kumar 12002b5fac1SAxel Lin return err; 12131ea7ff0SJaya Kumar } 12231ea7ff0SJaya Kumar 12331ea7ff0SJaya Kumar static int atlas_acpi_button_remove(struct acpi_device *device, int type) 12431ea7ff0SJaya Kumar { 12531ea7ff0SJaya Kumar acpi_status status; 12631ea7ff0SJaya Kumar 12731ea7ff0SJaya Kumar status = acpi_remove_address_space_handler(device->handle, 12831ea7ff0SJaya Kumar 0x81, &acpi_atlas_button_handler); 12902b5fac1SAxel Lin if (ACPI_FAILURE(status)) 13031ea7ff0SJaya Kumar printk(KERN_ERR "Atlas: Error removing addr spc handler\n"); 13131ea7ff0SJaya Kumar 13231ea7ff0SJaya Kumar input_unregister_device(input_dev); 13331ea7ff0SJaya Kumar 13402b5fac1SAxel Lin return 0; 13531ea7ff0SJaya Kumar } 13631ea7ff0SJaya Kumar 1371ba90e3aSThomas Renninger static const struct acpi_device_id atlas_device_ids[] = { 1381ba90e3aSThomas Renninger {"ASIM0000", 0}, 1391ba90e3aSThomas Renninger {"", 0}, 1401ba90e3aSThomas Renninger }; 1411ba90e3aSThomas Renninger MODULE_DEVICE_TABLE(acpi, atlas_device_ids); 1421ba90e3aSThomas Renninger 14331ea7ff0SJaya Kumar static struct acpi_driver atlas_acpi_driver = { 14431ea7ff0SJaya Kumar .name = ACPI_ATLAS_NAME, 14531ea7ff0SJaya Kumar .class = ACPI_ATLAS_CLASS, 14607d19ffcSAxel Lin .owner = THIS_MODULE, 1471ba90e3aSThomas Renninger .ids = atlas_device_ids, 14831ea7ff0SJaya Kumar .ops = { 14931ea7ff0SJaya Kumar .add = atlas_acpi_button_add, 15031ea7ff0SJaya Kumar .remove = atlas_acpi_button_remove, 15131ea7ff0SJaya Kumar }, 15231ea7ff0SJaya Kumar }; 15331ea7ff0SJaya Kumar 15431ea7ff0SJaya Kumar static int __init atlas_acpi_init(void) 15531ea7ff0SJaya Kumar { 15631ea7ff0SJaya Kumar int result; 15731ea7ff0SJaya Kumar 15831ea7ff0SJaya Kumar if (acpi_disabled) 15931ea7ff0SJaya Kumar return -ENODEV; 16031ea7ff0SJaya Kumar 16131ea7ff0SJaya Kumar result = acpi_bus_register_driver(&atlas_acpi_driver); 16231ea7ff0SJaya Kumar if (result < 0) { 16331ea7ff0SJaya Kumar printk(KERN_ERR "Atlas ACPI: Unable to register driver\n"); 16431ea7ff0SJaya Kumar return -ENODEV; 16531ea7ff0SJaya Kumar } 16631ea7ff0SJaya Kumar 16731ea7ff0SJaya Kumar return 0; 16831ea7ff0SJaya Kumar } 16931ea7ff0SJaya Kumar 17031ea7ff0SJaya Kumar static void __exit atlas_acpi_exit(void) 17131ea7ff0SJaya Kumar { 17231ea7ff0SJaya Kumar acpi_bus_unregister_driver(&atlas_acpi_driver); 17331ea7ff0SJaya Kumar } 17431ea7ff0SJaya Kumar 17531ea7ff0SJaya Kumar module_init(atlas_acpi_init); 17631ea7ff0SJaya Kumar module_exit(atlas_acpi_exit); 17731ea7ff0SJaya Kumar 17831ea7ff0SJaya Kumar MODULE_AUTHOR("Jaya Kumar"); 17931ea7ff0SJaya Kumar MODULE_LICENSE("GPL"); 18031ea7ff0SJaya Kumar MODULE_DESCRIPTION("Atlas button driver"); 18131ea7ff0SJaya Kumar 182