Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPIPHP: use ACPI dock driver

Modify the acpiphp driver to use the ACPI dock driver for dock
notifications. Only load the acpiphp driver if we find we have pci dock
devices.

Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Kristen Accardi and committed by
Len Brown
4e8662bb a5e1b940

+87 -519
+1 -2
drivers/pci/hotplug/Makefile
··· 40 40 ibmphp_hpc.o 41 41 42 42 acpiphp-objs := acpiphp_core.o \ 43 - acpiphp_glue.o \ 44 - acpiphp_dock.o 43 + acpiphp_glue.o 45 44 46 45 rpaphp-objs := rpaphp_core.o \ 47 46 rpaphp_pci.o \
+1 -34
drivers/pci/hotplug/acpiphp.h
··· 130 130 131 131 struct list_head sibling; 132 132 struct pci_dev *pci_dev; 133 - 133 + struct notifier_block nb; 134 134 acpi_handle handle; 135 135 136 136 u8 function; /* pci function# */ ··· 148 148 int (*set_attn)(struct hotplug_slot *slot, u8 status); 149 149 int (*get_attn)(struct hotplug_slot *slot, u8 *status); 150 150 struct module *owner; 151 - }; 152 - 153 - 154 - struct dependent_device { 155 - struct list_head device_list; 156 - struct list_head pci_list; 157 - acpi_handle handle; 158 - struct acpiphp_func *func; 159 - }; 160 - 161 - 162 - struct acpiphp_dock_station { 163 - acpi_handle handle; 164 - u32 last_dock_time; 165 - u32 flags; 166 - struct acpiphp_func *dock_bridge; 167 - struct list_head dependent_devices; 168 - struct list_head pci_dependent_devices; 169 151 }; 170 152 171 153 ··· 189 207 #define FUNC_HAS_PS2 (0x00000040) 190 208 #define FUNC_HAS_PS3 (0x00000080) 191 209 #define FUNC_HAS_DCK (0x00000100) 192 - #define FUNC_IS_DD (0x00000200) 193 - 194 - /* dock station flags */ 195 - #define DOCK_DOCKING (0x00000001) 196 - #define DOCK_HAS_BRIDGE (0x00000002) 197 210 198 211 /* function prototypes */ 199 212 ··· 212 235 extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); 213 236 extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); 214 237 extern u32 acpiphp_get_address (struct acpiphp_slot *slot); 215 - 216 - /* acpiphp_dock.c */ 217 - extern int find_dock_station(void); 218 - extern void remove_dock_station(void); 219 - extern void add_dependent_device(struct dependent_device *new_dd); 220 - extern void add_pci_dependent_device(struct dependent_device *new_dd); 221 - extern struct dependent_device *get_dependent_device(acpi_handle handle); 222 - extern int is_dependent_device(acpi_handle handle); 223 - extern int detect_dependent_devices(acpi_handle *bridge_handle); 224 - extern struct dependent_device *alloc_dependent_device(acpi_handle handle); 225 238 226 239 /* variables */ 227 240 extern int acpiphp_debug;
+1 -18
drivers/pci/hotplug/acpiphp_core.c
··· 416 416 417 417 static int __init acpiphp_init(void) 418 418 { 419 - int retval; 420 - int docking_station; 421 - 422 419 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 423 420 424 421 acpiphp_debug = debug; 425 422 426 - docking_station = find_dock_station(); 427 - 428 423 /* read all the ACPI info from the system */ 429 - retval = init_acpi(); 430 - 431 - /* if we have found a docking station, we should 432 - * go ahead and load even if init_acpi has found 433 - * no slots. This handles the case when the _DCK 434 - * method not defined under the actual dock bridge 435 - */ 436 - if (docking_station) 437 - return 0; 438 - else 439 - return retval; 424 + return init_acpi(); 440 425 } 441 426 442 427 ··· 429 444 { 430 445 /* deallocate internal data structures etc. */ 431 446 acpiphp_glue_exit(); 432 - 433 - remove_dock_station(); 434 447 } 435 448 436 449 module_init(acpiphp_init);
-438
drivers/pci/hotplug/acpiphp_dock.c
··· 1 - /* 2 - * ACPI PCI HotPlug dock functions to ACPI CA subsystem 3 - * 4 - * Copyright (C) 2006 Kristen Carlson Accardi (kristen.c.accardi@intel.com) 5 - * Copyright (C) 2006 Intel Corporation 6 - * 7 - * All rights reserved. 8 - * 9 - * This program is free software; you can redistribute it and/or modify 10 - * it under the terms of the GNU General Public License as published by 11 - * the Free Software Foundation; either version 2 of the License, or (at 12 - * your option) any later version. 13 - * 14 - * This program is distributed in the hope that it will be useful, but 15 - * WITHOUT ANY WARRANTY; without even the implied warranty of 16 - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 17 - * NON INFRINGEMENT. See the GNU General Public License for more 18 - * details. 19 - * 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. 23 - * 24 - * Send feedback to <kristen.c.accardi@intel.com> 25 - * 26 - */ 27 - #include <linux/init.h> 28 - #include <linux/module.h> 29 - 30 - #include <linux/kernel.h> 31 - #include <linux/pci.h> 32 - #include <linux/smp_lock.h> 33 - #include <linux/mutex.h> 34 - 35 - #include "../pci.h" 36 - #include "pci_hotplug.h" 37 - #include "acpiphp.h" 38 - 39 - static struct acpiphp_dock_station *ds; 40 - #define MY_NAME "acpiphp_dock" 41 - 42 - 43 - int is_dependent_device(acpi_handle handle) 44 - { 45 - return (get_dependent_device(handle) ? 1 : 0); 46 - } 47 - 48 - 49 - static acpi_status 50 - find_dependent_device(acpi_handle handle, u32 lvl, void *context, void **rv) 51 - { 52 - int *count = (int *)context; 53 - 54 - if (is_dependent_device(handle)) { 55 - (*count)++; 56 - return AE_CTRL_TERMINATE; 57 - } else { 58 - return AE_OK; 59 - } 60 - } 61 - 62 - 63 - 64 - 65 - void add_dependent_device(struct dependent_device *new_dd) 66 - { 67 - list_add_tail(&new_dd->device_list, &ds->dependent_devices); 68 - } 69 - 70 - 71 - void add_pci_dependent_device(struct dependent_device *new_dd) 72 - { 73 - list_add_tail(&new_dd->pci_list, &ds->pci_dependent_devices); 74 - } 75 - 76 - 77 - 78 - struct dependent_device * get_dependent_device(acpi_handle handle) 79 - { 80 - struct dependent_device *dd; 81 - 82 - if (!ds) 83 - return NULL; 84 - 85 - list_for_each_entry(dd, &ds->dependent_devices, device_list) { 86 - if (handle == dd->handle) 87 - return dd; 88 - } 89 - return NULL; 90 - } 91 - 92 - 93 - 94 - struct dependent_device *alloc_dependent_device(acpi_handle handle) 95 - { 96 - struct dependent_device *dd; 97 - 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; 103 - } 104 - return dd; 105 - } 106 - 107 - 108 - 109 - static int is_dock(acpi_handle handle) 110 - { 111 - acpi_status status; 112 - acpi_handle tmp; 113 - 114 - status = acpi_get_handle(handle, "_DCK", &tmp); 115 - if (ACPI_FAILURE(status)) { 116 - return 0; 117 - } 118 - return 1; 119 - } 120 - 121 - 122 - 123 - static int dock_present(void) 124 - { 125 - unsigned long sta; 126 - acpi_status status; 127 - 128 - if (ds) { 129 - status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta); 130 - if (ACPI_SUCCESS(status) && sta) 131 - return 1; 132 - } 133 - return 0; 134 - } 135 - 136 - 137 - 138 - static void eject_dock(void) 139 - { 140 - struct acpi_object_list arg_list; 141 - union acpi_object arg; 142 - 143 - arg_list.count = 1; 144 - arg_list.pointer = &arg; 145 - arg.type = ACPI_TYPE_INTEGER; 146 - arg.integer.value = 1; 147 - 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__); 151 - 152 - return; 153 - } 154 - 155 - 156 - 157 - 158 - static acpi_status handle_dock(int dock) 159 - { 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}; 164 - 165 - dbg("%s: %s\n", __FUNCTION__, dock ? "docking" : "undocking"); 166 - 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); 177 - 178 - return status; 179 - } 180 - 181 - 182 - 183 - static inline void dock(void) 184 - { 185 - handle_dock(1); 186 - } 187 - 188 - 189 - 190 - static inline void undock(void) 191 - { 192 - handle_dock(0); 193 - } 194 - 195 - 196 - 197 - /* 198 - * the _DCK method can do funny things... and sometimes not 199 - * hah-hah funny. 200 - * 201 - * TBD - figure out a way to only call fixups for 202 - * systems that require them. 203 - */ 204 - static void post_dock_fixups(void) 205 - { 206 - struct pci_bus *bus; 207 - u32 buses; 208 - struct dependent_device *dd; 209 - 210 - list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) { 211 - bus = dd->func->slot->bridge->pci_bus; 212 - 213 - /* fixup bad _DCK function that rewrites 214 - * secondary bridge on slot 215 - */ 216 - pci_read_config_dword(bus->self, 217 - PCI_PRIMARY_BUS, 218 - &buses); 219 - 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); 228 - } 229 - } 230 - } 231 - 232 - 233 - 234 - static void hotplug_pci(u32 type) 235 - { 236 - struct dependent_device *dd; 237 - 238 - list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) 239 - handle_hotplug_event_func(dd->handle, type, dd->func); 240 - } 241 - 242 - 243 - 244 - static inline void begin_dock(void) 245 - { 246 - ds->flags |= DOCK_DOCKING; 247 - } 248 - 249 - 250 - static inline void complete_dock(void) 251 - { 252 - ds->flags &= ~(DOCK_DOCKING); 253 - ds->last_dock_time = jiffies; 254 - } 255 - 256 - 257 - static int dock_in_progress(void) 258 - { 259 - if (ds->flags & DOCK_DOCKING || 260 - ds->last_dock_time == jiffies) { 261 - dbg("dock in progress\n"); 262 - return 1; 263 - } 264 - return 0; 265 - } 266 - 267 - 268 - 269 - static void 270 - handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context) 271 - { 272 - dbg("%s: enter\n", __FUNCTION__); 273 - 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; 283 - } 284 - post_dock_fixups(); 285 - hotplug_pci(type); 286 - complete_dock(); 287 - } 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"); 297 - } 298 - break; 299 - } 300 - } 301 - 302 - 303 - 304 - 305 - static acpi_status 306 - find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv) 307 - { 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; 316 - 317 - status = acpi_get_handle(handle, "_EJD", &tmp); 318 - if (ACPI_FAILURE(status)) 319 - return AE_OK; 320 - 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 326 - */ 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; 332 - } 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; 337 - 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; 345 - } 346 - add_dependent_device(dd); 347 - } 348 - 349 - find_ejd_out: 350 - acpi_os_free(ejd_buffer.pointer); 351 - return AE_OK; 352 - } 353 - 354 - 355 - 356 - int detect_dependent_devices(acpi_handle *bridge_handle) 357 - { 358 - acpi_status status; 359 - int count; 360 - 361 - count = 0; 362 - 363 - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, 364 - (u32)1, find_dependent_device, 365 - (void *)&count, NULL); 366 - 367 - return count; 368 - } 369 - 370 - 371 - 372 - 373 - 374 - static acpi_status 375 - find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) 376 - { 377 - int *count = (int *)context; 378 - 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); 385 - 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); 389 - 390 - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 391 - handle_hotplug_event_dock, ds); 392 - (*count)++; 393 - } 394 - 395 - return AE_OK; 396 - } 397 - 398 - 399 - 400 - 401 - int find_dock_station(void) 402 - { 403 - int num = 0; 404 - 405 - ds = NULL; 406 - 407 - /* start from the root object, because some laptops define 408 - * _DCK methods outside the scope of PCI (IBM x-series laptop) 409 - */ 410 - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 411 - ACPI_UINT32_MAX, find_dock, &num, NULL); 412 - 413 - return num; 414 - } 415 - 416 - 417 - 418 - void remove_dock_station(void) 419 - { 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"); 425 - 426 - /* free all dependent devices */ 427 - list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, 428 - device_list) 429 - kfree(dd); 430 - 431 - /* no need to touch the pci_dependent_device list, 432 - * cause all memory was freed above 433 - */ 434 - kfree(ds); 435 - } 436 - } 437 - 438 -
+84 -27
drivers/pci/hotplug/acpiphp_glue.c
··· 116 116 } 117 117 } 118 118 119 + /* callback routine to check for the existance of a pci dock device */ 120 + static acpi_status 121 + is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) 122 + { 123 + int *count = (int *)context; 124 + 125 + if (is_dock_device(handle)) { 126 + (*count)++; 127 + return AE_CTRL_TERMINATE; 128 + } else { 129 + return AE_OK; 130 + } 131 + } 132 + 133 + 134 + 135 + 136 + /* 137 + * the _DCK method can do funny things... and sometimes not 138 + * hah-hah funny. 139 + * 140 + * TBD - figure out a way to only call fixups for 141 + * systems that require them. 142 + */ 143 + static int post_dock_fixups(struct notifier_block *nb, unsigned long val, 144 + void *v) 145 + { 146 + struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); 147 + struct pci_bus *bus = func->slot->bridge->pci_bus; 148 + u32 buses; 149 + 150 + if (!bus->self) 151 + return NOTIFY_OK; 152 + 153 + /* fixup bad _DCK function that rewrites 154 + * secondary bridge on slot 155 + */ 156 + pci_read_config_dword(bus->self, 157 + PCI_PRIMARY_BUS, 158 + &buses); 159 + 160 + if (((buses >> 8) & 0xff) != bus->secondary) { 161 + buses = (buses & 0xff000000) 162 + | ((unsigned int)(bus->primary) << 0) 163 + | ((unsigned int)(bus->secondary) << 8) 164 + | ((unsigned int)(bus->subordinate) << 16); 165 + pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); 166 + } 167 + return NOTIFY_OK; 168 + } 169 + 170 + 171 + 119 172 120 173 /* callback routine to register each ACPI PCI slot object */ 121 174 static acpi_status ··· 177 124 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 178 125 struct acpiphp_slot *slot; 179 126 struct acpiphp_func *newfunc; 180 - struct dependent_device *dd; 181 127 acpi_handle tmp; 182 128 acpi_status status = AE_OK; 183 129 unsigned long adr, sun; ··· 189 137 190 138 status = acpi_get_handle(handle, "_EJ0", &tmp); 191 139 192 - if (ACPI_FAILURE(status) && !(is_dependent_device(handle))) 140 + if (ACPI_FAILURE(status) && !(is_dock_device(handle))) 193 141 return AE_OK; 194 142 195 143 device = (adr >> 16) & 0xffff; ··· 214 162 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 215 163 newfunc->flags |= FUNC_HAS_PS3; 216 164 217 - if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) { 165 + if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) 218 166 newfunc->flags |= FUNC_HAS_DCK; 219 - /* add to devices dependent on dock station, 220 - * because this may actually be the dock bridge 221 - */ 222 - dd = alloc_dependent_device(handle); 223 - if (!dd) 224 - err("Can't allocate memory for " 225 - "new dependent device!\n"); 226 - else 227 - add_dependent_device(dd); 228 - } 229 167 230 168 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 231 169 if (ACPI_FAILURE(status)) ··· 267 225 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 268 226 } 269 227 270 - /* if this is a device dependent on a dock station, 271 - * associate the acpiphp_func to the dependent_device 272 - * struct. 273 - */ 274 - if ((dd = get_dependent_device(handle))) { 275 - newfunc->flags |= FUNC_IS_DD; 276 - /* 277 - * we don't want any devices which is dependent 278 - * on the dock to have it's _EJ0 method executed. 279 - * because we need to run _DCK first. 228 + if (is_dock_device(handle)) { 229 + /* we don't want to call this device's _EJ0 230 + * because we want the dock notify handler 231 + * to call it after it calls _DCK 280 232 */ 281 233 newfunc->flags &= ~FUNC_HAS_EJ0; 282 - dd->func = newfunc; 283 - add_pci_dependent_device(dd); 234 + if (register_hotplug_dock_device(handle, 235 + handle_hotplug_event_func, newfunc)) 236 + dbg("failed to register dock device\n"); 237 + 238 + /* we need to be notified when dock events happen 239 + * outside of the hotplug operation, since we may 240 + * need to do fixups before we can hotplug. 241 + */ 242 + newfunc->nb.notifier_call = post_dock_fixups; 243 + if (register_dock_notifier(&newfunc->nb)) 244 + dbg("failed to register a dock notifier"); 284 245 } 285 246 286 247 /* install notify handler */ ··· 321 276 /* only check slots defined directly below bridge object */ 322 277 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, 323 278 is_ejectable_slot, (void *)&count, NULL); 279 + 280 + /* 281 + * we also need to add this bridge if there is a dock bridge or 282 + * other pci device on a dock station (removable) 283 + */ 284 + if (!count) 285 + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, 286 + (u32)1, is_pci_dock_device, (void *)&count, 287 + NULL); 324 288 325 289 return count; 326 290 } ··· 541 487 goto out; 542 488 543 489 /* check if this bridge has ejectable slots */ 544 - if ((detect_ejectable_slots(handle) > 0) || 545 - (detect_dependent_devices(handle) > 0)) { 490 + if ((detect_ejectable_slots(handle) > 0)) { 546 491 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 547 492 add_p2p_bridge(handle, dev); 548 493 } ··· 658 605 list_for_each_safe (list, tmp, &slot->funcs) { 659 606 struct acpiphp_func *func; 660 607 func = list_entry(list, struct acpiphp_func, sibling); 608 + if (is_dock_device(func->handle)) { 609 + unregister_hotplug_dock_device(func->handle); 610 + unregister_dock_notifier(&func->nb); 611 + } 661 612 if (!(func->flags & FUNC_HAS_DCK)) { 662 613 status = acpi_remove_notify_handler(func->handle, 663 614 ACPI_SYSTEM_NOTIFY,