Blame view

drivers/acpi/scan.c 38.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * scan.c - support for transforming the ACPI namespace into individual objects
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
7
  #include <linux/slab.h>
9b6d97b64   Randy Dunlap   ACPI: scan: handl...
8
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/acpi.h>
74523c901   Alok N Kataria   ACPI: fix checkpa...
10
11
  #include <linux/signal.h>
  #include <linux/kthread.h>
222e82ac9   Darrick J. Wong   acpi: Support IBM...
12
  #include <linux/dmi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  
  #include <acpi/acpi_drivers.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15

e60cc7a6f   Bjorn Helgaas   ACPI: move privat...
16
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #define _COMPONENT		ACPI_BUS_COMPONENT
f52fd66d2   Len Brown   ACPI: clean up AC...
18
  ACPI_MODULE_NAME("scan");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #define STRUCT_TO_INT(s)	(*((int*)&s))
4be44fcd3   Len Brown   [ACPI] Lindent al...
20
  extern struct acpi_device *acpi_root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  
  #define ACPI_BUS_CLASS			"system_bus"
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
23
  #define ACPI_BUS_HID			"LNXSYBUS"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #define ACPI_BUS_DEVICE_NAME		"System Bus"
859ac9a4b   Bjorn Helgaas   ACPI: identify de...
25
  #define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  static LIST_HEAD(acpi_device_list);
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
27
  static LIST_HEAD(acpi_bus_id_list);
9090589d8   Shaohua Li   ACPI: convert acp...
28
  DEFINE_MUTEX(acpi_device_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  LIST_HEAD(acpi_wakeup_device_list);
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
30
  struct acpi_device_bus_id{
bb0958544   Zhang Rui   ACPI: use more un...
31
  	char bus_id[15];
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
32
33
  	unsigned int instance_no;
  	struct list_head node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  };
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
35
36
37
38
39
40
  
  /*
   * Creates hid/cid(s) string needed for modalias and uevent
   * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
   * char *modalias: "acpi:IBM0001:ACPI0001"
  */
b3e572d2e   Adrian Bunk   make drivers/acpi...
41
42
43
  static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
  			   int size)
  {
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
44
  	int len;
5c9fcb5de   Zhang Rui   ACPI: fix a regre...
45
  	int count;
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
46
  	struct acpi_hardware_id *id;
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
47

5c9fcb5de   Zhang Rui   ACPI: fix a regre...
48
  	len = snprintf(modalias, size, "acpi:");
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
49
  	size -= len;
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
50
51
  	list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
  		count = snprintf(&modalias[len], size, "%s:", id->id);
5c9fcb5de   Zhang Rui   ACPI: fix a regre...
52
53
54
55
56
  		if (count < 0 || count >= size)
  			return -EINVAL;
  		len += count;
  		size -= count;
  	}
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  	modalias[len] = '\0';
  	return len;
  }
  
  static ssize_t
  acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	int len;
  
  	/* Device has no HID and no CID or string is >1024 */
  	len = create_modalias(acpi_dev, buf, 1024);
  	if (len <= 0)
  		return 0;
  	buf[len++] = '
  ';
  	return len;
  }
  static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
