ac.c revision a6ba5ebef91a59fabd45962e576c02468dbcd33f
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  acpi_ac.c - ACPI AC Adapter Driver ($Revision: 27 $)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the Free Software Foundation; either version 2 of the License, or (at
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is distributed in the hope that it will be useful, but
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  WITHOUT ANY WARRANTY; without even the implied warranty of
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  General Public License for more details.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  You should have received a copy of the GNU General Public License along
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  with this program; if not, write to the Free Software Foundation, Inc.,
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_COMPONENT		0x00020000
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_CLASS			"ac_adapter"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_HID 			"ACPI0003"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_DRIVER_NAME		"ACPI AC Adapter Driver"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_DEVICE_NAME		"AC Adapter"
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_FILE_STATE		"state"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_NOTIFY_STATUS		0x80
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_STATUS_OFFLINE		0x00
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_STATUS_ONLINE		0x01
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_STATUS_UNKNOWN		0xFF
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT		ACPI_AC_COMPONENT
474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen BrownACPI_MODULE_NAME("acpi_ac")
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown    MODULE_AUTHOR("Paul Diefenbaugh");
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_add(struct acpi_device *device);
544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_remove(struct acpi_device *device, int type);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_ac_open_fs(struct inode *inode, struct file *file);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_ac_driver = {
584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.name = ACPI_AC_DRIVER_NAME,
594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.class = ACPI_AC_CLASS,
604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.ids = ACPI_AC_HID,
614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.ops = {
624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		.add = acpi_ac_add,
634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		.remove = acpi_ac_remove,
644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		},
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_ac {
684be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_handle handle;
69af96179a8298832cc58be212d0e4988d8a1e11bfPatrick Mochel	struct acpi_device * device;
704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	unsigned long state;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations acpi_ac_fops = {
744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.open = acpi_ac_open_fs,
754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.read = seq_read,
764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.llseek = seq_lseek,
774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.release = single_release,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                               AC Adapter Management
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_get_state(struct acpi_ac *ac)
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
90d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92a6ba5ebef91a59fabd45962e576c02468dbcd33fPatrick Mochel	status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, &ac->state);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
94a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Error reading AC Adapter state"));
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ac->state = ACPI_AC_STATUS_UNKNOWN;
96d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
99d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              FS Interface (/proc)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic struct proc_dir_entry *acpi_ac_dir;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_ac_seq_show(struct seq_file *seq, void *offset)
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_ac *ac = (struct acpi_ac *)seq->private;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
114d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_ac_get_state(ac)) {
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
118d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_puts(seq, "state:                   ");
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ac->state) {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_AC_STATUS_OFFLINE:
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "off-line\n");
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_AC_STATUS_ONLINE:
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "on-line\n");
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "unknown\n");
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_ac_open_fs(struct inode *inode, struct file *file)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return single_open(file, acpi_ac_seq_show, PDE(inode)->data);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_add_fs(struct acpi_device *device)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct proc_dir_entry *entry = NULL;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!acpi_device_dir(device)) {
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown						     acpi_ac_dir);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!acpi_device_dir(device))
151d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return -ENODEV;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_device_dir(device)->owner = THIS_MODULE;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 'state' [R] */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = create_proc_entry(ACPI_AC_FILE_STATE,
1574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				  S_IRUGO, acpi_device_dir(device));
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!entry)
159d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry->proc_fops = &acpi_ac_fops;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry->data = acpi_driver_data(device);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry->owner = THIS_MODULE;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
166d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_remove_fs(struct acpi_device *device)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_device_dir(device)) {
1734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		remove_proc_entry(ACPI_AC_FILE_STATE, acpi_device_dir(device));
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_device_dir(device) = NULL;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
179d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                   Driver Model
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1884be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_ac *ac = (struct acpi_ac *)data;
1894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_device *device = NULL;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
193d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
195af96179a8298832cc58be212d0e4988d8a1e11bfPatrick Mochel	device = ac->device;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (event) {
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_AC_NOTIFY_STATUS:
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_ac_get_state(ac);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_bus_generate_event(device, event, (u32) ac->state);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
2034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				  "Unsupported event [0x%x]\n", event));
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_add(struct acpi_device *device)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
2134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
2144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_ac *ac = NULL;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!device)
218d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
222d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ac, 0, sizeof(struct acpi_ac));
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ac->handle = device->handle;
226af96179a8298832cc58be212d0e4988d8a1e11bfPatrick Mochel	ac->device = device;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_class(device), ACPI_AC_CLASS);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_driver_data(device) = ac;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_ac_get_state(ac);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_ac_add_fs(device);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
239a6ba5ebef91a59fabd45962e576c02468dbcd33fPatrick Mochel	status = acpi_install_notify_handler(device->handle,
2404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					     ACPI_DEVICE_NOTIFY, acpi_ac_notify,
2414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					     ac);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
2484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	       acpi_device_name(device), acpi_device_bid(device),
2494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	       ac->state ? "on-line" : "off-line");
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_ac_remove_fs(device);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(ac);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
257d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_remove(struct acpi_device *device, int type)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
2634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_ac *ac = NULL;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!device || !acpi_driver_data(device))
267d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	ac = (struct acpi_ac *)acpi_driver_data(device);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271a6ba5ebef91a59fabd45962e576c02468dbcd33fPatrick Mochel	status = acpi_remove_notify_handler(device->handle,
2724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					    ACPI_DEVICE_NOTIFY, acpi_ac_notify);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_ac_remove_fs(device);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(ac);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
278d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int __init acpi_ac_init(void)
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!acpi_ac_dir)
288d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_ac_dir->owner = THIS_MODULE;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_bus_register_driver(&acpi_ac_driver);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result < 0) {
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
294d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
297d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic void __exit acpi_ac_exit(void)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_bus_unregister_driver(&acpi_ac_driver);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
307d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(acpi_ac_init);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(acpi_ac_exit);
312