PageRenderTime 32ms CodeModel.GetById 18ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/acpi/ac.c

https://bitbucket.org/evzijst/gittest
C | 354 lines | 243 code | 77 blank | 34 comment | 24 complexity | db4bfa159f196713f2ce0ee401505b11 MD5 | raw file
  1/*
  2 *  acpi_ac.c - ACPI AC Adapter Driver ($Revision: 27 $)
  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 <acpi/acpi_bus.h>
 33#include <acpi/acpi_drivers.h>
 34
 35
 36#define ACPI_AC_COMPONENT		0x00020000
 37#define ACPI_AC_CLASS			"ac_adapter"
 38#define ACPI_AC_HID 			"ACPI0003"
 39#define ACPI_AC_DRIVER_NAME		"ACPI AC Adapter Driver"
 40#define ACPI_AC_DEVICE_NAME		"AC Adapter"
 41#define ACPI_AC_FILE_STATE		"state"
 42#define ACPI_AC_NOTIFY_STATUS		0x80
 43#define ACPI_AC_STATUS_OFFLINE		0x00
 44#define ACPI_AC_STATUS_ONLINE		0x01
 45#define ACPI_AC_STATUS_UNKNOWN		0xFF
 46
 47#define _COMPONENT		ACPI_AC_COMPONENT
 48ACPI_MODULE_NAME		("acpi_ac")
 49
 50MODULE_AUTHOR("Paul Diefenbaugh");
 51MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
 52MODULE_LICENSE("GPL");
 53
 54static int acpi_ac_add (struct acpi_device *device);
 55static int acpi_ac_remove (struct acpi_device *device, int type);
 56static int acpi_ac_open_fs(struct inode *inode, struct file *file);
 57
 58static struct acpi_driver acpi_ac_driver = {
 59	.name =		ACPI_AC_DRIVER_NAME,
 60	.class =	ACPI_AC_CLASS,
 61	.ids =		ACPI_AC_HID,
 62	.ops =		{
 63				.add =		acpi_ac_add,
 64				.remove =	acpi_ac_remove,
 65			},
 66};
 67
 68struct acpi_ac {
 69	acpi_handle		handle;
 70	unsigned long		state;
 71};
 72
 73static struct file_operations acpi_ac_fops = {
 74	.open		= acpi_ac_open_fs,
 75	.read		= seq_read,
 76	.llseek		= seq_lseek,
 77	.release	= single_release,
 78};
 79
 80/* --------------------------------------------------------------------------
 81                               AC Adapter Management
 82   -------------------------------------------------------------------------- */
 83
 84static int
 85acpi_ac_get_state (
 86	struct acpi_ac		*ac)
 87{
 88	acpi_status		status = AE_OK;
 89
 90	ACPI_FUNCTION_TRACE("acpi_ac_get_state");
 91
 92	if (!ac)
 93		return_VALUE(-EINVAL);
 94
 95	status = acpi_evaluate_integer(ac->handle, "_PSR", NULL, &ac->state);
 96	if (ACPI_FAILURE(status)) {
 97		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 98			"Error reading AC Adapter state\n"));
 99		ac->state = ACPI_AC_STATUS_UNKNOWN;
