bus.c 18.2 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 *  acpi_bus.c - ACPI Bus Driver ($Revision: 80 $)
 *
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pm.h>
31
#include <linux/pm_legacy.h>
Linus Torvalds's avatar
Linus Torvalds committed
32
33
34
35
36
37
38
39
40
#include <linux/device.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_X86
#include <asm/mpspec.h>
#endif
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>

#define _COMPONENT		ACPI_BUS_COMPONENT
Len Brown's avatar
Len Brown committed
41
ACPI_MODULE_NAME("acpi_bus")
Linus Torvalds's avatar
Linus Torvalds committed
42
43
44
45
#ifdef	CONFIG_X86
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif

Bob Moore's avatar
Bob Moore committed
46
struct fadt_descriptor acpi_fadt;
Linus Torvalds's avatar
Linus Torvalds committed
47
48
EXPORT_SYMBOL(acpi_fadt);

Len Brown's avatar
Len Brown committed
49
50
struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
Linus Torvalds's avatar
Linus Torvalds committed
51
52
53
54
55
56
57
58
EXPORT_SYMBOL(acpi_root_dir);

#define STRUCT_TO_INT(s)	(*((int*)&s))

/* --------------------------------------------------------------------------
                                Device Management
   -------------------------------------------------------------------------- */

Len Brown's avatar
Len Brown committed
59
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
Linus Torvalds's avatar
Linus Torvalds committed
60
{
Len Brown's avatar
Len Brown committed
61
	acpi_status status = AE_OK;
Linus Torvalds's avatar
Linus Torvalds committed
62
63
64


	if (!device)
65
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
66
67
68

	/* TBD: Support fixed-feature devices */

Len Brown's avatar
Len Brown committed
69
	status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
Linus Torvalds's avatar
Linus Torvalds committed
70
	if (ACPI_FAILURE(status) || !*device) {
71
		ACPI_EXCEPTION((AE_INFO, status, "No context for object [%p]", handle));
72
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
73
74
	}

75
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
76
}
Len Brown's avatar
Len Brown committed
77

Linus Torvalds's avatar
Linus Torvalds committed
78
79
EXPORT_SYMBOL(acpi_bus_get_device);

Len Brown's avatar
Len Brown committed
80
int acpi_bus_get_status(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
81
{
Len Brown's avatar
Len Brown committed
82
83
84
	acpi_status status = AE_OK;
	unsigned long sta = 0;

Linus Torvalds's avatar
Linus Torvalds committed
85
86

	if (!device)
87
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
88
89
90
91
92

	/*
	 * Evaluate _STA if present.
	 */
	if (device->flags.dynamic_status) {
Len Brown's avatar
Len Brown committed
93
94
		status =
		    acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
Linus Torvalds's avatar
Linus Torvalds committed
95
		if (ACPI_FAILURE(status))
96
			return -ENODEV;
Len Brown's avatar
Len Brown committed
97
		STRUCT_TO_INT(device->status) = (int)sta;
Linus Torvalds's avatar
Linus Torvalds committed
98
99
100
101
102
103
104
105
106
107
108
109
110
	}

	/*
	 * Otherwise we assume the status of our parent (unless we don't
	 * have one, in which case status is implied).
	 */
	else if (device->parent)
		device->status = device->parent->status;
	else
		STRUCT_TO_INT(device->status) = 0x0F;

	if (device->status.functional && !device->status.present) {
		printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
Len Brown's avatar
Len Brown committed
111
112
		       "functional but not present; setting present\n",
		       device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
Linus Torvalds's avatar
Linus Torvalds committed
113
114
115
		device->status.present = 1;
	}

Len Brown's avatar
Len Brown committed
116
117
118
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
			  device->pnp.bus_id,
			  (u32) STRUCT_TO_INT(device->status)));
Linus Torvalds's avatar
Linus Torvalds committed
119

120
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
121
122
}

Len Brown's avatar
Len Brown committed
123
EXPORT_SYMBOL(acpi_bus_get_status);
Linus Torvalds's avatar
Linus Torvalds committed
124
125
126
127
128

/* --------------------------------------------------------------------------
                                 Power Management
   -------------------------------------------------------------------------- */

