ac.c revision 27663c5855b10af9ec67bc7dfba001426ba21222
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>
30fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
338a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
3497749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
35d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy#include <linux/power_supply.h>
3697749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_COMPONENT		0x00020000
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_CLASS			"ac_adapter"
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_DEVICE_NAME		"AC Adapter"
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_FILE_STATE		"state"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_NOTIFY_STATUS		0x80
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_STATUS_OFFLINE		0x00
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_STATUS_ONLINE		0x01
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_AC_STATUS_UNKNOWN		0xFF
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT		ACPI_AC_COMPONENT
50f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("ac");
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownMODULE_AUTHOR("Paul Diefenbaugh");
537cda93e008e1a477970adbf82dba81a5d4f0ae40Len BrownMODULE_DESCRIPTION("ACPI AC Adapter Driver");
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
573f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendextern struct proc_dir_entry *acpi_lock_ac_dir(void);
583f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendextern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
598a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkovstatic int acpi_ac_open_fs(struct inode *inode, struct file *file);
608a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
613f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_add(struct acpi_device *device);
634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_remove(struct acpi_device *device, int type);
645bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiystatic int acpi_ac_resume(struct acpi_device *device);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66b299c22c8c1024a5a89d19524e24b3e1d67e9eabTobias Klauserstatic const struct acpi_device_id ac_device_ids[] = {
671ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"ACPI0003", 0},
681ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"", 0},
691ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger};
701ba90e3a87c46500623afdc3898573e4a5ebb21bThomas RenningerMODULE_DEVICE_TABLE(acpi, ac_device_ids);
711ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_ac_driver = {
73c2b6705b75d9c7aff98a4602a32230639e10891cLen Brown	.name = "ac",
744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.class = ACPI_AC_CLASS,
751ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	.ids = ac_device_ids,
764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.ops = {
774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		.add = acpi_ac_add,
784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		.remove = acpi_ac_remove,
795bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy		.resume = acpi_ac_resume,
804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		},
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_ac {
8497749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
85d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	struct power_supply charger;
8697749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
87af96179a8298832cc58be212d0e4988d8a1e11bfPatrick Mochel	struct acpi_device * device;
8827663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox	unsigned long long state;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
92d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy
93fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
94d75080328affb4b268da430b7074cc8139cc662aArjan van de Venstatic const struct file_operations acpi_ac_fops = {
95cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	.owner = THIS_MODULE,
964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.open = acpi_ac_open_fs,
974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.read = seq_read,
984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.llseek = seq_lseek,
994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.release = single_release,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1018a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
10297749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
103d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiystatic int get_ac_property(struct power_supply *psy,
104d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy			   enum power_supply_property psp,
105d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy			   union power_supply_propval *val)
106d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy{
107d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	struct acpi_ac *ac = to_acpi_ac(psy);
108d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	switch (psp) {
109d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	case POWER_SUPPLY_PROP_ONLINE:
110d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy		val->intval = ac->state;
111d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy		break;
112d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	default:
113d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy		return -EINVAL;
114d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	}
115d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	return 0;
116d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy}
117d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy
118d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiystatic enum power_supply_property ac_props[] = {
119d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	POWER_SUPPLY_PROP_ONLINE,
120d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy};
12197749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                               AC Adapter Management
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_get_state(struct acpi_ac *ac)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
132d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134a6ba5ebef91a59fabd45962e576c02468dbcd33fPatrick Mochel	status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, &ac->state);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
136a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Error reading AC Adapter state"));
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ac->state = ACPI_AC_STATUS_UNKNOWN;
138d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
141d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                              FS Interface (/proc)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic struct proc_dir_entry *acpi_ac_dir;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_ac_seq_show(struct seq_file *seq, void *offset)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15350dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_ac *ac = seq->private;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
157d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_ac_get_state(ac)) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
161d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_puts(seq, "state:                   ");
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ac->state) {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_AC_STATUS_OFFLINE:
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "off-line\n");
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_AC_STATUS_ONLINE:
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "on-line\n");
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "unknown\n");
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
177d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_ac_open_fs(struct inode *inode, struct file *file)
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return single_open(file, acpi_ac_seq_show, PDE(inode)->data);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_add_fs(struct acpi_device *device)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1874be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct proc_dir_entry *entry = NULL;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!acpi_device_dir(device)) {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown						     acpi_ac_dir);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!acpi_device_dir(device))
194d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return -ENODEV;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_device_dir(device)->owner = THIS_MODULE;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 'state' [R] */
199cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	entry = proc_create_data(ACPI_AC_FILE_STATE,
200cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev				 S_IRUGO, acpi_device_dir(device),
201cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev				 &acpi_ac_fops, acpi_driver_data(device));
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!entry)
203d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
204d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_remove_fs(struct acpi_device *device)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_device_dir(device)) {
2114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		remove_proc_entry(ACPI_AC_FILE_STATE, acpi_device_dir(device));
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_device_dir(device) = NULL;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2198a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                   Driver Model
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22750dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_ac *ac = data;
2284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_device *device = NULL;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
232d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
234af96179a8298832cc58be212d0e4988d8a1e11bfPatrick Mochel	device = ac->device;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (event) {
236f163ff5176a8e9c827d8ebe044710d67d40799c3Len Brown	default:
237f163ff5176a8e9c827d8ebe044710d67d40799c3Len Brown		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
238f163ff5176a8e9c827d8ebe044710d67d40799c3Len Brown				  "Unsupported event [0x%x]\n", event));
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_AC_NOTIFY_STATUS:
24003d782524e2d0511317769521c8d5daadbab8482Christian Lupien	case ACPI_NOTIFY_BUS_CHECK:
24103d782524e2d0511317769521c8d5daadbab8482Christian Lupien	case ACPI_NOTIFY_DEVICE_CHECK:
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_ac_get_state(ac);
24314e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown		acpi_bus_generate_proc_event(device, event, (u32) ac->state);
244962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui		acpi_bus_generate_netlink_event(device->pnp.device_class,
245962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui						  device->dev.bus_id, event,
246962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui						  (u32) ac->state);
24797749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
248d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy		kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
24997749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
252d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_add(struct acpi_device *device)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
2584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
2594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_ac *ac = NULL;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!device)
263d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26536bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ac)
267d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269af96179a8298832cc58be212d0e4988d8a1e11bfPatrick Mochel	ac->device = device;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_class(device), ACPI_AC_CLASS);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_driver_data(device) = ac;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_ac_get_state(ac);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
278fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_ac_add_fs(device);
2808a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
28397749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
284d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	ac->charger.name = acpi_device_bid(device);
285d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
286d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	ac->charger.properties = ac_props;
287d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	ac->charger.num_properties = ARRAY_SIZE(ac_props);
288d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	ac->charger.get_property = get_ac_property;
289d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	power_supply_register(&ac->device->dev, &ac->charger);
29097749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
291a6ba5ebef91a59fabd45962e576c02468dbcd33fPatrick Mochel	status = acpi_install_notify_handler(device->handle,
29203d782524e2d0511317769521c8d5daadbab8482Christian Lupien					     ACPI_ALL_NOTIFY, acpi_ac_notify,
2934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					     ac);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
3004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	       acpi_device_name(device), acpi_device_bid(device),
3014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	       ac->state ? "on-line" : "off-line");
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
305fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_ac_remove_fs(device);
3078a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(ac);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3145bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiystatic int acpi_ac_resume(struct acpi_device *device)
3155bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy{
3165bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	struct acpi_ac *ac;
3175bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	unsigned old_state;
3185bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	if (!device || !acpi_driver_data(device))
3195bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy		return -EINVAL;
3205bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	ac = acpi_driver_data(device);
3215bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	old_state = ac->state;
3225bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	if (acpi_ac_get_state(ac))
3235bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy		return 0;
32497749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
3255bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	if (old_state != ac->state)
3265bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy		kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
32797749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
3285bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy	return 0;
3295bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy}
3305bfeca3138a6031e38c566d57128ff592eb009a8Alexey Starikovskiy
3314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_ac_remove(struct acpi_device *device, int type)
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
3344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_ac *ac = NULL;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!device || !acpi_driver_data(device))
338d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34050dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	ac = acpi_driver_data(device);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
342a6ba5ebef91a59fabd45962e576c02468dbcd33fPatrick Mochel	status = acpi_remove_notify_handler(device->handle,
34303d782524e2d0511317769521c8d5daadbab8482Christian Lupien					    ACPI_ALL_NOTIFY, acpi_ac_notify);
34497749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#ifdef CONFIG_ACPI_SYSFS_POWER
345d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy	if (ac->charger.dev)
346d5b4a3d0efa36de31b86d5677dad6c36cb8735d7Alexey Starikovskiy		power_supply_unregister(&ac->charger);
34797749cd9adbb2985e4b2aee1a59d6b970fe9c3a7Alexey Starikovskiy#endif
348fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_ac_remove_fs(device);
3508a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(ac);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
354d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int __init acpi_ac_init(void)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3593f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int result;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3614d8316d5ea4dcf0bf15d8a06d539ed7c99e9cfbePavel Machek	if (acpi_disabled)
3624d8316d5ea4dcf0bf15d8a06d539ed7c99e9cfbePavel Machek		return -ENODEV;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
364fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
3653f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	acpi_ac_dir = acpi_lock_ac_dir();
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!acpi_ac_dir)
367d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
3688a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_bus_register_driver(&acpi_ac_driver);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result < 0) {
372fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
3733f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		acpi_unlock_ac_dir(acpi_ac_dir);
3748a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
375d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
378d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic void __exit acpi_ac_exit(void)
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_bus_unregister_driver(&acpi_ac_driver);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
386fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
3873f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	acpi_unlock_ac_dir(acpi_ac_dir);
3888a246ee43f4b1df3fa5cbf9c4a3d3dcad0b1e08cAndrey Borzenkov#endif
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
390d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(acpi_ac_init);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(acpi_ac_exit);
395