[PATCH] PCI: disable msi mode in pci_disable_device
[linux-2.6/mini2440.git] / drivers / pci / hotplug / acpiphp_dock.c
blob4f1aaf1283128c0a7c045343afb2d5bcd7722d46
1 /*
2 * ACPI PCI HotPlug dock functions to ACPI CA subsystem
4 * Copyright (C) 2006 Kristen Carlson Accardi (kristen.c.accardi@intel.com)
5 * Copyright (C) 2006 Intel Corporation
7 * All rights reserved.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
17 * NON INFRINGEMENT. See the GNU General Public License for more
18 * details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Send feedback to <kristen.c.accardi@intel.com>
27 #include <linux/init.h>
28 #include <linux/module.h>
30 #include <linux/kernel.h>
31 #include <linux/pci.h>
32 #include <linux/smp_lock.h>
33 #include <linux/mutex.h>
35 #include "../pci.h"
36 #include "pci_hotplug.h"
37 #include "acpiphp.h"
39 static struct acpiphp_dock_station *ds;
40 #define MY_NAME "acpiphp_dock"
43 int is_dependent_device(acpi_handle handle)
45 return (get_dependent_device(handle) ? 1 : 0);
49 static acpi_status
50 find_dependent_device(acpi_handle handle, u32 lvl, void *context, void **rv)
52 int *count = (int *)context;
54 if (is_dependent_device(handle)) {
55 (*count)++;
56 return AE_CTRL_TERMINATE;
57 } else {
58 return AE_OK;
65 void add_dependent_device(struct dependent_device *new_dd)
67 list_add_tail(&new_dd->device_list, &ds->dependent_devices);
71 void add_pci_dependent_device(struct dependent_device *new_dd)
73 list_add_tail(&new_dd->pci_list, &ds->pci_dependent_devices);
78 struct dependent_device * get_dependent_device(acpi_handle handle)
80 struct dependent_device *dd;
82 if (!ds)
83 return NULL;
85 list_for_each_entry(dd, &ds->dependent_devices, device_list) {
86 if (handle == dd->handle)
87 return dd;
89 return NULL;
94 struct dependent_device *alloc_dependent_device(acpi_handle handle)
96 struct dependent_device *dd;
98 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
99 if (dd) {
100 INIT_LIST_HEAD(&dd->pci_list);
101 INIT_LIST_HEAD(&dd->device_list);
102 dd->handle = handle;
104 return dd;
109 static int is_dock(acpi_handle handle)
111 acpi_status status;
112 acpi_handle tmp;
114 status = acpi_get_handle(handle, "_DCK", &tmp);
115 if (ACPI_FAILURE(status)) {
116 return 0;
118 return 1;
123 static int dock_present(void)
125 unsigned long sta;
126 acpi_status status;
128 if (ds) {
129 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
130 if (ACPI_SUCCESS(status) && sta)
131 return 1;
133 return 0;
138 static void eject_dock(void)
140 struct acpi_object_list arg_list;
141 union acpi_object arg;
143 arg_list.count = 1;
144 arg_list.pointer = &arg;
145 arg.type = ACPI_TYPE_INTEGER;
146 arg.integer.value = 1;
148 if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
149 &arg_list, NULL)) || dock_present())
150 warn("%s: failed to eject dock!\n", __FUNCTION__);
152 return;
158 static acpi_status handle_dock(int dock)
160 acpi_status status;
161 struct acpi_object_list arg_list;
162 union acpi_object arg;
163 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
165 dbg("%s: %s\n", __FUNCTION__, dock ? "docking" : "undocking");
167 /* _DCK method has one argument */
168 arg_list.count = 1;
169 arg_list.pointer = &arg;
170 arg.type = ACPI_TYPE_INTEGER;
171 arg.integer.value = dock;
172 status = acpi_evaluate_object(ds->handle, "_DCK",
173 &arg_list, &buffer);
174 if (ACPI_FAILURE(status))
175 err("%s: failed to execute _DCK\n", __FUNCTION__);
176 acpi_os_free(buffer.pointer);
178 return status;
183 static inline void dock(void)
185 handle_dock(1);
190 static inline void undock(void)
192 handle_dock(0);
198 * the _DCK method can do funny things... and sometimes not
199 * hah-hah funny.
201 * TBD - figure out a way to only call fixups for
202 * systems that require them.
204 static void post_dock_fixups(void)
206 struct pci_bus *bus;
207 u32 buses;
208 struct dependent_device *dd;
210 list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) {
211 bus = dd->func->slot->bridge->pci_bus;
213 /* fixup bad _DCK function that rewrites
214 * secondary bridge on slot
216 pci_read_config_dword(bus->self,
217 PCI_PRIMARY_BUS,
218 &buses);
220 if (((buses >> 8) & 0xff) != bus->secondary) {
221 buses = (buses & 0xff000000)
222 | ((unsigned int)(bus->primary) << 0)
223 | ((unsigned int)(bus->secondary) << 8)
224 | ((unsigned int)(bus->subordinate) << 16);
225 pci_write_config_dword(bus->self,
226 PCI_PRIMARY_BUS,
227 buses);
234 static void hotplug_pci(u32 type)
236 struct dependent_device *dd;
238 list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list)
239 handle_hotplug_event_func(dd->handle, type, dd->func);
244 static inline void begin_dock(void)
246 ds->flags |= DOCK_DOCKING;
250 static inline void complete_dock(void)
252 ds->flags &= ~(DOCK_DOCKING);
253 ds->last_dock_time = jiffies;
257 static int dock_in_progress(void)
259 if (ds->flags & DOCK_DOCKING ||
260 ds->last_dock_time == jiffies) {
261 dbg("dock in progress\n");
262 return 1;
264 return 0;
269 static void
270 handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
272 dbg("%s: enter\n", __FUNCTION__);
274 switch (type) {
275 case ACPI_NOTIFY_BUS_CHECK:
276 dbg("BUS Check\n");
277 if (!dock_in_progress() && dock_present()) {
278 begin_dock();
279 dock();
280 if (!dock_present()) {
281 err("Unable to dock!\n");
282 break;
284 post_dock_fixups();
285 hotplug_pci(type);
286 complete_dock();
288 break;
289 case ACPI_NOTIFY_EJECT_REQUEST:
290 dbg("EJECT request\n");
291 if (!dock_in_progress() && dock_present()) {
292 hotplug_pci(type);
293 undock();
294 eject_dock();
295 if (dock_present())
296 err("Unable to undock!\n");
298 break;
305 static acpi_status
306 find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv)
308 acpi_status status;
309 acpi_handle tmp;
310 acpi_handle dck_handle = (acpi_handle) context;
311 char objname[64];
312 struct acpi_buffer buffer = { .length = sizeof(objname),
313 .pointer = objname };
314 struct acpi_buffer ejd_buffer = {ACPI_ALLOCATE_BUFFER, NULL};
315 union acpi_object *ejd_obj;
317 status = acpi_get_handle(handle, "_EJD", &tmp);
318 if (ACPI_FAILURE(status))
319 return AE_OK;
321 /* make sure we are dependent on the dock device,
322 * by executing the _EJD method, then getting a handle
323 * to the device referenced by that name. If that
324 * device handle is the same handle as the dock station
325 * handle, then we are a device dependent on the dock station
327 acpi_get_name(dck_handle, ACPI_FULL_PATHNAME, &buffer);
328 status = acpi_evaluate_object(handle, "_EJD", NULL, &ejd_buffer);
329 if (ACPI_FAILURE(status)) {
330 err("Unable to execute _EJD!\n");
331 goto find_ejd_out;
333 ejd_obj = ejd_buffer.pointer;
334 status = acpi_get_handle(NULL, ejd_obj->string.pointer, &tmp);
335 if (ACPI_FAILURE(status))
336 goto find_ejd_out;
338 if (tmp == dck_handle) {
339 struct dependent_device *dd;
340 dbg("%s: found device dependent on dock\n", __FUNCTION__);
341 dd = alloc_dependent_device(handle);
342 if (!dd) {
343 err("Can't allocate memory for dependent device!\n");
344 goto find_ejd_out;
346 add_dependent_device(dd);
349 find_ejd_out:
350 acpi_os_free(ejd_buffer.pointer);
351 return AE_OK;
356 int detect_dependent_devices(acpi_handle *bridge_handle)
358 acpi_status status;
359 int count;
361 count = 0;
363 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
364 (u32)1, find_dependent_device,
365 (void *)&count, NULL);
367 return count;
374 static acpi_status
375 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
377 int *count = (int *)context;
379 if (is_dock(handle)) {
380 dbg("%s: found dock\n", __FUNCTION__);
381 ds = kzalloc(sizeof(*ds), GFP_KERNEL);
382 ds->handle = handle;
383 INIT_LIST_HEAD(&ds->dependent_devices);
384 INIT_LIST_HEAD(&ds->pci_dependent_devices);
386 /* look for devices dependent on dock station */
387 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
388 ACPI_UINT32_MAX, find_dock_ejd, handle, NULL);
390 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
391 handle_hotplug_event_dock, ds);
392 (*count)++;
395 return AE_OK;
401 int find_dock_station(void)
403 int num = 0;
405 ds = NULL;
407 /* start from the root object, because some laptops define
408 * _DCK methods outside the scope of PCI (IBM x-series laptop)
410 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
411 ACPI_UINT32_MAX, find_dock, &num, NULL);
413 return num;
418 void remove_dock_station(void)
420 struct dependent_device *dd, *tmp;
421 if (ds) {
422 if (ACPI_FAILURE(acpi_remove_notify_handler(ds->handle,
423 ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
424 err("failed to remove dock notify handler\n");
426 /* free all dependent devices */
427 list_for_each_entry_safe(dd, tmp, &ds->dependent_devices,
428 device_list)
429 kfree(dd);
431 /* no need to touch the pci_dependent_device list,
432 * cause all memory was freed above
434 kfree(ds);