Len Brown's avatar
Len Brown committed
129
int acpi_bus_get_power(acpi_handle handle, int *state)
Linus Torvalds's avatar
Linus Torvalds committed
130
{
Len Brown's avatar
Len Brown committed
131
132
133
134
	int result = 0;
	acpi_status status = 0;
	struct acpi_device *device = NULL;
	unsigned long psc = 0;
Linus Torvalds's avatar
Linus Torvalds committed
135
136
137
138


	result = acpi_bus_get_device(handle, &device);
	if (result)
139
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
140
141
142
143
144
145
146
147
148

	*state = ACPI_STATE_UNKNOWN;

	if (!device->flags.power_manageable) {
		/* TBD: Non-recursive algorithm for walking up hierarchy */
		if (device->parent)
			*state = device->parent->power.state;
		else
			*state = ACPI_STATE_D0;
Len Brown's avatar
Len Brown committed
149
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
150
151
152
153
154
		/*
		 * Get the device's power state either directly (via _PSC) or 
		 * indirectly (via power resources).
		 */
		if (device->power.flags.explicit_get) {
Len Brown's avatar
Len Brown committed
155
156
			status = acpi_evaluate_integer(device->handle, "_PSC",
						       NULL, &psc);
Linus Torvalds's avatar
Linus Torvalds committed
157
			if (ACPI_FAILURE(status))
158
				return -ENODEV;
Len Brown's avatar
Len Brown committed
159
160
			device->power.state = (int)psc;
		} else if (device->power.flags.power_resources) {
Linus Torvalds's avatar
Linus Torvalds committed
161
162
			result = acpi_power_get_inferred_state(device);
			if (result)
163
				return result;
Linus Torvalds's avatar
Linus Torvalds committed
164
165
166
167
168
169
		}

		*state = device->power.state;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
Len Brown's avatar
Len Brown committed
170
			  device->pnp.bus_id, device->power.state));
Linus Torvalds's avatar
Linus Torvalds committed
171

172
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
173
174
}

Len Brown's avatar
Len Brown committed
175
EXPORT_SYMBOL(acpi_bus_get_power);
Linus Torvalds's avatar
Linus Torvalds committed
176

Len Brown's avatar
Len Brown committed
177
int acpi_bus_set_power(acpi_handle handle, int state)
Linus Torvalds's avatar
Linus Torvalds committed
178
{
Len Brown's avatar
Len Brown committed
179
180
181
182
	int result = 0;
	acpi_status status = AE_OK;
	struct acpi_device *device = NULL;
	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
Linus Torvalds's avatar
Linus Torvalds committed
183
184
185
186


	result = acpi_bus_get_device(handle, &device);
	if (result)
187
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
188
189

	if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
190
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
191
192
193
194

	/* Make sure this is a valid target state */

	if (!device->flags.power_manageable) {
195
		printk(KERN_DEBUG "Device `[%s]' is not power manageable",
196
				device->kobj.name);
197
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
198
	}
199
200
201
202
	/*
	 * Get device's current power state if it's unknown
	 * This means device power state isn't initialized or previous setting failed
	 */
203
204
205
206
207
208
	if (!device->flags.force_power_state) {
		if (device->power.state == ACPI_STATE_UNKNOWN)
			acpi_bus_get_power(device->handle, &device->power.state);
		if (state == device->power.state) {
			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
					  state));
209
			return 0;
210
		}
Linus Torvalds's avatar
Linus Torvalds committed
211
212
	}
	if (!device->power.states[state].flags.valid) {
213
		printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
214
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
215
216
	}
	if (device->parent && (state < device->parent->power.state)) {
217
		printk(KERN_WARNING PREFIX
218
			      "Cannot set device to a higher-powered"
219
			      " state than parent\n");
220
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
221
222
223
224
225
226
227
228
	}

	/*
	 * Transition Power
	 * ----------------
	 * On transitions to a high-powered state we first apply power (via
	 * power resources) then evalute _PSx.  Conversly for transitions to
	 * a lower-powered state.
229
	 */
Linus Torvalds's avatar
Linus Torvalds committed
230
231
232
233
234
235
236
	if (state < device->power.state) {
		if (device->power.flags.power_resources) {
			result = acpi_power_transition(device, state);
			if (result)
				goto end;
		}
		if (device->power.states[state].flags.explicit_set) {
Len Brown's avatar
Len Brown committed
237
238
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
239
240
241
242
243
			if (ACPI_FAILURE(status)) {
				result = -ENODEV;
				goto end;
			}
		}
Len Brown's avatar
Len Brown committed
244
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
245
		if (device->power.states[state].flags.explicit_set) {
Len Brown's avatar
Len Brown committed
246
247
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
248
249
250
251
252
253
254
255
256
257
258
259
			if (ACPI_FAILURE(status)) {
				result = -ENODEV;
				goto end;
			}
		}
		if (device->power.flags.power_resources) {
			result = acpi_power_transition(device, state);
			if (result)
				goto end;
		}
	}