100		return_VALUE(-ENODEV);
101	}
102	
103	return_VALUE(0);
104}
105
106
107/* --------------------------------------------------------------------------
108                              FS Interface (/proc)
109   -------------------------------------------------------------------------- */
110
111static struct proc_dir_entry	*acpi_ac_dir;
112
113static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
114{
115	struct acpi_ac		*ac = (struct acpi_ac *) seq->private;
116
117	ACPI_FUNCTION_TRACE("acpi_ac_seq_show");
118
119	if (!ac)
120		return_VALUE(0);
121
122	if (acpi_ac_get_state(ac)) {
123		seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
124		return_VALUE(0);
125	}
126
127	seq_puts(seq, "state:                   ");
128	switch (ac->state) {
129	case ACPI_AC_STATUS_OFFLINE:
130		seq_puts(seq, "off-line\n");
131		break;
132	case ACPI_AC_STATUS_ONLINE:
133		seq_puts(seq, "on-line\n");
134		break;
135	default:
136		seq_puts(seq, "unknown\n");
137		break;
138	}
139
140	return_VALUE(0);
141}
142	
143static int acpi_ac_open_fs(struct inode *inode, struct file *file)
144{
145	return single_open(file, acpi_ac_seq_show, PDE(inode)->data);
146}
147
148static int
149acpi_ac_add_fs (
150	struct acpi_device	*device)
151{
152	struct proc_dir_entry	*entry = NULL;
153
154	ACPI_FUNCTION_TRACE("acpi_ac_add_fs");
155
156	if (!acpi_device_dir(device)) {
157		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
158			acpi_ac_dir);
159		if (!acpi_device_dir(device))
160			return_VALUE(-ENODEV);
161		acpi_device_dir(device)->owner = THIS_MODULE;
162	}
163
164	/* 'state' [R] */
165	entry = create_proc_entry(ACPI_AC_FILE_STATE,
166		S_IRUGO, acpi_device_dir(device));
167	if (!entry)
168		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
169			"Unable to create '%s' fs entry\n",
170			ACPI_AC_FILE_STATE));
171	else {
172		entry->proc_fops = &acpi_ac_fops;
173		entry->data = acpi_driver_data(device);
174		entry->owner = THIS_MODULE;
175	}
176
177	return_VALUE(0);
178}
179
180
181static int
182acpi_ac_remove_fs (
183	struct acpi_device	*device)
184{
185	ACPI_FUNCTION_TRACE("acpi_ac_remove_fs");
186
187	if (acpi_device_dir(device)) {
188		remove_proc_entry(ACPI_AC_FILE_STATE,
189				  acpi_device_dir(device));
190
191		remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
192		acpi_device_dir(device) = NULL;
193	}
194
195	return_VALUE(0);
196}
197
198
199/* --------------------------------------------------------------------------
200                                   Driver Model
201   -------------------------------------------------------------------------- */
202
203static void
204acpi_ac_notify (
205	acpi_handle		handle,
206	u32			event,
207	void			*data)
208{
209	struct acpi_ac		*ac = (struct acpi_ac *) data;
210	struct acpi_device	*device = NULL;
211
212	ACPI_FUNCTION_TRACE("acpi_ac_notify");
213
214	if (!ac)
215		return_VOID;
216
217	if (acpi_bus_get_device(ac->handle, &device))
218		return_VOID;
219
220	switch (event) {
221	case ACPI_AC_NOTIFY_STATUS:
222		acpi_ac_get_state(ac);
223		acpi_bus_generate_event(device, event, (u32) ac->state);
224		break;
225	default:
226		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
227			"Unsupported event [0x%x]\n", event));
228		break;
229	}
230
231	return_VOID;
232}
233
234
235static int
236acpi_ac_add (
237	struct acpi_device	*device)
238{
239	int			result = 0;
240	acpi_status		status = AE_OK;
241	struct acpi_ac		*ac = NULL;
242
243	ACPI_FUNCTION_TRACE("acpi_ac_add");
244
245	if (!device)
246		return_VALUE(-EINVAL);
247
248	ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
249	if (!ac)
250		return_VALUE(-ENOMEM);
251	memset(ac, 0, sizeof(struct acpi_ac));
252
253	ac->handle = device->handle;
254	strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
255	strcpy(acpi_device_class(device), ACPI_AC_CLASS);
256	acpi_driver_data(device) = ac;
257
258	result = acpi_ac_get_state(ac);
259	if (result)
260		goto end;
261
262	result = acpi_ac_add_fs(device);
263	if (result)
264		goto end;
265
266	status = acpi_install_notify_handler(ac->handle,
267		ACPI_DEVICE_NOTIFY, acpi_ac_notify, ac);
268	if (ACPI_FAILURE(status)) {
269		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
270			"Error installing notify handler\n"));
271		result = -ENODEV;
272		goto end;
273	}
274
275	printk(KERN_INFO PREFIX "%s [%s] (%s)\n", 
276		acpi_device_name(device), acpi_device_bid(device), 
277		ac->state?"on-line":"off-line");
278
279end:
280	if (result) {
281		acpi_ac_remove_fs(device);
282		kfree(ac);
283	}
284
285	return_VALUE(result);
286}
287
288
289static int
290acpi_ac_remove (
291	struct acpi_device	*device,
292	int			type)
293{
294	acpi_status		status = AE_OK;
295	struct acpi_ac		*ac = NULL;
296
297	ACPI_FUNCTION_TRACE("acpi_ac_remove");
298
299	if (!device || !acpi_driver_data(device))
300		return_VALUE(-EINVAL);
301
302	ac = (struct acpi_ac *) acpi_driver_data(device);
303
304	status = acpi_remove_notify_handler(ac->handle,
305		ACPI_DEVICE_NOTIFY, acpi_ac_notify);
306	if (ACPI_FAILURE(status))
307		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
308			"Error removing notify handler\n"));
309
310	acpi_ac_remove_fs(device);
311
312	kfree(ac);
313
314	return_VALUE(0);
315}
316
317
318static int __init
319acpi_ac_init (void)
320{
321	int			result = 0;
322
323	ACPI_FUNCTION_TRACE("acpi_ac_init");
324
325	acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
326	if (!acpi_ac_dir)
327		return_VALUE(-ENODEV);
328	acpi_ac_dir->owner = THIS_MODULE;
329
330	result = acpi_bus_register_driver(&acpi_ac_driver);
331	if (result < 0) {
332		remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
333		return_VALUE(-ENODEV);
334	}
335
336	return_VALUE(0);
337}
338
339
340static void __exit
341acpi_ac_exit (void)
342{
343	ACPI_FUNCTION_TRACE("acpi_ac_exit");
344
345	acpi_bus_unregister_driver(&acpi_ac_driver);
346
347	remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
348
349	return_VOID;
350}
351
352
353module_init(acpi_ac_init);
354module_exit(acpi_ac_exit);