at v2.6.21 4.2 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/input.h> 32#include <linux/slab.h> 33#include <linux/init.h> 34#include <linux/tty.h> 35#include <linux/delay.h> 36#include <linux/pm.h> 37 38static struct input_handler power_handler; 39 40/* 41 * Power management can't be done in a interrupt context. So we have to 42 * use keventd. 43 */ 44static int suspend_button_pushed = 0; 45static void suspend_button_task_handler(void *data) 46{ 47 udelay(200); /* debounce */ 48 suspend_button_pushed = 0; 49} 50 51static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); 52 53static void power_event(struct input_handle *handle, unsigned int type, 54 unsigned int code, int down) 55{ 56 struct input_dev *dev = handle->dev; 57 58 printk("Entering power_event\n"); 59 60 if (type == EV_PWR) { 61 switch (code) { 62 case KEY_SUSPEND: 63 printk("Powering down entire device\n"); 64 65 if (!suspend_button_pushed) { 66 suspend_button_pushed = 1; 67 schedule_work(&suspend_button_task); 68 } 69 break; 70 case KEY_POWER: 71 /* Hum power down the machine. */ 72 break; 73 default: 74 return; 75 } 76 } 77 78 if (type == EV_KEY) { 79 switch (code) { 80 case KEY_SUSPEND: 81 printk("Powering down input device\n"); 82 /* This is risky. See pm.h for details. */ 83 if (dev->state != PM_RESUME) 84 dev->state = PM_RESUME; 85 else 86 dev->state = PM_SUSPEND; 87 pm_send(dev->pm_dev, dev->state, dev); 88 break; 89 case KEY_POWER: 90 /* Turn the input device off completely ? */ 91 break; 92 default: 93 return; 94 } 95 } 96 return; 97} 98 99static struct input_handle *power_connect(struct input_handler *handler, 100 struct input_dev *dev, 101 const struct input_device_id *id) 102{ 103 struct input_handle *handle; 104 105 if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) 106 return NULL; 107 108 handle->dev = dev; 109 handle->handler = handler; 110 111 input_open_device(handle); 112 113 printk(KERN_INFO "power.c: Adding power management to input layer\n"); 114 return handle; 115} 116 117static void power_disconnect(struct input_handle *handle) 118{ 119 input_close_device(handle); 120 kfree(handle); 121} 122 123static const struct input_device_id power_ids[] = { 124 { 125 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 126 .evbit = { BIT(EV_KEY) }, 127 .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } 128 }, 129 { 130 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 131 .evbit = { BIT(EV_KEY) }, 132 .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) } 133 }, 134 { 135 .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 136 .evbit = { BIT(EV_PWR) }, 137 }, 138 { }, /* Terminating entry */ 139}; 140 141MODULE_DEVICE_TABLE(input, power_ids); 142 143static struct input_handler power_handler = { 144 .event = power_event, 145 .connect = power_connect, 146 .disconnect = power_disconnect, 147 .name = "power", 148 .id_table = power_ids, 149}; 150 151static int __init power_init(void) 152{ 153 return input_register_handler(&power_handler); 154} 155 156static void __exit power_exit(void) 157{ 158 input_unregister_handler(&power_handler); 159} 160 161module_init(power_init); 162module_exit(power_exit); 163 164MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); 165MODULE_DESCRIPTION("Input Power Management driver"); 166MODULE_LICENSE("GPL");