Len Brown's avatar
Len Brown committed
260
      end:
Linus Torvalds's avatar
Linus Torvalds committed
261
	if (result)
262
263
264
		printk(KERN_WARNING PREFIX
			      "Transitioning device [%s] to D%d\n",
			      device->pnp.bus_id, state);
Linus Torvalds's avatar
Linus Torvalds committed
265
	else
Len Brown's avatar
Len Brown committed
266
267
268
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to D%d\n",
				  device->pnp.bus_id, state));
Linus Torvalds's avatar
Linus Torvalds committed
269

270
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
271
272
}

Len Brown's avatar
Len Brown committed
273
EXPORT_SYMBOL(acpi_bus_set_power);
Linus Torvalds's avatar
Linus Torvalds committed
274
275
276
277
278
279
280
281
282
283

/* --------------------------------------------------------------------------
                                Event Management
   -------------------------------------------------------------------------- */

static DEFINE_SPINLOCK(acpi_bus_event_lock);

LIST_HEAD(acpi_bus_event_list);
DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);

Len Brown's avatar
Len Brown committed
284
extern int event_is_open;
Linus Torvalds's avatar
Linus Torvalds committed
285

Len Brown's avatar
Len Brown committed
286
int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
Linus Torvalds's avatar
Linus Torvalds committed
287
{
Len Brown's avatar
Len Brown committed
288
289
	struct acpi_bus_event *event = NULL;
	unsigned long flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
290
291
292


	if (!device)
293
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
294
295
296

	/* drop event on the floor if no one's listening */
	if (!event_is_open)
297
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
298
299
300

	event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
	if (!event)
301
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
302
303
304
305
306
307
308
309
310
311
312
313

	strcpy(event->device_class, device->pnp.device_class);
	strcpy(event->bus_id, device->pnp.bus_id);
	event->type = type;
	event->data = data;

	spin_lock_irqsave(&acpi_bus_event_lock, flags);
	list_add_tail(&event->node, &acpi_bus_event_list);
	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);

	wake_up_interruptible(&acpi_bus_event_queue);

314
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
315
}
Len Brown's avatar
Len Brown committed
316

Linus Torvalds's avatar
Linus Torvalds committed
317
318
EXPORT_SYMBOL(acpi_bus_generate_event);

Len Brown's avatar
Len Brown committed
319
int acpi_bus_receive_event(struct acpi_bus_event *event)
Linus Torvalds's avatar
Linus Torvalds committed
320
{
Len Brown's avatar
Len Brown committed
321
322
	unsigned long flags = 0;
	struct acpi_bus_event *entry = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
323
324
325
326
327

	DECLARE_WAITQUEUE(wait, current);


	if (!event)
328
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
329
330
331
332
333
334
335
336
337
338
339
340
341

	if (list_empty(&acpi_bus_event_list)) {

		set_current_state(TASK_INTERRUPTIBLE);
		add_wait_queue(&acpi_bus_event_queue, &wait);

		if (list_empty(&acpi_bus_event_list))
			schedule();

		remove_wait_queue(&acpi_bus_event_queue, &wait);
		set_current_state(TASK_RUNNING);

		if (signal_pending(current))
342
			return -ERESTARTSYS;
Linus Torvalds's avatar
Linus Torvalds committed
343
344
345
	}

	spin_lock_irqsave(&acpi_bus_event_lock, flags);
Len Brown's avatar
Len Brown committed
346
347
	entry =
	    list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node);
Linus Torvalds's avatar
Linus Torvalds committed
348
349
350
351
352
	if (entry)
		list_del(&entry->node);
	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);

	if (!entry)
353
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
354
355
356
357
358

	memcpy(event, entry, sizeof(struct acpi_bus_event));

	kfree(entry);

359
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
360
361
}

Len Brown's avatar
Len Brown committed
362
EXPORT_SYMBOL(acpi_bus_receive_event);
Linus Torvalds's avatar
Linus Torvalds committed
363
364
365
366
367
368

/* --------------------------------------------------------------------------
                             Notification Handling
   -------------------------------------------------------------------------- */

