xref: /openbmc/linux/drivers/acpi/button.c (revision 2b8232ce)
1 /*
2  *  acpi_button.c - ACPI Button Driver ($Revision: 30 $)
3  *
4  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6  *
7  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or (at
12  *  your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful, but
15  *  WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License along
20  *  with this program; if not, write to the Free Software Foundation, Inc.,
21  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22  *
23  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24  */
25 
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/types.h>
30 #include <linux/proc_fs.h>
31 #include <linux/seq_file.h>
32 #include <linux/input.h>
33 #include <acpi/acpi_bus.h>
34 #include <acpi/acpi_drivers.h>
35 
36 #define ACPI_BUTTON_COMPONENT		0x00080000
37 #define ACPI_BUTTON_CLASS		"button"
38 #define ACPI_BUTTON_FILE_INFO		"info"
39 #define ACPI_BUTTON_FILE_STATE		"state"
40 #define ACPI_BUTTON_TYPE_UNKNOWN	0x00
41 #define ACPI_BUTTON_NOTIFY_STATUS	0x80
42 
43 #define ACPI_BUTTON_SUBCLASS_POWER	"power"
44 #define ACPI_BUTTON_HID_POWER		"PNP0C0C"
45 #define ACPI_BUTTON_DEVICE_NAME_POWER	"Power Button (CM)"
46 #define ACPI_BUTTON_DEVICE_NAME_POWERF	"Power Button (FF)"
47 #define ACPI_BUTTON_TYPE_POWER		0x01
48 #define ACPI_BUTTON_TYPE_POWERF		0x02
49 
50 #define ACPI_BUTTON_SUBCLASS_SLEEP	"sleep"
51 #define ACPI_BUTTON_HID_SLEEP		"PNP0C0E"
52 #define ACPI_BUTTON_DEVICE_NAME_SLEEP	"Sleep Button (CM)"
53 #define ACPI_BUTTON_DEVICE_NAME_SLEEPF	"Sleep Button (FF)"
54 #define ACPI_BUTTON_TYPE_SLEEP		0x03
55 #define ACPI_BUTTON_TYPE_SLEEPF		0x04
56 
57 #define ACPI_BUTTON_SUBCLASS_LID	"lid"
58 #define ACPI_BUTTON_HID_LID		"PNP0C0D"
59 #define ACPI_BUTTON_DEVICE_NAME_LID	"Lid Switch"
60 #define ACPI_BUTTON_TYPE_LID		0x05
61 
62 #define _COMPONENT		ACPI_BUTTON_COMPONENT
63 ACPI_MODULE_NAME("button");
64 
65 MODULE_AUTHOR("Paul Diefenbaugh");
66 MODULE_DESCRIPTION("ACPI Button Driver");
67 MODULE_LICENSE("GPL");
68 
69 static const struct acpi_device_id button_device_ids[] = {
70 	{ACPI_BUTTON_HID_LID,    0},
71 	{ACPI_BUTTON_HID_SLEEP,  0},
72 	{ACPI_BUTTON_HID_SLEEPF, 0},
73 	{ACPI_BUTTON_HID_POWER,  0},
74 	{ACPI_BUTTON_HID_POWERF, 0},
75 	{"", 0},
76 };
77 MODULE_DEVICE_TABLE(acpi, button_device_ids);
78 
79 static int acpi_button_add(struct acpi_device *device);
80 static int acpi_button_remove(struct acpi_device *device, int type);
81 static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
82 static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
83 
84 static struct acpi_driver acpi_button_driver = {
85 	.name = "button",
86 	.class = ACPI_BUTTON_CLASS,
87 	.ids = button_device_ids,
88 	.ops = {
89 		.add = acpi_button_add,
90 		.remove = acpi_button_remove,
91 	},
92 };
93 
94 struct acpi_button {
95 	struct acpi_device *device;	/* Fixed button kludge */
96 	unsigned int type;
97 	struct input_dev *input;
98 	char phys[32];			/* for input device */
99 	unsigned long pushed;
100 };
101 
102 static const struct file_operations acpi_button_info_fops = {
103 	.open = acpi_button_info_open_fs,
104 	.read = seq_read,
105 	.llseek = seq_lseek,
106 	.release = single_release,
107 };
108 
109 static const struct file_operations acpi_button_state_fops = {
110 	.open = acpi_button_state_open_fs,
111 	.read = seq_read,
112 	.llseek = seq_lseek,
113 	.release = single_release,
114 };
115 
116 /* --------------------------------------------------------------------------
117                               FS Interface (/proc)
118    -------------------------------------------------------------------------- */
119 
120 static struct proc_dir_entry *acpi_button_dir;
121 
122 static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
123 {
124 	struct acpi_button *button = seq->private;
125 
126 	if (!button || !button->device)
127 		return 0;
128 
129 	seq_printf(seq, "type:                    %s\n",
130 		   acpi_device_name(button->device));
131 
132 	return 0;
133 }
134 
135 static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
136 {
137 	return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
138 }
139 
140 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
141 {
142 	struct acpi_button *button = seq->private;
143 	acpi_status status;
144 	unsigned long state;
145 
146 	if (!button || !button->device)
147 		return 0;
148 
149 	status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
150 	seq_printf(seq, "state:      %s\n",
151 		   ACPI_FAILURE(status) ? "unsupported" :
152 			(state ? "open" : "closed"));
153 	return 0;
154 }
155 
156 static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
157 {
158 	return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
159 }
160 
161 static struct proc_dir_entry *acpi_power_dir;
162 static struct proc_dir_entry *acpi_sleep_dir;
163 static struct proc_dir_entry *acpi_lid_dir;
164 
165 static int acpi_button_add_fs(struct acpi_device *device)
166 {
167 	struct proc_dir_entry *entry = NULL;
168 	struct acpi_button *button;
169 
170 	if (!device || !acpi_driver_data(device))
171 		return -EINVAL;
172 
173 	button = acpi_driver_data(device);
174 
175 	switch (button->type) {
176 	case ACPI_BUTTON_TYPE_POWER:
177 	case ACPI_BUTTON_TYPE_POWERF:
178 		if (!acpi_power_dir)
179 			acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
180 						    acpi_button_dir);
181 		entry = acpi_power_dir;
182 		break;
183 	case ACPI_BUTTON_TYPE_SLEEP:
184 	case ACPI_BUTTON_TYPE_SLEEPF:
185 		if (!acpi_sleep_dir)
186 			acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
187 						    acpi_button_dir);
188 		entry = acpi_sleep_dir;
189 		break;
190 	case ACPI_BUTTON_TYPE_LID:
191 		if (!acpi_lid_dir)
192 			acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
193 						  acpi_button_dir);
194 		entry = acpi_lid_dir;
195 		break;
196 	}
197 
198 	if (!entry)
199 		return -ENODEV;
200 	entry->owner = THIS_MODULE;
201 
202 	acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
203 	if (!acpi_device_dir(device))
204 		return -ENODEV;
205 	acpi_device_dir(device)->owner = THIS_MODULE;
206 
207 	/* 'info' [R] */
208 	entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
209 				  S_IRUGO, acpi_device_dir(device));
210 	if (!entry)
211 		return -ENODEV;
212 	else {
213 		entry->proc_fops = &acpi_button_info_fops;
214 		entry->data = acpi_driver_data(device);
215 		entry->owner = THIS_MODULE;
216 	}
217 
218 	/* show lid state [R] */
219 	if (button->type == ACPI_BUTTON_TYPE_LID) {
220 		entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
221 					  S_IRUGO, acpi_device_dir(device));
222 		if (!entry)
223 			return -ENODEV;
224 		else {
225 			entry->proc_fops = &acpi_button_state_fops;
226 			entry->data = acpi_driver_data(device);
227 			entry->owner = THIS_MODULE;
228 		}
229 	}
230 
231 	return 0;
232 }
233 
234 static int acpi_button_remove_fs(struct acpi_device *device)
235 {
236 	struct acpi_button *button = acpi_driver_data(device);
237 
238 	if (acpi_device_dir(device)) {
239 		if (button->type == ACPI_BUTTON_TYPE_LID)
240 			remove_proc_entry(ACPI_BUTTON_FILE_STATE,
241 					  acpi_device_dir(device));
242 		remove_proc_entry(ACPI_BUTTON_FILE_INFO,
243 				  acpi_device_dir(device));
244 
245 		remove_proc_entry(acpi_device_bid(device),
246 				  acpi_device_dir(device)->parent);
247 		acpi_device_dir(device) = NULL;
248 	}
249 
250 	return 0;
251 }
252 
253 /* --------------------------------------------------------------------------
254                                 Driver Interface
255    -------------------------------------------------------------------------- */
256 
257 static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
258 {
259 	struct acpi_button *button = data;
260 	struct input_dev *input;
261 
262 	if (!button || !button->device)
263 		return;
264 
265 	switch (event) {
266 	case ACPI_BUTTON_NOTIFY_STATUS:
267 		input = button->input;
268 
269 		if (button->type == ACPI_BUTTON_TYPE_LID) {
270 			struct acpi_handle *handle = button->device->handle;
271 			unsigned long state;
272 
273 			if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
274 								NULL, &state)))
275 				input_report_switch(input, SW_LID, !state);
276 
277 		} else {
278 			int keycode = test_bit(KEY_SLEEP, input->keybit) ?
279 						KEY_SLEEP : KEY_POWER;
280 
281 			input_report_key(input, keycode, 1);
282 			input_sync(input);
283 			input_report_key(input, keycode, 0);
284 		}
285 		input_sync(input);
286 
287 		acpi_bus_generate_proc_event(button->device, event,
288 					++button->pushed);
289 		break;
290 	default:
291 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
292 				  "Unsupported event [0x%x]\n", event));
293 		break;
294 	}
295 
296 	return;
297 }
298 
299 static acpi_status acpi_button_notify_fixed(void *data)
300 {
301 	struct acpi_button *button = data;
302 
303 	if (!button)
304 		return AE_BAD_PARAMETER;
305 
306 	acpi_button_notify(button->device->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
307 
308 	return AE_OK;
309 }
310 
311 static int acpi_button_install_notify_handlers(struct acpi_button *button)
312 {
313 	acpi_status status;
314 
315 	switch (button->type) {
316 	case ACPI_BUTTON_TYPE_POWERF:
317 		status =
318 		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
319 						     acpi_button_notify_fixed,
320 						     button);
321 		break;
322 	case ACPI_BUTTON_TYPE_SLEEPF:
323 		status =
324 		    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
325 						     acpi_button_notify_fixed,
326 						     button);
327 		break;
328 	default:
329 		status = acpi_install_notify_handler(button->device->handle,
330 						     ACPI_DEVICE_NOTIFY,
331 						     acpi_button_notify,
332 						     button);
333 		break;
334 	}
335 
336 	return ACPI_FAILURE(status) ? -ENODEV : 0;
337 }
338 
339 static void acpi_button_remove_notify_handlers(struct acpi_button *button)
340 {
341 	switch (button->type) {
342 	case ACPI_BUTTON_TYPE_POWERF:
343 		acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
344 						acpi_button_notify_fixed);
345 		break;
346 	case ACPI_BUTTON_TYPE_SLEEPF:
347 		acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
348 						acpi_button_notify_fixed);
349 		break;
350 	default:
351 		acpi_remove_notify_handler(button->device->handle,
352 					   ACPI_DEVICE_NOTIFY,
353 					   acpi_button_notify);
354 		break;
355 	}
356 }
357 
358 static int acpi_button_add(struct acpi_device *device)
359 {
360 	int error;
361 	struct acpi_button *button;
362 	struct input_dev *input;
363 
364 	if (!device)
365 		return -EINVAL;
366 
367 	button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
368 	if (!button)
369 		return -ENOMEM;
370 
371 	button->device = device;
372 	acpi_driver_data(device) = button;
373 
374 	button->input = input = input_allocate_device();
375 	if (!input) {
376 		error = -ENOMEM;
377 		goto err_free_button;
378 	}
379 
380 	/*
381 	 * Determine the button type (via hid), as fixed-feature buttons
382 	 * need to be handled a bit differently than generic-space.
383 	 */
384 	if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
385 		button->type = ACPI_BUTTON_TYPE_POWER;
386 		strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_POWER);
387 		sprintf(acpi_device_class(device), "%s/%s",
388 			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
389 	} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
390 		button->type = ACPI_BUTTON_TYPE_POWERF;
391 		strcpy(acpi_device_name(device),
392 		       ACPI_BUTTON_DEVICE_NAME_POWERF);
393 		sprintf(acpi_device_class(device), "%s/%s",
394 			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
395 	} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
396 		button->type = ACPI_BUTTON_TYPE_SLEEP;
397 		strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_SLEEP);
398 		sprintf(acpi_device_class(device), "%s/%s",
399 			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
400 	} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
401 		button->type = ACPI_BUTTON_TYPE_SLEEPF;
402 		strcpy(acpi_device_name(device),
403 		       ACPI_BUTTON_DEVICE_NAME_SLEEPF);
404 		sprintf(acpi_device_class(device), "%s/%s",
405 			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
406 	} else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
407 		button->type = ACPI_BUTTON_TYPE_LID;
408 		strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_LID);
409 		sprintf(acpi_device_class(device), "%s/%s",
410 			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
411 	} else {
412 		printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
413 			    acpi_device_hid(device));
414 		error = -ENODEV;
415 		goto err_free_input;
416 	}
417 
418 	error = acpi_button_add_fs(device);
419 	if (error)
420 		goto err_free_input;
421 
422 	error = acpi_button_install_notify_handlers(button);
423 	if (error)
424 		goto err_remove_fs;
425 
426 	snprintf(button->phys, sizeof(button->phys),
427 		 "%s/button/input0", acpi_device_hid(device));
428 
429 	input->name = acpi_device_name(device);
430 	input->phys = button->phys;
431 	input->id.bustype = BUS_HOST;
432 	input->id.product = button->type;
433 
434 	switch (button->type) {
435 	case ACPI_BUTTON_TYPE_POWER:
436 	case ACPI_BUTTON_TYPE_POWERF:
437 		input->evbit[0] = BIT(EV_KEY);
438 		set_bit(KEY_POWER, input->keybit);
439 		break;
440 
441 	case ACPI_BUTTON_TYPE_SLEEP:
442 	case ACPI_BUTTON_TYPE_SLEEPF:
443 		input->evbit[0] = BIT(EV_KEY);
444 		set_bit(KEY_SLEEP, input->keybit);
445 		break;
446 
447 	case ACPI_BUTTON_TYPE_LID:
448 		input->evbit[0] = BIT(EV_SW);
449 		set_bit(SW_LID, input->swbit);
450 		break;
451 	}
452 
453 	error = input_register_device(input);
454 	if (error)
455 		goto err_remove_handlers;
456 
457 	if (device->wakeup.flags.valid) {
458 		/* Button's GPE is run-wake GPE */
459 		acpi_set_gpe_type(device->wakeup.gpe_device,
460 				  device->wakeup.gpe_number,
461 				  ACPI_GPE_TYPE_WAKE_RUN);
462 		acpi_enable_gpe(device->wakeup.gpe_device,
463 				device->wakeup.gpe_number, ACPI_NOT_ISR);
464 		device->wakeup.state.enabled = 1;
465 	}
466 
467 	printk(KERN_INFO PREFIX "%s [%s]\n",
468 	       acpi_device_name(device), acpi_device_bid(device));
469 
470 	return 0;
471 
472  err_remove_handlers:
473 	acpi_button_remove_notify_handlers(button);
474  err_remove_fs:
475 	acpi_button_remove_fs(device);
476  err_free_input:
477 	input_free_device(input);
478  err_free_button:
479 	kfree(button);
480 	return error;
481 }
482 
483 static int acpi_button_remove(struct acpi_device *device, int type)
484 {
485 	struct acpi_button *button;
486 
487 	if (!device || !acpi_driver_data(device))
488 		return -EINVAL;
489 
490 	button = acpi_driver_data(device);
491 
492 	acpi_button_remove_notify_handlers(button);
493 	acpi_button_remove_fs(device);
494 	input_unregister_device(button->input);
495 	kfree(button);
496 
497 	return 0;
498 }
499 
500 static int __init acpi_button_init(void)
501 {
502 	int result;
503 
504 	acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
505 	if (!acpi_button_dir)
506 		return -ENODEV;
507 	acpi_button_dir->owner = THIS_MODULE;
508 	result = acpi_bus_register_driver(&acpi_button_driver);
509 	if (result < 0) {
510 		remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
511 		return -ENODEV;
512 	}
513 
514 	return 0;
515 }
516 
517 static void __exit acpi_button_exit(void)
518 {
519 	acpi_bus_unregister_driver(&acpi_button_driver);
520 
521 	if (acpi_power_dir)
522 		remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir);
523 	if (acpi_sleep_dir)
524 		remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir);
525 	if (acpi_lid_dir)
526 		remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
527 	remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
528 }
529 
530 module_init(acpi_button_init);
531 module_exit(acpi_button_exit);
532