75
  static void acpi_bus_hot_remove_device(void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  {
26d46867b   Zhang Rui   fix a deadlock is...
77
78
  	struct acpi_device *device;
  	acpi_handle handle = context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
  	struct acpi_object_list arg_list;
  	union acpi_object arg;
  	acpi_status status = AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82

26d46867b   Zhang Rui   fix a deadlock is...
83
  	if (acpi_bus_get_device(handle, &device))
c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
84
  		return;
26d46867b   Zhang Rui   fix a deadlock is...
85
86
  
  	if (!device)
c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
87
  		return;
26d46867b   Zhang Rui   fix a deadlock is...
88
89
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
0794469da   Kay Sievers   ACPI: struct devi...
90
91
  		"Hot-removing device %s...
  ", dev_name(&device->dev)));
26d46867b   Zhang Rui   fix a deadlock is...
92
93
  
  	if (acpi_bus_trim(device, 1)) {
55ac9a018   Lin Ming   ACPI: replace ACP...
94
95
96
  		printk(KERN_ERR PREFIX
  				"Removing device failed
  ");
c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
97
  		return;
26d46867b   Zhang Rui   fix a deadlock is...
98
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99

26d46867b   Zhang Rui   fix a deadlock is...
100
101
102
  	/* power off device */
  	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
  	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
55ac9a018   Lin Ming   ACPI: replace ACP...
103
104
105
  		printk(KERN_WARNING PREFIX
  				"Power-off device failed
  ");
26d46867b   Zhang Rui   fix a deadlock is...
106
107
  
  	if (device->flags.lockable) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
  		arg_list.count = 1;
  		arg_list.pointer = &arg;
  		arg.type = ACPI_TYPE_INTEGER;
  		arg.integer.value = 0;
  		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
  	arg_list.count = 1;
  	arg_list.pointer = &arg;
  	arg.type = ACPI_TYPE_INTEGER;
  	arg.integer.value = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  	/*
  	 * TBD: _EJD support.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
26d46867b   Zhang Rui   fix a deadlock is...
124
  	if (ACPI_FAILURE(status))
c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
125
126
127
  		printk(KERN_WARNING PREFIX
  				"Eject device failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
129
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  static ssize_t
f883d9db0   Patrick Mochel   ACPI: convert to ...
132
133
  acpi_eject_store(struct device *d, struct device_attribute *attr,
  		const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
135
  	int ret = count;
4be44fcd3   Len Brown   [ACPI] Lindent al...
136
  	acpi_status status;
4be44fcd3   Len Brown   [ACPI] Lindent al...
137
  	acpi_object_type type = 0;
f883d9db0   Patrick Mochel   ACPI: convert to ...
138
  	struct acpi_device *acpi_device = to_acpi_device(d);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
  	if ((!count) || (buf[0] != '1')) {
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  #ifndef FORCE_EJECT
f883d9db0   Patrick Mochel   ACPI: convert to ...
144
  	if (acpi_device->driver == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
  		ret = -ENODEV;
  		goto err;
  	}
  #endif
f883d9db0   Patrick Mochel   ACPI: convert to ...
149
150
  	status = acpi_get_type(acpi_device->handle, &type);
  	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
  		ret = -ENODEV;
  		goto err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

c8d72a5e7   Zhang Rui   ACPI: run ACPI de...
155
  	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle);
74523c901   Alok N Kataria   ACPI: fix checkpa...
156
  err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  }
f883d9db0   Patrick Mochel   ACPI: convert to ...
159
  static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
161
162
163
  static ssize_t
  acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164

ea8d82fd3   Bjorn Helgaas   ACPI: use acpi_de...
165
166
  	return sprintf(buf, "%s
  ", acpi_device_hid(acpi_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  }
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
168
  static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
170
171
172
173
174
  static ssize_t
  acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
  	int result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
176
  	result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
0c526d96a   Alex Chiang   ACPI: clean up wh...
177
  	if (result)
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
178
  		goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
180
181
182
  	result = sprintf(buf, "%s
  ", (char*)path.pointer);
  	kfree(path.pointer);
0c526d96a   Alex Chiang   ACPI: clean up wh...
183
  end:
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
184
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  }
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
186
  static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
188
  static int acpi_device_setup_files(struct acpi_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  {
f883d9db0   Patrick Mochel   ACPI: convert to ...
190
191
  	acpi_status status;
  	acpi_handle temp;
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
192
  	int result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  
  	/*
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
195
  	 * Devices gotten from FADT don't have a "path" attribute
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  	 */
0c526d96a   Alex Chiang   ACPI: clean up wh...
197
  	if (dev->handle) {
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
198
  		result = device_create_file(&dev->dev, &dev_attr_path);
0c526d96a   Alex Chiang   ACPI: clean up wh...
199
  		if (result)
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
200
  			goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  	}
1131b938f   Bjorn Helgaas   ACPI: remove acpi...
202
203
204
  	result = device_create_file(&dev->dev, &dev_attr_hid);
  	if (result)
  		goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205

1131b938f   Bjorn Helgaas   ACPI: remove acpi...
206
207
208
  	result = device_create_file(&dev->dev, &dev_attr_modalias);
  	if (result)
  		goto end;
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
209

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
210
211
212
213
          /*
           * If device has _EJ0, 'eject' file is created that is used to trigger
           * hot-removal function from userland.
           */
f883d9db0   Patrick Mochel   ACPI: convert to ...
214
215
  	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
  	if (ACPI_SUCCESS(status))
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
216
  		result = device_create_file(&dev->dev, &dev_attr_eject);
0c526d96a   Alex Chiang   ACPI: clean up wh...
217
  end:
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
218
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  }
f883d9db0   Patrick Mochel   ACPI: convert to ...
220
  static void acpi_device_remove_files(struct acpi_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  {
f883d9db0   Patrick Mochel   ACPI: convert to ...
222
223
  	acpi_status status;
  	acpi_handle temp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224

f883d9db0   Patrick Mochel   ACPI: convert to ...
225
226
227
228
229
230
231
  	/*
  	 * If device has _EJ0, 'eject' file is created that is used to trigger
  	 * hot-removal function from userland.
  	 */
  	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
  	if (ACPI_SUCCESS(status))
  		device_remove_file(&dev->dev, &dev_attr_eject);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

1131b938f   Bjorn Helgaas   ACPI: remove acpi...
233
234
  	device_remove_file(&dev->dev, &dev_attr_modalias);
  	device_remove_file(&dev->dev, &dev_attr_hid);
0c526d96a   Alex Chiang   ACPI: clean up wh...
235
  	if (dev->handle)
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
236
  		device_remove_file(&dev->dev, &dev_attr_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  /* --------------------------------------------------------------------------
9e89dde2b   Zhang Rui   ACPI: clean up sc...
239
  			ACPI Bus operations
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
     -------------------------------------------------------------------------- */
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
241
242
243
244
245
  
  int acpi_match_device_ids(struct acpi_device *device,
  			  const struct acpi_device_id *ids)
  {
  	const struct acpi_device_id *id;
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
246
  	struct acpi_hardware_id *hwid;
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
247

39a0ad871   Zhao Yakui   ACPI : Load devic...
248
249
250
251
252
253
  	/*
  	 * If the device is not present, it is unnecessary to load device
  	 * driver for it.
  	 */
  	if (!device->status.present)
  		return -ENODEV;
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
254
255
256
  	for (id = ids; id->id[0]; id++)
  		list_for_each_entry(hwid, &device->pnp.ids, list)
  			if (!strcmp((char *) id->id, hwid->id))
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
257
  				return 0;
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
258
259
260
261
  
  	return -ENOENT;
  }
  EXPORT_SYMBOL(acpi_match_device_ids);
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
262
263
264
265
266
267
268
269
270
  static void acpi_free_ids(struct acpi_device *device)
  {
  	struct acpi_hardware_id *id, *tmp;
  
  	list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
  		kfree(id->id);
  		kfree(id);
  	}
  }
1890a97ab   Patrick Mochel   ACPI: change regi...
271
  static void acpi_device_release(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  {
1890a97ab   Patrick Mochel   ACPI: change regi...
273
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274

7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
275
  	acpi_free_ids(acpi_dev);
1890a97ab   Patrick Mochel   ACPI: change regi...
276
  	kfree(acpi_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  }
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
278
  static int acpi_device_suspend(struct device *dev, pm_message_t state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  {
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
280
281
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = acpi_dev->driver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282

5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
283
284
  	if (acpi_drv && acpi_drv->ops.suspend)
  		return acpi_drv->ops.suspend(acpi_dev, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287

5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
288
  static int acpi_device_resume(struct device *dev)
9e89dde2b   Zhang Rui   ACPI: clean up sc...
289
  {
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
290
291
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = acpi_dev->driver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292

5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
293
294
  	if (acpi_drv && acpi_drv->ops.resume)
  		return acpi_drv->ops.resume(acpi_dev);
d550d98d3   Patrick Mochel   ACPI: delete trac...
295
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  }
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
297
  static int acpi_bus_match(struct device *dev, struct device_driver *drv)
9e89dde2b   Zhang Rui   ACPI: clean up sc...
298
  {
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
299
300
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = to_acpi_driver(drv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301

29b71a1ca   Thomas Renninger   ACPI: autoload mo...
302
  	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
303
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304

7eff2e7a8   Kay Sievers   Driver core: chan...
305
  static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  {
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
307
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
7eff2e7a8   Kay Sievers   Driver core: chan...
308
  	int len;
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
309

7eff2e7a8   Kay Sievers   Driver core: chan...
310
311
312
313
314
315
316
  	if (add_uevent_var(env, "MODALIAS="))
  		return -ENOMEM;
  	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
  			      sizeof(env->buf) - env->buflen);
  	if (len >= (sizeof(env->buf) - env->buflen))
  		return -ENOMEM;
  	env->buflen += len;
9e89dde2b   Zhang Rui   ACPI: clean up sc...
317
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  }
46ec8598f   Bjorn Helgaas   ACPI: support acp...
319
320
321
322
323
324
325
326
327
328
  static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
  {
  	struct acpi_device *device = data;
  
  	device->driver->ops.notify(device, event);
  }
  
  static acpi_status acpi_device_notify_fixed(void *data)
  {
  	struct acpi_device *device = data;
53de5356b   Bjorn Helgaas   ACPI: don't pass ...
329
330
  	/* Fixed hardware devices have no handles */
  	acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
46ec8598f   Bjorn Helgaas   ACPI: support acp...
331
332
333
334
335
336
  	return AE_OK;
  }
  
  static int acpi_device_install_notify_handler(struct acpi_device *device)
  {
  	acpi_status status;
46ec8598f   Bjorn Helgaas   ACPI: support acp...
337

ccba2a36d   Bjorn Helgaas   ACPI: use device_...
338
  	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
46ec8598f   Bjorn Helgaas   ACPI: support acp...
339
340
341
342
  		status =
  		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
  						     acpi_device_notify_fixed,
  						     device);
ccba2a36d   Bjorn Helgaas   ACPI: use device_...
343
  	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
46ec8598f   Bjorn Helgaas   ACPI: support acp...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  		status =
  		    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
  						     acpi_device_notify_fixed,
  						     device);
  	else
  		status = acpi_install_notify_handler(device->handle,
  						     ACPI_DEVICE_NOTIFY,
  						     acpi_device_notify,
  						     device);
  
  	if (ACPI_FAILURE(status))
  		return -EINVAL;
  	return 0;
  }
  
  static void acpi_device_remove_notify_handler(struct acpi_device *device)
  {
ccba2a36d   Bjorn Helgaas   ACPI: use device_...
361
  	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
46ec8598f   Bjorn Helgaas   ACPI: support acp...
362
363
  		acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
  						acpi_device_notify_fixed);
ccba2a36d   Bjorn Helgaas   ACPI: use device_...
364
  	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
46ec8598f   Bjorn Helgaas   ACPI: support acp...
365
366
367
368
369
370
  		acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
  						acpi_device_notify_fixed);
  	else
  		acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
  					   acpi_device_notify);
  }
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
371
372
373
  static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
  static int acpi_start_single_object(struct acpi_device *);
  static int acpi_device_probe(struct device * dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  {
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
375
376
377
378
379
380
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
  	int ret;
  
  	ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
  	if (!ret) {
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
381
382
  		if (acpi_dev->bus_ops.acpi_op_start)
  			acpi_start_single_object(acpi_dev);
46ec8598f   Bjorn Helgaas   ACPI: support acp...
383
384
385
386
  
  		if (acpi_drv->ops.notify) {
  			ret = acpi_device_install_notify_handler(acpi_dev);
  			if (ret) {
46ec8598f   Bjorn Helgaas   ACPI: support acp...
387
388
389
390
391
392
  				if (acpi_drv->ops.remove)
  					acpi_drv->ops.remove(acpi_dev,
  						     acpi_dev->removal_type);
  				return ret;
  			}
  		}
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
393
394
395
396
397
398
399
400
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  			"Found driver [%s] for device [%s]
  ",
  			acpi_drv->name, acpi_dev->pnp.bus_id));
  		get_device(dev);
  	}
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401

5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
402
403
404
405
406
407
  static int acpi_device_remove(struct device * dev)
  {
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = acpi_dev->driver;
  
  	if (acpi_drv) {
46ec8598f   Bjorn Helgaas   ACPI: support acp...
408
409
  		if (acpi_drv->ops.notify)
  			acpi_device_remove_notify_handler(acpi_dev);
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
410
  		if (acpi_drv->ops.remove)
96333578b   Li Shaohua   ACPI: add acpi_bu...
411
  			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  	}
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
413
  	acpi_dev->driver = NULL;
db89b4f0d   Pavel Machek   ACPI: catch calls...
414
  	acpi_dev->driver_data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415

5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
416
  	put_device(dev);
9e89dde2b   Zhang Rui   ACPI: clean up sc...
417
418
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

55955aad7   David Brownell   PNPACPI sets pnpd...
420
  struct bus_type acpi_bus_type = {
9e89dde2b   Zhang Rui   ACPI: clean up sc...
421
422
423
  	.name		= "acpi",
  	.suspend	= acpi_device_suspend,
  	.resume		= acpi_device_resume,
5d9464a46   Patrick Mochel   ACPI: add ACPI bu...
424
425
426
427
  	.match		= acpi_bus_match,
  	.probe		= acpi_device_probe,
  	.remove		= acpi_device_remove,
  	.uevent		= acpi_device_uevent,
9e89dde2b   Zhang Rui   ACPI: clean up sc...
428
  };
66b7ed40a   Bjorn Helgaas   ACPI: remove redu...
429
  static int acpi_device_register(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
431
  	int result;
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
432
433
  	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
  	int found = 0;
66b7ed40a   Bjorn Helgaas   ACPI: remove redu...
434

9e89dde2b   Zhang Rui   ACPI: clean up sc...
435
436
437
438
439
440
441
  	/*
  	 * Linkage
  	 * -------
  	 * Link this device to its parent and siblings.
  	 */
  	INIT_LIST_HEAD(&device->children);
  	INIT_LIST_HEAD(&device->node);
9e89dde2b   Zhang Rui   ACPI: clean up sc...
442
  	INIT_LIST_HEAD(&device->wakeup_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
444
445
446
447
448
  	new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
  	if (!new_bus_id) {
  		printk(KERN_ERR PREFIX "Memory allocation error
  ");
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  	}
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
450

9090589d8   Shaohua Li   ACPI: convert acp...
451
  	mutex_lock(&acpi_device_lock);
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
452
453
454
455
456
  	/*
  	 * Find suitable bus_id and instance number in acpi_bus_id_list
  	 * If failed, create one and link it into acpi_bus_id_list
  	 */
  	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
1131b938f   Bjorn Helgaas   ACPI: remove acpi...
457
458
459
  		if (!strcmp(acpi_device_bus_id->bus_id,
  			    acpi_device_hid(device))) {
  			acpi_device_bus_id->instance_no++;
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
460
461
462
463
  			found = 1;
  			kfree(new_bus_id);
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  	}
0c526d96a   Alex Chiang   ACPI: clean up wh...
465
  	if (!found) {
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
466
  		acpi_device_bus_id = new_bus_id;
1131b938f   Bjorn Helgaas   ACPI: remove acpi...
467
  		strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
468
469
  		acpi_device_bus_id->instance_no = 0;
  		list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	}
0794469da   Kay Sievers   ACPI: struct devi...
471
  	dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

33b571501   Len Brown   ACPI: delete acpi...
473
  	if (device->parent)
9e89dde2b   Zhang Rui   ACPI: clean up sc...
474
  		list_add_tail(&device->node, &device->parent->children);
33b571501   Len Brown   ACPI: delete acpi...
475

9e89dde2b   Zhang Rui   ACPI: clean up sc...
476
477
  	if (device->wakeup.flags.valid)
  		list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
9090589d8   Shaohua Li   ACPI: convert acp...
478
  	mutex_unlock(&acpi_device_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479

1890a97ab   Patrick Mochel   ACPI: change regi...
480
  	if (device->parent)
66b7ed40a   Bjorn Helgaas   ACPI: remove redu...
481
  		device->dev.parent = &device->parent->dev;
1890a97ab   Patrick Mochel   ACPI: change regi...
482
  	device->dev.bus = &acpi_bus_type;
1890a97ab   Patrick Mochel   ACPI: change regi...
483
  	device->dev.release = &acpi_device_release;
8b12b922e   Alex Chiang   ACPI: acpi_device...
484
  	result = device_register(&device->dev);
0c526d96a   Alex Chiang   ACPI: clean up wh...
485
  	if (result) {
8b12b922e   Alex Chiang   ACPI: acpi_device...
486
487
  		dev_err(&device->dev, "Error registering device
  ");
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
488
  		goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490

e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
491
  	result = acpi_device_setup_files(device);
0c526d96a   Alex Chiang   ACPI: clean up wh...
492
  	if (result)
0794469da   Kay Sievers   ACPI: struct devi...
493
494
495
  		printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s
  ",
  		       dev_name(&device->dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496

96333578b   Li Shaohua   ACPI: add acpi_bu...
497
  	device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
  	return 0;
0c526d96a   Alex Chiang   ACPI: clean up wh...
499
  end:
9090589d8   Shaohua Li   ACPI: convert acp...
500
  	mutex_lock(&acpi_device_lock);
33b571501   Len Brown   ACPI: delete acpi...
501
  	if (device->parent)
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
502
  		list_del(&device->node);
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
503
  	list_del(&device->wakeup_list);
9090589d8   Shaohua Li   ACPI: convert acp...
504
  	mutex_unlock(&acpi_device_lock);
e49bd2dd5   Zhang Rui   ACPI: use PNPID:i...
505
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  }
9e89dde2b   Zhang Rui   ACPI: clean up sc...
507
508
  static void acpi_device_unregister(struct acpi_device *device, int type)
  {
9090589d8   Shaohua Li   ACPI: convert acp...
509
  	mutex_lock(&acpi_device_lock);
33b571501   Len Brown   ACPI: delete acpi...
510
  	if (device->parent)
9e89dde2b   Zhang Rui   ACPI: clean up sc...
511
  		list_del(&device->node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512

9e89dde2b   Zhang Rui   ACPI: clean up sc...
513
  	list_del(&device->wakeup_list);
9090589d8   Shaohua Li   ACPI: convert acp...
514
  	mutex_unlock(&acpi_device_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515

9e89dde2b   Zhang Rui   ACPI: clean up sc...
516
  	acpi_detach_data(device->handle, acpi_bus_data_handler);
1890a97ab   Patrick Mochel   ACPI: change regi...
517

f883d9db0   Patrick Mochel   ACPI: convert to ...
518
  	acpi_device_remove_files(device);
1890a97ab   Patrick Mochel   ACPI: change regi...
519
  	device_unregister(&device->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  }
9e89dde2b   Zhang Rui   ACPI: clean up sc...
521
522
523
  /* --------------------------------------------------------------------------
                                   Driver Management
     -------------------------------------------------------------------------- */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  /**
d758a8fa8   Randy Dunlap   [ACPI] fix kernel...
525
526
527
528
   * acpi_bus_driver_init - add a device to a driver
   * @device: the device to add and initialize
   * @driver: driver for the device
   *
0c526d96a   Alex Chiang   ACPI: clean up wh...
529
   * Used to initialize a device via its device driver.  Called whenever a
1890a97ab   Patrick Mochel   ACPI: change regi...
530
   * driver is bound to a device.  Invokes the driver's add() ops.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
   */
  static int
4be44fcd3   Len Brown   [ACPI] Lindent al...
533
  acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
535
  	int result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  	if (!device || !driver)
d550d98d3   Patrick Mochel   ACPI: delete trac...
538
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
  
  	if (!driver->ops.add)
d550d98d3   Patrick Mochel   ACPI: delete trac...
541
  		return -ENOSYS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
  
  	result = driver->ops.add(device);
  	if (result) {
  		device->driver = NULL;
db89b4f0d   Pavel Machek   ACPI: catch calls...
546
  		device->driver_data = NULL;
d550d98d3   Patrick Mochel   ACPI: delete trac...
547
  		return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
552
553
554
555
  	}
  
  	device->driver = driver;
  
  	/*
  	 * TBD - Configuration Management: Assign resources to device based
  	 * upon possible configuration and currently allocated resources.
  	 */
4be44fcd3   Len Brown   [ACPI] Lindent al...
556
557
558
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  			  "Driver successfully bound to device
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
559
  	return 0;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
560
  }
8713cbefa   Adrian Bunk   [ACPI] add static...
561
  static int acpi_start_single_object(struct acpi_device *device)
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
562
563
564
  {
  	int result = 0;
  	struct acpi_driver *driver;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
565
566
  
  	if (!(driver = device->driver))
d550d98d3   Patrick Mochel   ACPI: delete trac...
567
  		return 0;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
568

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
572
  	if (driver->ops.start) {
  		result = driver->ops.start(device);
  		if (result && driver->ops.remove)
  			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	}
d550d98d3   Patrick Mochel   ACPI: delete trac...
574
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  }
9e89dde2b   Zhang Rui   ACPI: clean up sc...
576
577
578
579
580
581
582
583
584
  /**
   * acpi_bus_register_driver - register a driver with the ACPI bus
   * @driver: driver being registered
   *
   * Registers a driver with the ACPI bus.  Searches the namespace for all
   * devices that match the driver's criteria and binds.  Returns zero for
   * success or a negative error status for failure.
   */
  int acpi_bus_register_driver(struct acpi_driver *driver)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  {
1890a97ab   Patrick Mochel   ACPI: change regi...
586
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587

9e89dde2b   Zhang Rui   ACPI: clean up sc...
588
589
  	if (acpi_disabled)
  		return -ENODEV;
1890a97ab   Patrick Mochel   ACPI: change regi...
590
591
592
  	driver->drv.name = driver->name;
  	driver->drv.bus = &acpi_bus_type;
  	driver->drv.owner = driver->owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593

1890a97ab   Patrick Mochel   ACPI: change regi...
594
595
  	ret = driver_register(&driver->drv);
  	return ret;
9e89dde2b   Zhang Rui   ACPI: clean up sc...
596
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597

9e89dde2b   Zhang Rui   ACPI: clean up sc...
598
599
600
601
602
603
604
605
606
607
608
  EXPORT_SYMBOL(acpi_bus_register_driver);
  
  /**
   * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
   * @driver: driver to unregister
   *
   * Unregisters a driver with the ACPI bus.  Searches the namespace for all
   * devices that match the driver's criteria and unbinds.
   */
  void acpi_bus_unregister_driver(struct acpi_driver *driver)
  {
1890a97ab   Patrick Mochel   ACPI: change regi...
609
  	driver_unregister(&driver->drv);
9e89dde2b   Zhang Rui   ACPI: clean up sc...
610
611
612
  }
  
  EXPORT_SYMBOL(acpi_bus_unregister_driver);
9e89dde2b   Zhang Rui   ACPI: clean up sc...
613
614
615
  /* --------------------------------------------------------------------------
                                   Device Enumeration
     -------------------------------------------------------------------------- */
5c478f499   Bjorn Helgaas   ACPI: add acpi_bu...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
  {
  	acpi_status status;
  	int ret;
  	struct acpi_device *device;
  
  	/*
  	 * Fixed hardware devices do not appear in the namespace and do not
  	 * have handles, but we fabricate acpi_devices for them, so we have
  	 * to deal with them specially.
  	 */
  	if (handle == NULL)
  		return acpi_root;
  
  	do {
  		status = acpi_get_parent(handle, &handle);
  		if (status == AE_NULL_ENTRY)
  			return NULL;
  		if (ACPI_FAILURE(status))
  			return acpi_root;
  
  		ret = acpi_bus_get_device(handle, &device);
  		if (ret == 0)
  			return device;
  	} while (1);
  }
9e89dde2b   Zhang Rui   ACPI: clean up sc...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
  acpi_status
  acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
  {
  	acpi_status status;
  	acpi_handle tmp;
  	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
  	union acpi_object *obj;
  
  	status = acpi_get_handle(handle, "_EJD", &tmp);
  	if (ACPI_FAILURE(status))
  		return status;
  
  	status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
  	if (ACPI_SUCCESS(status)) {
  		obj = buffer.pointer;
3b5fee595   Holger Macht   ACPI: Do not pass...
657
658
  		status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
  					 ejd);
9e89dde2b   Zhang Rui   ACPI: clean up sc...
659
660
661
662
663
  		kfree(buffer.pointer);
  	}
  	return status;
  }
  EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
8e4319c42   Bob Moore   ACPICA: Fix sever...
664
  void acpi_bus_data_handler(acpi_handle handle, void *context)
9e89dde2b   Zhang Rui   ACPI: clean up sc...
665
666
667
668
669
670
  {
  
  	/* TBD */
  
  	return;
  }
9e89dde2b   Zhang Rui   ACPI: clean up sc...
671
672
673
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
707
708
709
710
711
712
713
714
715
716
  static int acpi_bus_get_perf_flags(struct acpi_device *device)
  {
  	device->performance.state = ACPI_STATE_UNKNOWN;
  	return 0;
  }
  
  static acpi_status
  acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
  					     union acpi_object *package)
  {
  	int i = 0;
  	union acpi_object *element = NULL;
  
  	if (!device || !package || (package->package.count < 2))
  		return AE_BAD_PARAMETER;
  
  	element = &(package->package.elements[0]);
  	if (!element)
  		return AE_BAD_PARAMETER;
  	if (element->type == ACPI_TYPE_PACKAGE) {
  		if ((element->package.count < 2) ||
  		    (element->package.elements[0].type !=
  		     ACPI_TYPE_LOCAL_REFERENCE)
  		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
  			return AE_BAD_DATA;
  		device->wakeup.gpe_device =
  		    element->package.elements[0].reference.handle;
  		device->wakeup.gpe_number =
  		    (u32) element->package.elements[1].integer.value;
  	} else if (element->type == ACPI_TYPE_INTEGER) {
  		device->wakeup.gpe_number = element->integer.value;
  	} else
  		return AE_BAD_DATA;
  
  	element = &(package->package.elements[1]);
  	if (element->type != ACPI_TYPE_INTEGER) {
  		return AE_BAD_DATA;
  	}
  	device->wakeup.sleep_state = element->integer.value;
  
  	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
  		return AE_NO_MEMORY;
  	}
  	device->wakeup.resources.count = package->package.count - 2;
  	for (i = 0; i < device->wakeup.resources.count; i++) {
  		element = &(package->package.elements[i + 2]);
cd0b22482   Bob Moore   ACPICA: Fixes for...
717
  		if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
9e89dde2b   Zhang Rui   ACPI: clean up sc...
718
  			return AE_BAD_DATA;
9e89dde2b   Zhang Rui   ACPI: clean up sc...
719
720
  
  		device->wakeup.resources.handles[i] = element->reference.handle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  	}
9e89dde2b   Zhang Rui   ACPI: clean up sc...
722

9874647ba   Rafael J. Wysocki   ACPI / ACPICA: Do...
723
  	acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number);
9e89dde2b   Zhang Rui   ACPI: clean up sc...
724
  	return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  }
f517709d6   Rafael J. Wysocki   ACPI / PM: Add mo...
726
  static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  {
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
728
729
730
731
732
733
  	struct acpi_device_id button_device_ids[] = {
  		{"PNP0C0D", 0},
  		{"PNP0C0C", 0},
  		{"PNP0C0E", 0},
  		{"", 0},
  	};
f517709d6   Rafael J. Wysocki   ACPI / PM: Add mo...
734
735
736
737
  	acpi_status status;
  	acpi_event_status event_status;
  
  	device->wakeup.run_wake_count = 0;
b67ea7617   Rafael J. Wysocki   PCI / ACPI / PM: ...
738
  	device->wakeup.flags.notifier_present = 0;
f517709d6   Rafael J. Wysocki   ACPI / PM: Add mo...
739
740
741
742
743
744
745
  
  	/* Power button, Lid switch always enable wakeup */
  	if (!acpi_match_device_ids(device, button_device_ids)) {
  		device->wakeup.flags.run_wake = 1;
  		device->wakeup.flags.always_enabled = 1;
  		return;
  	}
e8e18c956   Rafael J. Wysocki   ACPI: Fix bogus G...
746
747
748
  	status = acpi_get_gpe_status(device->wakeup.gpe_device,
  					device->wakeup.gpe_number,
  						&event_status);
f517709d6   Rafael J. Wysocki   ACPI / PM: Add mo...
749
750
751
752
753
754
755
756
757
758
759
  	if (status == AE_OK)
  		device->wakeup.flags.run_wake =
  				!!(event_status & ACPI_EVENT_FLAG_HANDLE);
  }
  
  static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
  {
  	acpi_status status = 0;
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  	union acpi_object *package = NULL;
  	int psw_error;
29b71a1ca   Thomas Renninger   ACPI: autoload mo...
760

9e89dde2b   Zhang Rui   ACPI: clean up sc...
761
762
763
764
765
  	/* _PRW */
  	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
  	if (ACPI_FAILURE(status)) {
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
  		goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767

9e89dde2b   Zhang Rui   ACPI: clean up sc...
768
769
770
771
772
773
  	package = (union acpi_object *)buffer.pointer;
  	status = acpi_bus_extract_wakeup_device_power_package(device, package);
  	if (ACPI_FAILURE(status)) {
  		ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
  		goto end;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774

9e89dde2b   Zhang Rui   ACPI: clean up sc...
775
  	kfree(buffer.pointer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776

9e89dde2b   Zhang Rui   ACPI: clean up sc...
777
  	device->wakeup.flags.valid = 1;
9b83ccd2f   Rafael J. Wysocki   ACPI PM: Replace ...
778
  	device->wakeup.prepare_count = 0;
f517709d6   Rafael J. Wysocki   ACPI / PM: Add mo...
779
  	acpi_bus_set_run_wake_flags(device);
729b2bdbf   Zhao Yakui   ACPI : Disable th...
780
781
782
783
784
785
  	/* Call _PSW/_DSW object to disable its ability to wake the sleeping
  	 * system for the ACPI device with the _PRW object.
  	 * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
  	 * So it is necessary to call _DSW object first. Only when it is not
  	 * present will the _PSW object used.
  	 */
77e766099   Rafael J. Wysocki   ACPI: Introduce a...
786
787
788
789
790
  	psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
  	if (psw_error)
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  				"error in _DSW or _PSW evaluation
  "));
0c526d96a   Alex Chiang   ACPI: clean up wh...
791
  end:
9e89dde2b   Zhang Rui   ACPI: clean up sc...
792
793
  	if (ACPI_FAILURE(status))
  		device->flags.wake_capable = 0;
d550d98d3   Patrick Mochel   ACPI: delete trac...
794
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796

9e89dde2b   Zhang Rui   ACPI: clean up sc...
797
  static int acpi_bus_get_power_flags(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  {
9e89dde2b   Zhang Rui   ACPI: clean up sc...
799
800
801
  	acpi_status status = 0;
  	acpi_handle handle = NULL;
  	u32 i = 0;
1a3656160   Bjorn Helgaas   ACPI: simplify sc...
802

4be44fcd3   Len Brown   [ACPI] Lindent al...
803

9e89dde2b   Zhang Rui   ACPI: clean up sc...
804
805
806
807
808
809
810
811
812
  	/*
  	 * Power Management Flags
  	 */
  	status = acpi_get_handle(device->handle, "_PSC", &handle);
  	if (ACPI_SUCCESS(status))
  		device->power.flags.explicit_get = 1;
  	status = acpi_get_handle(device->handle, "_IRC", &handle);
  	if (ACPI_SUCCESS(status))
  		device->power.flags.inrush_current = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813

9e89dde2b   Zhang Rui   ACPI: clean up sc...
814
815
816
817
818
819
  	/*
  	 * Enumerate supported power management states
  	 */
  	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
  		struct acpi_device_power_state *ps = &device->power.states[i];
  		char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820

9e89dde2b   Zhang Rui   ACPI: clean up sc...
821
822
823
824
825
826
  		/* Evaluate "_PRx" to se if power resources are referenced */
  		acpi_evaluate_reference(device->handle, object_name, NULL,
  					&ps->resources);
  		if (ps->resources.count) {
  			device->power.flags.power_resources = 1;
  			ps->flags.valid = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828

9e89dde2b   Zhang Rui   ACPI: clean up sc...
829
830
831
832
833
834
  		/* Evaluate "_PSx" to see if we can do explicit sets */
  		object_name[2] = 'S';
  		status = acpi_get_handle(device->handle, object_name, &handle);
  		if (ACPI_SUCCESS(status)) {
  			ps->flags.explicit_set = 1;
  			ps->flags.valid = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836

9e89dde2b   Zhang Rui   ACPI: clean up sc...
837
838
839
  		/* State is valid if we have some power control */
  		if (ps->resources.count || ps->flags.explicit_set)
  			ps->flags.valid = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840

9e89dde2b   Zhang Rui   ACPI: clean up sc...
841
842
843
  		ps->power = -1;	/* Unknown - driver assigned */
  		ps->latency = -1;	/* Unknown - driver assigned */
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844

9e89dde2b   Zhang Rui   ACPI: clean up sc...
845
846
847
848
849
  	/* Set defaults for D0 and D3 states (always valid) */
  	device->power.states[ACPI_STATE_D0].flags.valid = 1;
  	device->power.states[ACPI_STATE_D0].power = 100;
  	device->power.states[ACPI_STATE_D3].flags.valid = 1;
  	device->power.states[ACPI_STATE_D3].power = 0;
c8f7a62cd   Len Brown   Revert "Revert "A...
850

9e89dde2b   Zhang Rui   ACPI: clean up sc...
851
  	/* TBD: System wake support and resource requirements. */
c8f7a62cd   Len Brown   Revert "Revert "A...
852

9e89dde2b   Zhang Rui   ACPI: clean up sc...
853
  	device->power.state = ACPI_STATE_UNKNOWN;
a51e145f3   Zhao Yakui   ACPI: Get the dev...
854
  	acpi_bus_get_power(device->handle, &(device->power.state));
c8f7a62cd   Len Brown   Revert "Revert "A...
855

9e89dde2b   Zhang Rui   ACPI: clean up sc...
856
857
  	return 0;
  }
c8f7a62cd   Len Brown   Revert "Revert "A...
858

4be44fcd3   Len Brown   [ACPI] Lindent al...
859
  static int acpi_bus_get_flags(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
861
862
  	acpi_status status = AE_OK;
  	acpi_handle temp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
865
866
867
868
  
  	/* Presence of _STA indicates 'dynamic_status' */
  	status = acpi_get_handle(device->handle, "_STA", &temp);
  	if (ACPI_SUCCESS(status))
  		device->flags.dynamic_status = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
  	/* Presence of _RMV indicates 'removable' */
  	status = acpi_get_handle(device->handle, "_RMV", &temp);
  	if (ACPI_SUCCESS(status))
  		device->flags.removable = 1;
  
  	/* Presence of _EJD|_EJ0 indicates 'ejectable' */
  	status = acpi_get_handle(device->handle, "_EJD", &temp);
  	if (ACPI_SUCCESS(status))
  		device->flags.ejectable = 1;
  	else {
  		status = acpi_get_handle(device->handle, "_EJ0", &temp);
  		if (ACPI_SUCCESS(status))
  			device->flags.ejectable = 1;
  	}
  
  	/* Presence of _LCK indicates 'lockable' */
  	status = acpi_get_handle(device->handle, "_LCK", &temp);
  	if (ACPI_SUCCESS(status))
  		device->flags.lockable = 1;
  
  	/* Presence of _PS0|_PR0 indicates 'power manageable' */
  	status = acpi_get_handle(device->handle, "_PS0", &temp);
  	if (ACPI_FAILURE(status))
  		status = acpi_get_handle(device->handle, "_PR0", &temp);
  	if (ACPI_SUCCESS(status))
  		device->flags.power_manageable = 1;
  
  	/* Presence of _PRW indicates wake capable */
  	status = acpi_get_handle(device->handle, "_PRW", &temp);
  	if (ACPI_SUCCESS(status))
  		device->flags.wake_capable = 1;
3c5f9be46   Joe Perches   drivers/acpi/: Sp...
900
  	/* TBD: Performance management */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901

d550d98d3   Patrick Mochel   ACPI: delete trac...
902
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  }
c7bcb4e98   Bjorn Helgaas   ACPI: remove redu...
904
  static void acpi_device_get_busid(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
906
907
908
  	char bus_id[5] = { '?', 0 };
  	struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
912
913
914
915
  
  	/*
  	 * Bus ID
  	 * ------
  	 * The device's Bus ID is simply the object name.
  	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
  	 */
859ac9a4b   Bjorn Helgaas   ACPI: identify de...
916
  	if (ACPI_IS_ROOT_DEVICE(device)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  		strcpy(device->pnp.bus_id, "ACPI");
859ac9a4b   Bjorn Helgaas   ACPI: identify de...
918
919
920
921
  		return;
  	}
  
  	switch (device->device_type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
925
926
927
928
  	case ACPI_BUS_TYPE_POWER_BUTTON:
  		strcpy(device->pnp.bus_id, "PWRF");
  		break;
  	case ACPI_BUS_TYPE_SLEEP_BUTTON:
  		strcpy(device->pnp.bus_id, "SLPF");
  		break;
  	default:
66b7ed40a   Bjorn Helgaas   ACPI: remove redu...
929
  		acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
933
934
935
936
937
938
939
940
  		/* Clean up trailing underscores (if any) */
  		for (i = 3; i > 1; i--) {
  			if (bus_id[i] == '_')
  				bus_id[i] = '\0';
  			else
  				break;
  		}
  		strcpy(device->pnp.bus_id, bus_id);
  		break;
  	}
  }
547352660   Zhang Rui   ACPI: bay: Conver...
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
  /*
   * acpi_bay_match - see if a device is an ejectable driver bay
   *
   * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
   * then we can safely call it an ejectable drive bay
   */
  static int acpi_bay_match(struct acpi_device *device){
  	acpi_status status;
  	acpi_handle handle;
  	acpi_handle tmp;
  	acpi_handle phandle;
  
  	handle = device->handle;
  
  	status = acpi_get_handle(handle, "_EJ0", &tmp);
  	if (ACPI_FAILURE(status))
  		return -ENODEV;
  
  	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
  		(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
  		(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
  		(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
  		return 0;
  
  	if (acpi_get_parent(handle, &phandle))
  		return -ENODEV;
  
          if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
                  (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
                  (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
                  (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
                  return 0;
  
  	return -ENODEV;
  }
3620f2f2f   Frank Seidel   ACPI: Fix autload...
976
977
978
979
980
981
982
983
  /*
   * acpi_dock_match - see if a device has a _DCK method
   */
  static int acpi_dock_match(struct acpi_device *device)
  {
  	acpi_handle tmp;
  	return acpi_get_handle(device->handle, "_DCK", &tmp);
  }
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
984
  char *acpi_device_hid(struct acpi_device *device)
15b8dd53f   Bob Moore   ACPICA: Major upd...
985
  {
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
986
  	struct acpi_hardware_id *hid;
15b8dd53f   Bob Moore   ACPICA: Major upd...
987

7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
988
989
990
991
  	hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
  	return hid->id;
  }
  EXPORT_SYMBOL(acpi_device_hid);
15b8dd53f   Bob Moore   ACPICA: Major upd...
992

7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
993
994
995
  static void acpi_add_id(struct acpi_device *device, const char *dev_id)
  {
  	struct acpi_hardware_id *id;
15b8dd53f   Bob Moore   ACPICA: Major upd...
996

7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
997
998
999
  	id = kmalloc(sizeof(*id), GFP_KERNEL);
  	if (!id)
  		return;
15b8dd53f   Bob Moore   ACPICA: Major upd...
1000

7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
1001
1002
1003
1004
  	id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
  	if (!id->id) {
  		kfree(id);
  		return;
15b8dd53f   Bob Moore   ACPICA: Major upd...
1005
  	}
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
1006
1007
  	strcpy(id->id, dev_id);
  	list_add_tail(&id->list, &device->pnp.ids);
15b8dd53f   Bob Moore   ACPICA: Major upd...
1008
  }
222e82ac9   Darrick J. Wong   acpi: Support IBM...
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  /*
   * Old IBM workstations have a DSDT bug wherein the SMBus object
   * lacks the SMBUS01 HID and the methods do not have the necessary "_"
   * prefix.  Work around this.
   */
  static int acpi_ibm_smbus_match(struct acpi_device *device)
  {
  	acpi_handle h_dummy;
  	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
  	int result;
  
  	if (!dmi_name_in_vendors("IBM"))
  		return -ENODEV;
  
  	/* Look for SMBS object */
  	result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
  	if (result)
  		return result;
  
  	if (strcmp("SMBS", path.pointer)) {
  		result = -ENODEV;
  		goto out;
  	}
  
  	/* Does it have the necessary (but misnamed) methods? */
  	result = -ENODEV;
  	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
  	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
  	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
  		result = 0;
  out:
  	kfree(path.pointer);
  	return result;
  }
c7bcb4e98   Bjorn Helgaas   ACPI: remove redu...
1043
  static void acpi_device_set_id(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
1045
  	acpi_status status;
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1046
1047
  	struct acpi_device_info *info;
  	struct acpica_device_id_list *cid_list;
7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
1048
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049

c7bcb4e98   Bjorn Helgaas   ACPI: remove redu...
1050
  	switch (device->device_type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
  	case ACPI_BUS_TYPE_DEVICE:
859ac9a4b   Bjorn Helgaas   ACPI: identify de...
1052
  		if (ACPI_IS_ROOT_DEVICE(device)) {
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1053
  			acpi_add_id(device, ACPI_SYSTEM_HID);
859ac9a4b   Bjorn Helgaas   ACPI: identify de...
1054
1055
  			break;
  		}
66b7ed40a   Bjorn Helgaas   ACPI: remove redu...
1056
  		status = acpi_get_object_info(device->handle, &info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
  		if (ACPI_FAILURE(status)) {
96b2dd1f1   Harvey Harrison   ACPI: replace rem...
1058
1059
  			printk(KERN_ERR PREFIX "%s: Error reading device info
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
  			return;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  		if (info->valid & ACPI_VALID_HID)
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1063
1064
  			acpi_add_id(device, info->hardware_id.string);
  		if (info->valid & ACPI_VALID_CID) {
15b8dd53f   Bob Moore   ACPICA: Major upd...
1065
  			cid_list = &info->compatible_id_list;
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1066
1067
1068
  			for (i = 0; i < cid_list->count; i++)
  				acpi_add_id(device, cid_list->ids[i].string);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
  		if (info->valid & ACPI_VALID_ADR) {
  			device->pnp.bus_address = info->address;
  			device->flags.bus_address = 1;
  		}
ae8433324   Zhang Rui   ACPI: Set fake hi...
1073

a83893ae9   Bjorn Helgaas   ACPI: fix bus sca...
1074
  		kfree(info);
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1075
1076
1077
1078
  		/*
  		 * Some devices don't reliably have _HIDs & _CIDs, so add
  		 * synthetic HIDs to make sure drivers can find them.
  		 */
c3d6de698   Thomas Renninger   ACPI video: if no...
1079
  		if (acpi_is_video_device(device))
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1080
  			acpi_add_id(device, ACPI_VIDEO_HID);
3620f2f2f   Frank Seidel   ACPI: Fix autload...
1081
  		else if (ACPI_SUCCESS(acpi_bay_match(device)))
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1082
  			acpi_add_id(device, ACPI_BAY_HID);
3620f2f2f   Frank Seidel   ACPI: Fix autload...
1083
  		else if (ACPI_SUCCESS(acpi_dock_match(device)))
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1084
  			acpi_add_id(device, ACPI_DOCK_HID);
222e82ac9   Darrick J. Wong   acpi: Support IBM...
1085
1086
  		else if (!acpi_ibm_smbus_match(device))
  			acpi_add_id(device, ACPI_SMBUS_IBM_HID);
b7b30de53   Bjorn Helgaas   ACPI: use _HID wh...
1087
1088
1089
1090
1091
1092
  		else if (!acpi_device_hid(device) &&
  			 ACPI_IS_ROOT_DEVICE(device->parent)) {
  			acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
  			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
  			strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
  		}
547352660   Zhang Rui   ACPI: bay: Conver...
1093

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
1095
  		break;
  	case ACPI_BUS_TYPE_POWER:
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1096
  		acpi_add_id(device, ACPI_POWER_HID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
  		break;
  	case ACPI_BUS_TYPE_PROCESSOR:
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1099
  		acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
  	case ACPI_BUS_TYPE_THERMAL:
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1102
  		acpi_add_id(device, ACPI_THERMAL_HID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
  		break;
  	case ACPI_BUS_TYPE_POWER_BUTTON:
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1105
  		acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
  		break;
  	case ACPI_BUS_TYPE_SLEEP_BUTTON:
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1108
  		acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
1110
  		break;
  	}
b1fbfb2ae   Bjorn Helgaas   ACPI: make sure e...
1111
1112
1113
1114
1115
1116
1117
  	/*
  	 * We build acpi_devices for some objects that don't have _HID or _CID,
  	 * e.g., PCI bridges and slots.  Drivers can't bind to these objects,
  	 * but we do use them indirectly by traversing the acpi_device tree.
  	 * This generic ID isn't useful for driver binding, but it provides
  	 * the useful property that "every acpi_device has an ID."
  	 */
57f3674f5   Bjorn Helgaas   ACPI: simplify bu...
1118
1119
  	if (list_empty(&device->pnp.ids))
  		acpi_add_id(device, "device");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
  }
bc3b07726   Bjorn Helgaas   ACPI: remove acpi...
1121
  static int acpi_device_set_context(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  {
bc3b07726   Bjorn Helgaas   ACPI: remove acpi...
1123
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
1125
1126
1127
  	/*
  	 * Context
  	 * -------
  	 * Attach this 'struct acpi_device' to the ACPI object.  This makes
bc3b07726   Bjorn Helgaas   ACPI: remove acpi...
1128
1129
  	 * resolutions from handle->device very efficient.  Fixed hardware
  	 * devices have no handles, so we skip them.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
  	 */
bc3b07726   Bjorn Helgaas   ACPI: remove acpi...
1131
1132
  	if (!device->handle)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133

bc3b07726   Bjorn Helgaas   ACPI: remove acpi...
1134
1135
1136
1137
1138
1139
1140
1141
  	status = acpi_attach_data(device->handle,
  				  acpi_bus_data_handler, device);
  	if (ACPI_SUCCESS(status))
  		return 0;
  
  	printk(KERN_ERR PREFIX "Error attaching device data
  ");
  	return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
1143
  static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  	if (!dev)
d550d98d3   Patrick Mochel   ACPI: delete trac...
1146
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147

96333578b   Li Shaohua   ACPI: add acpi_bu...
1148
  	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
1890a97ab   Patrick Mochel   ACPI: change regi...
1149
  	device_release_driver(&dev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
  
  	if (!rmdevice)
d550d98d3   Patrick Mochel   ACPI: delete trac...
1152
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153

2786f6e38   Rui Zhang   ACPI: fix Supermi...
1154
1155
1156
  	/*
  	 * unbind _ADR-Based Devices when hot removal
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
1160
  	if (dev->flags.bus_address) {
  		if ((dev->parent) && (dev->parent->ops.unbind))
  			dev->parent->ops.unbind(dev);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
  	acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
d550d98d3   Patrick Mochel   ACPI: delete trac...
1162
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
  }
5c478f499   Bjorn Helgaas   ACPI: add acpi_bu...
1164
1165
  static int acpi_add_single_object(struct acpi_device **child,
  				  acpi_handle handle, int type,
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1166
  				  unsigned long long sta,
5c478f499   Bjorn Helgaas   ACPI: add acpi_bu...
1167
  				  struct acpi_bus_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
  {
77c24888b   Bjorn Helgaas   ACPI: remove unne...
1169
1170
  	int result;
  	struct acpi_device *device;
29aaefa68   Bjorn Helgaas   ACPI: add debug f...
1171
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172

36bcbec7c   Burman Yan   ACPI: replace kma...
1173
  	device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
  	if (!device) {
6468463ab   Len Brown   ACPI: un-export A...
1175
1176
  		printk(KERN_ERR PREFIX "Memory allocation error
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
1177
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179

7f47fa6c2   Bjorn Helgaas   ACPI: maintain a ...
1180
  	INIT_LIST_HEAD(&device->pnp.ids);
caaa6efb3   Bjorn Helgaas   ACPI: save device...
1181
  	device->device_type = type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
  	device->handle = handle;
5c478f499   Bjorn Helgaas   ACPI: add acpi_bu...
1183
  	device->parent = acpi_bus_get_parent(handle);
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1184
  	device->bus_ops = *ops; /* workround for not call .start */
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1185
  	STRUCT_TO_INT(device->status) = sta;
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1186

c7bcb4e98   Bjorn Helgaas   ACPI: remove redu...
1187
  	acpi_device_get_busid(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
1189
1190
1191
  
  	/*
  	 * Flags
  	 * -----
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1192
1193
  	 * Note that we only look for object handles -- cannot evaluate objects
  	 * until we know the device is present and properly initialized.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
1197
1198
1199
  	 */
  	result = acpi_bus_get_flags(device);
  	if (result)
  		goto end;
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
1203
  	 * Initialize Device
  	 * -----------------
  	 * TBD: Synch with Core's enumeration/initialization process.
  	 */
c7bcb4e98   Bjorn Helgaas   ACPI: remove redu...
1204
  	acpi_device_set_id(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  
  	/*
  	 * Power Management
  	 * ----------------
  	 */
  	if (device->flags.power_manageable) {
  		result = acpi_bus_get_power_flags(device);
  		if (result)
  			goto end;
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
1215
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
  	 * Wakeup device management
  	 *-----------------------
  	 */
  	if (device->flags.wake_capable) {
  		result = acpi_bus_get_wakeup_device_flags(device);
  		if (result)
  			goto end;
  	}
  
  	/*
  	 * Performance Management
  	 * ----------------------
  	 */
  	if (device->flags.performance_manageable) {
  		result = acpi_bus_get_perf_flags(device);
  		if (result)
  			goto end;
  	}
bc3b07726   Bjorn Helgaas   ACPI: remove acpi...
1234
  	if ((result = acpi_device_set_context(device)))
f61f92585   Len Brown   Revert "ACPI: Att...
1235
  		goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236

66b7ed40a   Bjorn Helgaas   ACPI: remove redu...
1237
  	result = acpi_device_register(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
  
  	/*
2786f6e38   Rui Zhang   ACPI: fix Supermi...
1240
  	 * Bind _ADR-Based Devices when hot add
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
1242
1243
1244
1245
  	 */
  	if (device->flags.bus_address) {
  		if (device->parent && device->parent->ops.bind)
  			device->parent->ops.bind(device);
  	}
0c526d96a   Alex Chiang   ACPI: clean up wh...
1246
  end:
29aaefa68   Bjorn Helgaas   ACPI: add debug f...
1247
1248
1249
1250
1251
1252
1253
1254
1255
  	if (!result) {
  		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  			"Adding %s [%s] parent %s
  ", dev_name(&device->dev),
  			 (char *) buffer.pointer,
  			 device->parent ? dev_name(&device->parent->dev) :
  					  "(null)"));
  		kfree(buffer.pointer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  		*child = device;
29aaefa68   Bjorn Helgaas   ACPI: add debug f...
1257
  	} else
718fb0de8   Hugh Dickins   ACPI: fix NULL bu...
1258
  		acpi_device_release(&device->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259

d550d98d3   Patrick Mochel   ACPI: delete trac...
1260
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262

778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1263
1264
1265
1266
1267
  #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
  			  ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING)
  
  static int acpi_bus_type_and_status(acpi_handle handle, int *type,
  				    unsigned long long *sta)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  {
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1269
1270
  	acpi_status status;
  	acpi_object_type acpi_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271

778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1272
  	status = acpi_get_type(handle, &acpi_type);
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1273
  	if (ACPI_FAILURE(status))
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1274
  		return -ENODEV;
4be44fcd3   Len Brown   [ACPI] Lindent al...
1275

778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1276
  	switch (acpi_type) {
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1277
1278
  	case ACPI_TYPE_ANY:		/* for ACPI_ROOT_OBJECT */
  	case ACPI_TYPE_DEVICE:
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1279
1280
1281
1282
  		*type = ACPI_BUS_TYPE_DEVICE;
  		status = acpi_bus_get_status_handle(handle, sta);
  		if (ACPI_FAILURE(status))
  			return -ENODEV;
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1283
1284
  		break;
  	case ACPI_TYPE_PROCESSOR:
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1285
1286
1287
1288
  		*type = ACPI_BUS_TYPE_PROCESSOR;
  		status = acpi_bus_get_status_handle(handle, sta);
  		if (ACPI_FAILURE(status))
  			return -ENODEV;
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1289
1290
  		break;
  	case ACPI_TYPE_THERMAL:
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1291
1292
  		*type = ACPI_BUS_TYPE_THERMAL;
  		*sta = ACPI_STA_DEFAULT;
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1293
1294
  		break;
  	case ACPI_TYPE_POWER:
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1295
1296
  		*type = ACPI_BUS_TYPE_POWER;
  		*sta = ACPI_STA_DEFAULT;
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1297
1298
  		break;
  	default:
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1299
  		return -ENODEV;
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1300
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301

778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1302
1303
1304
1305
1306
1307
1308
  	return 0;
  }
  
  static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
  				      void *context, void **return_value)
  {
  	struct acpi_bus_ops *ops = context;
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1309
1310
  	int type;
  	unsigned long long sta;
e3b87f8a9   Bjorn Helgaas   ACPI: handle re-e...
1311
1312
  	struct acpi_device *device;
  	acpi_status status;
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1313
1314
1315
1316
1317
1318
1319
1320
1321
  	int result;
  
  	result = acpi_bus_type_and_status(handle, &type, &sta);
  	if (result)
  		return AE_OK;
  
  	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
  	    !(sta & ACPI_STA_DEVICE_FUNCTIONING))
  		return AE_CTRL_DEPTH;
e3b87f8a9   Bjorn Helgaas   ACPI: handle re-e...
1322
1323
1324
1325
1326
1327
1328
1329
  	/*
  	 * We may already have an acpi_device from a previous enumeration.  If
  	 * so, we needn't add it again, but we may still have to start it.
  	 */
  	device = NULL;
  	acpi_bus_get_device(handle, &device);
  	if (ops->acpi_op_add && !device)
  		acpi_add_single_object(&device, handle, type, sta, ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330

e3b87f8a9   Bjorn Helgaas   ACPI: handle re-e...
1331
  	if (!device)
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1332
  		return AE_CTRL_DEPTH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333

51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1334
1335
  	if (ops->acpi_op_start && !(ops->acpi_op_add)) {
  		status = acpi_start_single_object(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
  		if (ACPI_FAILURE(status))
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1337
1338
  			return AE_CTRL_DEPTH;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339

51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1340
1341
1342
1343
  	if (!*return_value)
  		*return_value = device;
  	return AE_OK;
  }
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1344

51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1345
1346
1347
1348
  static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
  			 struct acpi_device **child)
  {
  	acpi_status status;
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1349
  	void *device = NULL;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1350

51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1351
1352
1353
  	status = acpi_bus_check_add(handle, 0, ops, &device);
  	if (ACPI_SUCCESS(status))
  		acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
2263576cf   Lin Ming   ACPICA: Add post-...
1354
  				    acpi_bus_check_add, NULL, ops, &device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355

51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1356
1357
  	if (child)
  		*child = device;
7779688fc   Thomas Renninger   ACPI: acpi_bus_{s...
1358
1359
1360
1361
1362
  
  	if (device)
  		return 0;
  	else
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364

7779688fc   Thomas Renninger   ACPI: acpi_bus_{s...
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
  /*
   * acpi_bus_add and acpi_bus_start
   *
   * scan a given ACPI tree and (probably recently hot-plugged)
   * create and add or starts found devices.
   *
   * If no devices were found -ENODEV is returned which does not
   * mean that this is a real error, there just have been no suitable
   * ACPI objects in the table trunk from which the kernel could create
   * a device and add/start an appropriate driver.
   */
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1376
  int
4be44fcd3   Len Brown   [ACPI] Lindent al...
1377
1378
  acpi_bus_add(struct acpi_device **child,
  	     struct acpi_device *parent, acpi_handle handle, int type)
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1379
  {
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1380
  	struct acpi_bus_ops ops;
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1381
1382
  	memset(&ops, 0, sizeof(ops));
  	ops.acpi_op_add = 1;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1383

7779688fc   Thomas Renninger   ACPI: acpi_bus_{s...
1384
  	return acpi_bus_scan(handle, &ops, child);
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1385
1386
  }
  EXPORT_SYMBOL(acpi_bus_add);
4be44fcd3   Len Brown   [ACPI] Lindent al...
1387
  int acpi_bus_start(struct acpi_device *device)
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1388
  {
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1389
  	struct acpi_bus_ops ops;
d2f6650a9   Thomas Renninger   ACPI: Add NULL po...
1390
1391
  	if (!device)
  		return -EINVAL;
8e029bf0a   Bjorn Helgaas   ACPI: convert acp...
1392
1393
  	memset(&ops, 0, sizeof(ops));
  	ops.acpi_op_start = 1;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1394

7779688fc   Thomas Renninger   ACPI: acpi_bus_{s...
1395
  	return acpi_bus_scan(device->handle, &ops, NULL);
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1396
1397
  }
  EXPORT_SYMBOL(acpi_bus_start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398

ceaba6630   Kristen Accardi   [PATCH] acpi: exp...
1399
  int acpi_bus_trim(struct acpi_device *start, int rmdevice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
1401
1402
1403
1404
1405
1406
1407
1408
  	acpi_status status;
  	struct acpi_device *parent, *child;
  	acpi_handle phandle, chandle;
  	acpi_object_type type;
  	u32 level = 1;
  	int err = 0;
  
  	parent = start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
1412
1413
  	phandle = start->handle;
  	child = chandle = NULL;
  
  	while ((level > 0) && parent && (!err)) {
  		status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
4be44fcd3   Len Brown   [ACPI] Lindent al...
1414
  					      chandle, &chandle);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
  
  		/*
  		 * If this scope is exhausted then move our way back up.
  		 */
  		if (ACPI_FAILURE(status)) {
  			level--;
  			chandle = phandle;
  			acpi_get_parent(phandle, &phandle);
  			child = parent;
  			parent = parent->parent;
  
  			if (level == 0)
  				err = acpi_bus_remove(child, rmdevice);
  			else
  				err = acpi_bus_remove(child, 1);
  
  			continue;
  		}
  
  		status = acpi_get_type(chandle, &type);
  		if (ACPI_FAILURE(status)) {
  			continue;
  		}
  		/*
  		 * If there is a device corresponding to chandle then
  		 * parse it (depth-first).
  		 */
  		if (acpi_bus_get_device(chandle, &child) == 0) {
  			level++;
  			phandle = chandle;
  			chandle = NULL;
  			parent = child;
  		}
  		continue;
  	}
  	return err;
  }
ceaba6630   Kristen Accardi   [PATCH] acpi: exp...
1452
  EXPORT_SYMBOL_GPL(acpi_bus_trim);
e8b945c9c   Bjorn Helgaas   ACPI: remove unus...
1453
  static int acpi_bus_scan_fixed(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
1455
1456
  	int result = 0;
  	struct acpi_device *device = NULL;
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1457
  	struct acpi_bus_ops ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458

c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1459
1460
1461
  	memset(&ops, 0, sizeof(ops));
  	ops.acpi_op_add = 1;
  	ops.acpi_op_start = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
1463
1464
  	/*
  	 * Enumerate all fixed-feature devices.
  	 */
cee324b14   Alexey Starikovskiy   ACPICA: use new A...
1465
  	if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
5c478f499   Bjorn Helgaas   ACPI: add acpi_bu...
1466
  		result = acpi_add_single_object(&device, NULL,
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1467
  						ACPI_BUS_TYPE_POWER_BUTTON,
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1468
  						ACPI_STA_DEFAULT,
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1469
  						&ops);
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1470
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471

cee324b14   Alexey Starikovskiy   ACPICA: use new A...
1472
  	if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
5c478f499   Bjorn Helgaas   ACPI: add acpi_bu...
1473
  		result = acpi_add_single_object(&device, NULL,
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1474
  						ACPI_BUS_TYPE_SLEEP_BUTTON,
778cbc1d3   Bjorn Helgaas   ACPI: factor out ...
1475
  						ACPI_STA_DEFAULT,
c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1476
  						&ops);
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1477
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478

d550d98d3   Patrick Mochel   ACPI: delete trac...
1479
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
  }
e747f2749   Bjorn Helgaas   ACPI: call acpi_s...
1481
  int __init acpi_scan_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1482
1483
  {
  	int result;
3fb02738b   Rajesh Shah   [PATCH] acpi brid...
1484
  	struct acpi_bus_ops ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485

c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1486
1487
1488
  	memset(&ops, 0, sizeof(ops));
  	ops.acpi_op_add = 1;
  	ops.acpi_op_start = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1489

5b3272655   Patrick Mochel   ACPI: create acpi...
1490
1491
1492
1493
1494
1495
  	result = bus_register(&acpi_bus_type);
  	if (result) {
  		/* We don't want to quit even if we failed to add suspend/resume */
  		printk(KERN_ERR PREFIX "Could not register bus type
  ");
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1496
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
1498
  	 * Enumerate devices in the ACPI namespace.
  	 */
51a85faf2   Bjorn Helgaas   ACPI: use acpi_wa...
1499
  	result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
c04209a79   Alexey Starikovskiy   ACPI: EC: Enable ...
1500

c4168bff3   Li Shaohua   ACPI: add acpi_bu...
1501
  	if (!result)
adc08e203   Bjorn Helgaas   ACPI: enumerate n...
1502
  		result = acpi_bus_scan_fixed();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
  
  	if (result)
  		acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
d550d98d3   Patrick Mochel   ACPI: delete trac...
1506
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  }