static int
Len Brown's avatar
Len Brown committed
369
acpi_bus_check_device(struct acpi_device *device, int *status_changed)
Linus Torvalds's avatar
Linus Torvalds committed
370
{
Len Brown's avatar
Len Brown committed
371
	acpi_status status = 0;
Linus Torvalds's avatar
Linus Torvalds committed
372
373
374
375
	struct acpi_device_status old_status;


	if (!device)
376
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392

	if (status_changed)
		*status_changed = 0;

	old_status = device->status;

	/*
	 * Make sure this device's parent is present before we go about
	 * messing with the device.
	 */
	if (device->parent && !device->parent->status.present) {
		device->status = device->parent->status;
		if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) {
			if (status_changed)
				*status_changed = 1;
		}
393
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
394
395
396
397
	}

	status = acpi_bus_get_status(device);
	if (ACPI_FAILURE(status))
398
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
399
400

	if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
401
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
402
403
404

	if (status_changed)
		*status_changed = 1;
Len Brown's avatar
Len Brown committed
405

Linus Torvalds's avatar
Linus Torvalds committed
406
407
408
409
410
411
	/*
	 * Device Insertion/Removal
	 */
	if ((device->status.present) && !(old_status.present)) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
		/* TBD: Handle device insertion */
Len Brown's avatar
Len Brown committed
412
	} else if (!(device->status.present) && (old_status.present)) {
Linus Torvalds's avatar
Linus Torvalds committed
413
414
415
416
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
		/* TBD: Handle device removal */
	}

417
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
418
419
}

Len Brown's avatar
Len Brown committed
420
static int acpi_bus_check_scope(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
421
{
Len Brown's avatar
Len Brown committed
422
423
	int result = 0;
	int status_changed = 0;
Linus Torvalds's avatar
Linus Torvalds committed
424
425
426


	if (!device)
427
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
428
429
430
431

	/* Status Change? */
	result = acpi_bus_check_device(device, &status_changed);
	if (result)
432
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
433
434

	if (!status_changed)
435
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
436
437
438
439
440
441

	/*
	 * TBD: Enumerate child devices within this device's scope and
	 *       run acpi_bus_check_device()'s on them.
	 */

442
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
443
444
445
446
447
448
449
}

/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
Len Brown's avatar
Len Brown committed
450
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
Linus Torvalds's avatar
Linus Torvalds committed
451
{
Len Brown's avatar
Len Brown committed
452
453
	int result = 0;
	struct acpi_device *device = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
454
455
456


	if (acpi_bus_get_device(handle, &device))
457
		return;
Linus Torvalds's avatar
Linus Torvalds committed
458
459
460
461

	switch (type) {

	case ACPI_NOTIFY_BUS_CHECK:
Len Brown's avatar
Len Brown committed
462
463
464
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received BUS CHECK notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
465
466
467
		result = acpi_bus_check_scope(device);
		/* 
		 * TBD: We'll need to outsource certain events to non-ACPI
Len Brown's avatar
Len Brown committed
468
		 *      drivers via the device manager (device.c).
Linus Torvalds's avatar
Linus Torvalds committed
469
470
471
472
		 */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
Len Brown's avatar
Len Brown committed
473
474
475
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received DEVICE CHECK notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
476
477
478
		result = acpi_bus_check_device(device, NULL);
		/* 
		 * TBD: We'll need to outsource certain events to non-ACPI
Len Brown's avatar
Len Brown committed
479
		 *      drivers via the device manager (device.c).
Linus Torvalds's avatar
Linus Torvalds committed
480
481
482
483
		 */
		break;

	case ACPI_NOTIFY_DEVICE_WAKE:
Len Brown's avatar
Len Brown committed
484
485
486
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received DEVICE WAKE notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
487
488
489
490
		/* TBD */
		break;

	case ACPI_NOTIFY_EJECT_REQUEST:
Len Brown's avatar
Len Brown committed
491
492
493
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received EJECT REQUEST notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
494
495
496
497
		/* TBD */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
Len Brown's avatar
Len Brown committed
498
499
500
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received DEVICE CHECK LIGHT notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
501
502
503
504
		/* TBD: Exactly what does 'light' mean? */
		break;

	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
Len Brown's avatar
Len Brown committed
505
506
507
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received FREQUENCY MISMATCH notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
508
509
510
511
		/* TBD */
		break;

	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
Len Brown's avatar
Len Brown committed
512
513
514
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received BUS MODE MISMATCH notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
515
516
517
518
		/* TBD */
		break;

	case ACPI_NOTIFY_POWER_FAULT:
Len Brown's avatar
Len Brown committed
519
520
521
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received POWER FAULT notification for device [%s]\n",
				  device->pnp.bus_id));
Linus Torvalds's avatar
Linus Torvalds committed
522
523
524
525
		/* TBD */
		break;

	default:
Len Brown's avatar
Len Brown committed
526
527
528
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
Linus Torvalds's avatar
Linus Torvalds committed
529
530
531
		break;
	}

