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
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
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>
36 #include "pci_hotplug.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);
50 find_dependent_device(acpi_handle handle
, u32 lvl
, void *context
, void **rv
)
52 int *count
= (int *)context
;
54 if (is_dependent_device(handle
)) {
56 return AE_CTRL_TERMINATE
;
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
;
85 list_for_each_entry(dd
, &ds
->dependent_devices
, device_list
) {
86 if (handle
== dd
->handle
)
94 struct dependent_device
*alloc_dependent_device(acpi_handle handle
)
96 struct dependent_device
*dd
;
98 dd
= kzalloc(sizeof(*dd
), GFP_KERNEL
);
100 INIT_LIST_HEAD(&dd
->pci_list
);
101 INIT_LIST_HEAD(&dd
->device_list
);
109 static int is_dock(acpi_handle handle
)
114 status
= acpi_get_handle(handle
, "_DCK", &tmp
);
115 if (ACPI_FAILURE(status
)) {
123 static int dock_present(void)
129 status
= acpi_evaluate_integer(ds
->handle
, "_STA", NULL
, &sta
);
130 if (ACPI_SUCCESS(status
) && sta
)
138 static void eject_dock(void)
140 struct acpi_object_list arg_list
;
141 union acpi_object arg
;
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__
);
158 static acpi_status
handle_dock(int dock
)
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 */
169 arg_list
.pointer
= &arg
;
170 arg
.type
= ACPI_TYPE_INTEGER
;
171 arg
.integer
.value
= dock
;
172 status
= acpi_evaluate_object(ds
->handle
, "_DCK",
174 if (ACPI_FAILURE(status
))
175 err("%s: failed to execute _DCK\n", __FUNCTION__
);
176 acpi_os_free(buffer
.pointer
);
183 static inline void dock(void)
190 static inline void undock(void)
198 * the _DCK method can do funny things... and sometimes not
201 * TBD - figure out a way to only call fixups for
202 * systems that require them.
204 static void post_dock_fixups(void)
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
,
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
,
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");
270 handle_hotplug_event_dock(acpi_handle handle
, u32 type
, void *context
)
272 dbg("%s: enter\n", __FUNCTION__
);
275 case ACPI_NOTIFY_BUS_CHECK
:
277 if (!dock_in_progress() && dock_present()) {
280 if (!dock_present()) {
281 err("Unable to dock!\n");
289 case ACPI_NOTIFY_EJECT_REQUEST
:
290 dbg("EJECT request\n");
291 if (!dock_in_progress() && dock_present()) {
296 err("Unable to undock!\n");
306 find_dock_ejd(acpi_handle handle
, u32 lvl
, void *context
, void **rv
)
310 acpi_handle dck_handle
= (acpi_handle
) context
;
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
))
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");
333 ejd_obj
= ejd_buffer
.pointer
;
334 status
= acpi_get_handle(NULL
, ejd_obj
->string
.pointer
, &tmp
);
335 if (ACPI_FAILURE(status
))
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
);
343 err("Can't allocate memory for dependent device!\n");
346 add_dependent_device(dd
);
350 acpi_os_free(ejd_buffer
.pointer
);
356 int detect_dependent_devices(acpi_handle
*bridge_handle
)
363 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, bridge_handle
,
364 (u32
)1, find_dependent_device
,
365 (void *)&count
, NULL
);
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
);
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
);
401 int find_dock_station(void)
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
);
418 void remove_dock_station(void)
420 struct dependent_device
*dd
, *tmp
;
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
,
431 /* no need to touch the pci_dependent_device list,
432 * cause all memory was freed above