at v2.6.13 169 lines 4.3 kB view raw
1/* 2 * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $ 3 * 4 * Copyright (c) 2001 "Crazy" James Simmons 5 * 6 * Input driver Power Management. 7 * 8 * Sponsored by Transvirtual Technology. 9 */ 10 11/* 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 * 26 * Should you need to contact me, the author, you can do so by 27 * e-mail - mail your message to <jsimmons@transvirtual.com>. 28 */ 29 30#include <linux/module.h> 31#include <linux/config.h> 32#include <linux/input.h> 33#include <linux/slab.h> 34#include <linux/init.h> 35#include <linux/tty.h> 36#include <linux/delay.h> 37#include <linux/pm.h> 38 39static struct input_handler power_handler; 40 41/* 42 * Power management can't be done in a interrupt context. So we have to 43 * use keventd. 44 */ 45static int suspend_button_pushed = 0; 46static void suspend_button_task_handler(void *data) 47{ 48 udelay(200); /* debounce */ 49 suspend_button_pushed = 0; 50} 51 52static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); 53 54static void power_event(struct input_handle *handle, unsigned int type, 55 unsigned int code, int down) 56{ 57 struct input_dev *dev = handle->dev; 58 59 printk("Entering power_event\n"); 60 61 if (type == EV_PWR) { 62 switch (code) { 63 case KEY_SUSPEND: 64 printk("Powering down entire device\n"); 65 66 if (!suspend_button_pushed) { 67 suspend_button_pushed = 1; 68 schedule_work(&suspend_button_task); 69 } 70 break; 71 case KEY_POWER: 72 /* Hum power down the machine. */ 73 break; 74 default: 75 return; 76 } 77 } 78 79 if (type == EV_KEY) { 80 switch (code) { 81 case KEY_SUSPEND: 82 printk("Powering down input device\n"); 83 /* This is risky. See pm.h for details. */ 84 if (dev->state != PM_RESUME) 85 dev->state = PM_RESUME; 86 else 87 dev->state = PM_SUSPEND; 88 pm_send(dev->pm_dev, dev->state, dev); 89 break; 90 case KEY_POWER: 91 /* Turn the input device off completely ? */ 92 break; 93 default: 94 return; 95 } 96 } 97 return; 98} 99 100static struct input_handle *power_connect(struct input_handler *handler, 101 struct input_dev *dev, 102 struct input_device_id *id) 103{ 104 struct input_handle *handle; 105 106 if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) 107 return NULL; 108 memset(handle, 0, sizeof(struct input_handle)); 109 110 handle->dev = dev; 111 handle->handler = handler; 112 113 input_open_device(handle); 114 115 printk(KERN_INFO "power.c: Adding power management to input layer\n"); 116 return handle; 117} 118 119static void power_disconnect(struct input_handle *handle) 120{ 121 input_close_device(handle); 122 kfree(handle); 123} 124 125static struct input_device_id power_ids[] = { 126 { 127 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 128 .evbit = { BIT(EV_KEY) }, 129 .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } 130 }, 131 { 132 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 133 .evbit = { BIT(EV_KEY) }, 134 .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) } 135 }, 136 { 137 .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 138 .evbit = { BIT(EV_PWR) }, 139 }, 140 { }, /* Terminating entry */ 141}; 142 143MODULE_DEVICE_TABLE(input, power_ids); 144 145static struct input_handler power_handler = { 146 .event = power_event, 147 .connect = power_connect, 148 .disconnect = power_disconnect, 149 .name = "power", 150 .id_table = power_ids, 151}; 152 153static int __init power_init(void) 154{ 155 input_register_handler(&power_handler); 156 return 0; 157} 158 159static void __exit power_exit(void) 160{ 161 input_unregister_handler(&power_handler); 162} 163 164module_init(power_init); 165module_exit(power_exit); 166 167MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); 168MODULE_DESCRIPTION("Input Power Management driver"); 169MODULE_LICENSE("GPL");