532
	return;
Linus Torvalds's avatar
Linus Torvalds committed
533
534
535
536
537
538
}

/* --------------------------------------------------------------------------
                             Initialization/Cleanup
   -------------------------------------------------------------------------- */

Len Brown's avatar
Len Brown committed
539
static int __init acpi_bus_init_irq(void)
Linus Torvalds's avatar
Linus Torvalds committed
540
{
Len Brown's avatar
Len Brown committed
541
542
543
544
	acpi_status status = AE_OK;
	union acpi_object arg = { ACPI_TYPE_INTEGER };
	struct acpi_object_list arg_list = { 1, &arg };
	char *message = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563


	/* 
	 * Let the system know what interrupt model we are using by
	 * evaluating the \_PIC object, if exists.
	 */

	switch (acpi_irq_model) {
	case ACPI_IRQ_MODEL_PIC:
		message = "PIC";
		break;
	case ACPI_IRQ_MODEL_IOAPIC:
		message = "IOAPIC";
		break;
	case ACPI_IRQ_MODEL_IOSAPIC:
		message = "IOSAPIC";
		break;
	default:
		printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
564
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
565
566
567
568
569
570
571
572
	}

	printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);

	arg.integer.value = acpi_irq_model;

	status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
573
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
574
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
575
576
	}

577
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
578
579
}

Len Brown's avatar
Len Brown committed
580
void __init acpi_early_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
581
{
Len Brown's avatar
Len Brown committed
582
583
	acpi_status status = AE_OK;
	struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
Linus Torvalds's avatar
Linus Torvalds committed
584
585
586


	if (acpi_disabled)
587
		return;
Linus Torvalds's avatar
Linus Torvalds committed
588

Bob Moore's avatar
Bob Moore committed
589
590
	printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);

Linus Torvalds's avatar
Linus Torvalds committed
591
592
593
594
595
596
	/* enable workarounds, unless strict ACPI spec. compliance */
	if (!acpi_strict)
		acpi_gbl_enable_interpreter_slack = TRUE;

	status = acpi_initialize_subsystem();
	if (ACPI_FAILURE(status)) {
Len Brown's avatar
Len Brown committed
597
598
		printk(KERN_ERR PREFIX
		       "Unable to initialize the ACPI Interpreter\n");
Linus Torvalds's avatar
Linus Torvalds committed
599
600
601
602
603
		goto error0;
	}

	status = acpi_load_tables();
	if (ACPI_FAILURE(status)) {
Len Brown's avatar
Len Brown committed
604
605
		printk(KERN_ERR PREFIX
		       "Unable to load the System Description Tables\n");
Linus Torvalds's avatar
Linus Torvalds committed
606
607
608
609
610
611
		goto error0;
	}

	/*
	 * Get a separate copy of the FADT for use by other drivers.
	 */
Bob Moore's avatar
Bob Moore committed
612
	status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
Linus Torvalds's avatar
Linus Torvalds committed
613
614
615
616
617
618
619
620
621
622
623
624
625
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to get the FADT\n");
		goto error0;
	}
#ifdef CONFIG_X86
	if (!acpi_ioapic) {
		extern acpi_interrupt_flags acpi_sci_flags;

		/* compatible (0) means level (3) */
		if (acpi_sci_flags.trigger == 0)
			acpi_sci_flags.trigger = 3;

		/* Set PIC-mode SCI trigger type */
Len Brown's avatar
Len Brown committed
626
627
		acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
					 acpi_sci_flags.trigger);
Linus Torvalds's avatar
Linus Torvalds committed
628
629
630
631
632
633
634
635
636
637
	} else {
		extern int acpi_sci_override_gsi;
		/*
		 * now that acpi_fadt is initialized,
		 * update it with result from INT_SRC_OVR parsing
		 */
		acpi_fadt.sci_int = acpi_sci_override_gsi;
	}
#endif

Len Brown's avatar
Len Brown committed
638
639
640
641
	status =
	    acpi_enable_subsystem(~
				  (ACPI_NO_HARDWARE_INIT |
				   ACPI_NO_ACPI_ENABLE));
Linus Torvalds's avatar
Linus Torvalds committed
642
643
644
645
646
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
		goto error0;
	}

647
	return;
Linus Torvalds's avatar
Linus Torvalds committed
648

Len Brown's avatar
Len Brown committed
649
      error0:
Linus Torvalds's avatar
Linus Torvalds committed
650
	disable_acpi();
651
	return;
Linus Torvalds's avatar
Linus Torvalds committed
652
653
}

Len Brown's avatar
Len Brown committed
654
static int __init acpi_bus_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
655
{
Len Brown's avatar
Len Brown committed
656
657
658
	int result = 0;
	acpi_status status = AE_OK;
	extern acpi_status acpi_os_initialize1(void);
Linus Torvalds's avatar
Linus Torvalds committed
659
660
661
662


	status = acpi_os_initialize1();

Len Brown's avatar
Len Brown committed
663
664
	status =
	    acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
Linus Torvalds's avatar
Linus Torvalds committed
665
	if (ACPI_FAILURE(status)) {
Len Brown's avatar
Len Brown committed
666
667
		printk(KERN_ERR PREFIX
		       "Unable to start the ACPI Interpreter\n");
Linus Torvalds's avatar
Linus Torvalds committed
668
669
670
671
		goto error1;
	}

	if (ACPI_FAILURE(status)) {
Len Brown's avatar
Len Brown committed
672
673
		printk(KERN_ERR PREFIX
		       "Unable to initialize ACPI OS objects\n");
Linus Torvalds's avatar
Linus Torvalds committed
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
		goto error1;
	}
#ifdef CONFIG_ACPI_EC
	/*
	 * ACPI 2.0 requires the EC driver to be loaded and work before
	 * the EC device is found in the namespace (i.e. before acpi_initialize_objects()
	 * is called).
	 *
	 * This is accomplished by looking for the ECDT table, and getting 
	 * the EC parameters out of that.
	 */
	status = acpi_ec_ecdt_probe();
	/* Ignore result. Not having an ECDT is not fatal. */
#endif

	status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
		goto error1;
	}

	printk(KERN_INFO PREFIX "Interpreter enabled\n");

	/*
	 * Get the system interrupt model and evaluate \_PIC.
	 */
	result = acpi_bus_init_irq();
	if (result)
		goto error1;

	/*
	 * Register the for all standard device notifications.
	 */
Len Brown's avatar
Len Brown committed
707
708
709
	status =
	    acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
					&acpi_bus_notify, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
710
	if (ACPI_FAILURE(status)) {
Len Brown's avatar
Len Brown committed
711
712
		printk(KERN_ERR PREFIX
		       "Unable to register for device notifications\n");
Linus Torvalds's avatar
Linus Torvalds committed
713
714
715
716
717
718
719
720
		goto error1;
	}

	/*
	 * Create the top ACPI proc directory
	 */
	acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);

721
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
722
723

	/* Mimic structured exception handling */
Len Brown's avatar
Len Brown committed
724
      error1:
Linus Torvalds's avatar
Linus Torvalds committed
725
	acpi_terminate();
726
	return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
727
728
}

Len Brown's avatar
Len Brown committed
729
decl_subsys(acpi, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
730

Len Brown's avatar
Len Brown committed
731
static int __init acpi_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
732
{
Len Brown's avatar
Len Brown committed
733
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
734
735
736
737


	if (acpi_disabled) {
		printk(KERN_INFO PREFIX "Interpreter disabled.\n");
738
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
739
740
741
742
743
744
745
	}

	firmware_register(&acpi_subsys);

	result = acpi_bus_init();

	if (!result) {
746
#ifdef CONFIG_PM_LEGACY
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
		if (!PM_IS_ACTIVE())
			pm_active = 1;
		else {
Len Brown's avatar
Len Brown committed
750
751
			printk(KERN_INFO PREFIX
			       "APM is already active, exiting\n");
Linus Torvalds's avatar
Linus Torvalds committed
752
753
754
755
756
757
758
			disable_acpi();
			result = -ENODEV;
		}
#endif
	} else
		disable_acpi();

759
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
760
761
762
}

subsys_initcall(acpi_init);