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

Configure Feed

Select the types of activity you want to include in your feed.

at c9a28fa7b9ac19b676deefa0a171ce7df8755c08 929 lines 25 kB view raw
1/* 2 * dock.c - ACPI dock station driver 3 * 4 * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com> 5 * 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or (at 11 * your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 21 * 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 */ 24 25#include <linux/kernel.h> 26#include <linux/module.h> 27#include <linux/init.h> 28#include <linux/types.h> 29#include <linux/notifier.h> 30#include <linux/platform_device.h> 31#include <linux/jiffies.h> 32#include <linux/stddef.h> 33#include <acpi/acpi_bus.h> 34#include <acpi/acpi_drivers.h> 35 36#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" 37 38ACPI_MODULE_NAME("dock"); 39MODULE_AUTHOR("Kristen Carlson Accardi"); 40MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); 41MODULE_LICENSE("GPL"); 42 43static int immediate_undock = 1; 44module_param(immediate_undock, bool, 0644); 45MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " 46 "undock immediately when the undock button is pressed, 0 will cause" 47 " the driver to wait for userspace to write the undock sysfs file " 48 " before undocking"); 49 50static struct atomic_notifier_head dock_notifier_list; 51static struct platform_device *dock_device; 52static char dock_device_name[] = "dock"; 53 54struct dock_station { 55 acpi_handle handle; 56 unsigned long last_dock_time; 57 u32 flags; 58 spinlock_t dd_lock; 59 struct mutex hp_lock; 60 struct list_head dependent_devices; 61 struct list_head hotplug_devices; 62}; 63 64struct dock_dependent_device { 65 struct list_head list; 66 struct list_head hotplug_list; 67 acpi_handle handle; 68 acpi_notify_handler handler; 69 void *context; 70}; 71 72#define DOCK_DOCKING 0x00000001 73#define DOCK_UNDOCKING 0x00000002 74#define DOCK_EVENT 3 75#define UNDOCK_EVENT 2 76 77static struct dock_station *dock_station; 78 79/***************************************************************************** 80 * Dock Dependent device functions * 81 *****************************************************************************/ 82/** 83 * alloc_dock_dependent_device - allocate and init a dependent device 84 * @handle: the acpi_handle of the dependent device 85 * 86 * Allocate memory for a dependent device structure for a device referenced 87 * by the acpi handle 88 */ 89static struct dock_dependent_device * 90alloc_dock_dependent_device(acpi_handle handle) 91{ 92 struct dock_dependent_device *dd; 93 94 dd = kzalloc(sizeof(*dd), GFP_KERNEL); 95 if (dd) { 96 dd->handle = handle; 97 INIT_LIST_HEAD(&dd->list); 98 INIT_LIST_HEAD(&dd->hotplug_list); 99 } 100 return dd; 101} 102 103/** 104 * add_dock_dependent_device - associate a device with the dock station 105 * @ds: The dock station 106 * @dd: The dependent device 107 * 108 * Add the dependent device to the dock's dependent device list. 109 */ 110static void 111add_dock_dependent_device(struct dock_station *ds, 112 struct dock_dependent_device *dd) 113{ 114 spin_lock(&ds->dd_lock); 115 list_add_tail(&dd->list, &ds->dependent_devices); 116 spin_unlock(&ds->dd_lock); 117} 118 119/** 120 * dock_add_hotplug_device - associate a hotplug handler with the dock station 121 * @ds: The dock station 122 * @dd: The dependent device struct 123 * 124 * Add the dependent device to the dock's hotplug device list 125 */ 126static void 127dock_add_hotplug_device(struct dock_station *ds, 128 struct dock_dependent_device *dd) 129{ 130 mutex_lock(&ds->hp_lock); 131 list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); 132 mutex_unlock(&ds->hp_lock); 133} 134 135/** 136 * dock_del_hotplug_device - remove a hotplug handler from the dock station 137 * @ds: The dock station 138 * @dd: the dependent device struct 139 * 140 * Delete the dependent device from the dock's hotplug device list 141 */ 142static void 143dock_del_hotplug_device(struct dock_station *ds, 144 struct dock_dependent_device *dd) 145{ 146 mutex_lock(&ds->hp_lock); 147 list_del(&dd->hotplug_list); 148 mutex_unlock(&ds->hp_lock); 149} 150 151/** 152 * find_dock_dependent_device - get a device dependent on this dock 153 * @ds: the dock station 154 * @handle: the acpi_handle of the device we want 155 * 156 * iterate over the dependent device list for this dock. If the 157 * dependent device matches the handle, return. 158 */ 159static struct dock_dependent_device * 160find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) 161{ 162 struct dock_dependent_device *dd; 163 164 spin_lock(&ds->dd_lock); 165 list_for_each_entry(dd, &ds->dependent_devices, list) { 166 if (handle == dd->handle) { 167 spin_unlock(&ds->dd_lock); 168 return dd; 169 } 170 } 171 spin_unlock(&ds->dd_lock); 172 return NULL; 173} 174 175/***************************************************************************** 176 * Dock functions * 177 *****************************************************************************/ 178/** 179 * is_dock - see if a device is a dock station 180 * @handle: acpi handle of the device 181 * 182 * If an acpi object has a _DCK method, then it is by definition a dock 183 * station, so return true. 184 */ 185static int is_dock(acpi_handle handle) 186{ 187 acpi_status status; 188 acpi_handle tmp; 189 190 status = acpi_get_handle(handle, "_DCK", &tmp); 191 if (ACPI_FAILURE(status)) 192 return 0; 193 return 1; 194} 195 196/** 197 * is_dock_device - see if a device is on a dock station 198 * @handle: acpi handle of the device 199 * 200 * If this device is either the dock station itself, 201 * or is a device dependent on the dock station, then it 202 * is a dock device 203 */ 204int is_dock_device(acpi_handle handle) 205{ 206 if (!dock_station) 207 return 0; 208 209 if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) 210 return 1; 211 212 return 0; 213} 214 215EXPORT_SYMBOL_GPL(is_dock_device); 216 217/** 218 * dock_present - see if the dock station is present. 219 * @ds: the dock station 220 * 221 * execute the _STA method. note that present does not 222 * imply that we are docked. 223 */ 224static int dock_present(struct dock_station *ds) 225{ 226 unsigned long sta; 227 acpi_status status; 228 229 if (ds) { 230 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta); 231 if (ACPI_SUCCESS(status) && sta) 232 return 1; 233 } 234 return 0; 235} 236 237 238 239/** 240 * dock_create_acpi_device - add new devices to acpi 241 * @handle - handle of the device to add 242 * 243 * This function will create a new acpi_device for the given 244 * handle if one does not exist already. This should cause 245 * acpi to scan for drivers for the given devices, and call 246 * matching driver's add routine. 247 * 248 * Returns a pointer to the acpi_device corresponding to the handle. 249 */ 250static struct acpi_device * dock_create_acpi_device(acpi_handle handle) 251{ 252 struct acpi_device *device = NULL; 253 struct acpi_device *parent_device; 254 acpi_handle parent; 255 int ret; 256 257 if (acpi_bus_get_device(handle, &device)) { 258 /* 259 * no device created for this object, 260 * so we should create one. 261 */ 262 acpi_get_parent(handle, &parent); 263 if (acpi_bus_get_device(parent, &parent_device)) 264 parent_device = NULL; 265 266 ret = acpi_bus_add(&device, parent_device, handle, 267 ACPI_BUS_TYPE_DEVICE); 268 if (ret) { 269 pr_debug("error adding bus, %x\n", 270 -ret); 271 return NULL; 272 } 273 } 274 return device; 275} 276 277/** 278 * dock_remove_acpi_device - remove the acpi_device struct from acpi 279 * @handle - the handle of the device to remove 280 * 281 * Tell acpi to remove the acpi_device. This should cause any loaded 282 * driver to have it's remove routine called. 283 */ 284static void dock_remove_acpi_device(acpi_handle handle) 285{ 286 struct acpi_device *device; 287 int ret; 288 289 if (!acpi_bus_get_device(handle, &device)) { 290 ret = acpi_bus_trim(device, 1); 291 if (ret) 292 pr_debug("error removing bus, %x\n", -ret); 293 } 294} 295 296 297/** 298 * hotplug_dock_devices - insert or remove devices on the dock station 299 * @ds: the dock station 300 * @event: either bus check or eject request 301 * 302 * Some devices on the dock station need to have drivers called 303 * to perform hotplug operations after a dock event has occurred. 304 * Traverse the list of dock devices that have registered a 305 * hotplug handler, and call the handler. 306 */ 307static void hotplug_dock_devices(struct dock_station *ds, u32 event) 308{ 309 struct dock_dependent_device *dd; 310 311 mutex_lock(&ds->hp_lock); 312 313 /* 314 * First call driver specific hotplug functions 315 */ 316 list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { 317 if (dd->handler) 318 dd->handler(dd->handle, event, dd->context); 319 } 320 321 /* 322 * Now make sure that an acpi_device is created for each 323 * dependent device, or removed if this is an eject request. 324 * This will cause acpi_drivers to be stopped/started if they 325 * exist 326 */ 327 list_for_each_entry(dd, &ds->dependent_devices, list) { 328 if (event == ACPI_NOTIFY_EJECT_REQUEST) 329 dock_remove_acpi_device(dd->handle); 330 else 331 dock_create_acpi_device(dd->handle); 332 } 333 mutex_unlock(&ds->hp_lock); 334} 335 336static void dock_event(struct dock_station *ds, u32 event, int num) 337{ 338 struct device *dev = &dock_device->dev; 339 char event_string[13]; 340 char *envp[] = { event_string, NULL }; 341 342 if (num == UNDOCK_EVENT) 343 sprintf(event_string, "EVENT=undock"); 344 else 345 sprintf(event_string, "EVENT=dock"); 346 347 /* 348 * Indicate that the status of the dock station has 349 * changed. 350 */ 351 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); 352} 353 354/** 355 * eject_dock - respond to a dock eject request 356 * @ds: the dock station 357 * 358 * This is called after _DCK is called, to execute the dock station's 359 * _EJ0 method. 360 */ 361static void eject_dock(struct dock_station *ds) 362{ 363 struct acpi_object_list arg_list; 364 union acpi_object arg; 365 acpi_status status; 366 acpi_handle tmp; 367 368 /* all dock devices should have _EJ0, but check anyway */ 369 status = acpi_get_handle(ds->handle, "_EJ0", &tmp); 370 if (ACPI_FAILURE(status)) { 371 pr_debug("No _EJ0 support for dock device\n"); 372 return; 373 } 374 375 arg_list.count = 1; 376 arg_list.pointer = &arg; 377 arg.type = ACPI_TYPE_INTEGER; 378 arg.integer.value = 1; 379 380 if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", 381 &arg_list, NULL))) 382 pr_debug("Failed to evaluate _EJ0!\n"); 383} 384 385/** 386 * handle_dock - handle a dock event 387 * @ds: the dock station 388 * @dock: to dock, or undock - that is the question 389 * 390 * Execute the _DCK method in response to an acpi event 391 */ 392static void handle_dock(struct dock_station *ds, int dock) 393{ 394 acpi_status status; 395 struct acpi_object_list arg_list; 396 union acpi_object arg; 397 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 398 struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 399 400 acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); 401 402 printk(KERN_INFO PREFIX "%s - %s\n", 403 (char *)name_buffer.pointer, dock ? "docking" : "undocking"); 404 405 /* _DCK method has one argument */ 406 arg_list.count = 1; 407 arg_list.pointer = &arg; 408 arg.type = ACPI_TYPE_INTEGER; 409 arg.integer.value = dock; 410 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); 411 if (ACPI_FAILURE(status)) 412 printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", 413 (char *)name_buffer.pointer); 414 kfree(buffer.pointer); 415 kfree(name_buffer.pointer); 416} 417 418static inline void dock(struct dock_station *ds) 419{ 420 handle_dock(ds, 1); 421} 422 423static inline void undock(struct dock_station *ds) 424{ 425 handle_dock(ds, 0); 426} 427 428static inline void begin_dock(struct dock_station *ds) 429{ 430 ds->flags |= DOCK_DOCKING; 431} 432 433static inline void complete_dock(struct dock_station *ds) 434{ 435 ds->flags &= ~(DOCK_DOCKING); 436 ds->last_dock_time = jiffies; 437} 438 439static inline void begin_undock(struct dock_station *ds) 440{ 441 ds->flags |= DOCK_UNDOCKING; 442} 443 444static inline void complete_undock(struct dock_station *ds) 445{ 446 ds->flags &= ~(DOCK_UNDOCKING); 447} 448 449/** 450 * dock_in_progress - see if we are in the middle of handling a dock event 451 * @ds: the dock station 452 * 453 * Sometimes while docking, false dock events can be sent to the driver 454 * because good connections aren't made or some other reason. Ignore these 455 * if we are in the middle of doing something. 456 */ 457static int dock_in_progress(struct dock_station *ds) 458{ 459 if ((ds->flags & DOCK_DOCKING) || 460 time_before(jiffies, (ds->last_dock_time + HZ))) 461 return 1; 462 return 0; 463} 464 465/** 466 * register_dock_notifier - add yourself to the dock notifier list 467 * @nb: the callers notifier block 468 * 469 * If a driver wishes to be notified about dock events, they can 470 * use this function to put a notifier block on the dock notifier list. 471 * this notifier call chain will be called after a dock event, but 472 * before hotplugging any new devices. 473 */ 474int register_dock_notifier(struct notifier_block *nb) 475{ 476 if (!dock_station) 477 return -ENODEV; 478 479 return atomic_notifier_chain_register(&dock_notifier_list, nb); 480} 481 482EXPORT_SYMBOL_GPL(register_dock_notifier); 483 484/** 485 * unregister_dock_notifier - remove yourself from the dock notifier list 486 * @nb: the callers notifier block 487 */ 488void unregister_dock_notifier(struct notifier_block *nb) 489{ 490 if (!dock_station) 491 return; 492 493 atomic_notifier_chain_unregister(&dock_notifier_list, nb); 494} 495 496EXPORT_SYMBOL_GPL(unregister_dock_notifier); 497 498/** 499 * register_hotplug_dock_device - register a hotplug function 500 * @handle: the handle of the device 501 * @handler: the acpi_notifier_handler to call after docking 502 * @context: device specific data 503 * 504 * If a driver would like to perform a hotplug operation after a dock 505 * event, they can register an acpi_notifiy_handler to be called by 506 * the dock driver after _DCK is executed. 507 */ 508int 509register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, 510 void *context) 511{ 512 struct dock_dependent_device *dd; 513 514 if (!dock_station) 515 return -ENODEV; 516 517 /* 518 * make sure this handle is for a device dependent on the dock, 519 * this would include the dock station itself 520 */ 521 dd = find_dock_dependent_device(dock_station, handle); 522 if (dd) { 523 dd->handler = handler; 524 dd->context = context; 525 dock_add_hotplug_device(dock_station, dd); 526 return 0; 527 } 528 529 return -EINVAL; 530} 531 532EXPORT_SYMBOL_GPL(register_hotplug_dock_device); 533 534/** 535 * unregister_hotplug_dock_device - remove yourself from the hotplug list 536 * @handle: the acpi handle of the device 537 */ 538void unregister_hotplug_dock_device(acpi_handle handle) 539{ 540 struct dock_dependent_device *dd; 541 542 if (!dock_station) 543 return; 544 545 dd = find_dock_dependent_device(dock_station, handle); 546 if (dd) 547 dock_del_hotplug_device(dock_station, dd); 548} 549 550EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); 551 552/** 553 * handle_eject_request - handle an undock request checking for error conditions 554 * 555 * Check to make sure the dock device is still present, then undock and 556 * hotremove all the devices that may need removing. 557 */ 558static int handle_eject_request(struct dock_station *ds, u32 event) 559{ 560 if (!dock_present(ds)) 561 return -ENODEV; 562 563 if (dock_in_progress(ds)) 564 return -EBUSY; 565 566 /* 567 * here we need to generate the undock 568 * event prior to actually doing the undock 569 * so that the device struct still exists. 570 */ 571 dock_event(ds, event, UNDOCK_EVENT); 572 hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); 573 undock(ds); 574 eject_dock(ds); 575 if (dock_present(ds)) { 576 printk(KERN_ERR PREFIX "Unable to undock!\n"); 577 return -EBUSY; 578 } 579 complete_undock(ds); 580 return 0; 581} 582 583/** 584 * dock_notify - act upon an acpi dock notification 585 * @handle: the dock station handle 586 * @event: the acpi event 587 * @data: our driver data struct 588 * 589 * If we are notified to dock, then check to see if the dock is 590 * present and then dock. Notify all drivers of the dock event, 591 * and then hotplug and devices that may need hotplugging. 592 */ 593static void dock_notify(acpi_handle handle, u32 event, void *data) 594{ 595 struct dock_station *ds = data; 596 597 switch (event) { 598 case ACPI_NOTIFY_BUS_CHECK: 599 if (!dock_in_progress(ds) && dock_present(ds)) { 600 begin_dock(ds); 601 dock(ds); 602 if (!dock_present(ds)) { 603 printk(KERN_ERR PREFIX "Unable to dock!\n"); 604 break; 605 } 606 atomic_notifier_call_chain(&dock_notifier_list, 607 event, NULL); 608 hotplug_dock_devices(ds, event); 609 complete_dock(ds); 610 dock_event(ds, event, DOCK_EVENT); 611 } 612 break; 613 case ACPI_NOTIFY_DEVICE_CHECK: 614 /* 615 * According to acpi spec 3.0a, if a DEVICE_CHECK notification 616 * is sent and _DCK is present, it is assumed to mean an 617 * undock request. This notify routine will only be called 618 * for objects defining _DCK, so we will fall through to eject 619 * request here. However, we will pass an eject request through 620 * to the driver who wish to hotplug. 621 */ 622 case ACPI_NOTIFY_EJECT_REQUEST: 623 begin_undock(ds); 624 if (immediate_undock) 625 handle_eject_request(ds, event); 626 else 627 dock_event(ds, event, UNDOCK_EVENT); 628 break; 629 default: 630 printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); 631 } 632} 633 634/** 635 * find_dock_devices - find devices on the dock station 636 * @handle: the handle of the device we are examining 637 * @lvl: unused 638 * @context: the dock station private data 639 * @rv: unused 640 * 641 * This function is called by acpi_walk_namespace. It will 642 * check to see if an object has an _EJD method. If it does, then it 643 * will see if it is dependent on the dock station. 644 */ 645static acpi_status 646find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) 647{ 648 acpi_status status; 649 acpi_handle tmp, parent; 650 struct dock_station *ds = context; 651 struct dock_dependent_device *dd; 652 653 status = acpi_bus_get_ejd(handle, &tmp); 654 if (ACPI_FAILURE(status)) { 655 /* try the parent device as well */ 656 status = acpi_get_parent(handle, &parent); 657 if (ACPI_FAILURE(status)) 658 goto fdd_out; 659 /* see if parent is dependent on dock */ 660 status = acpi_bus_get_ejd(parent, &tmp); 661 if (ACPI_FAILURE(status)) 662 goto fdd_out; 663 } 664 665 if (tmp == ds->handle) { 666 dd = alloc_dock_dependent_device(handle); 667 if (dd) 668 add_dock_dependent_device(ds, dd); 669 } 670fdd_out: 671 return AE_OK; 672} 673 674/* 675 * show_docked - read method for "docked" file in sysfs 676 */ 677static ssize_t show_docked(struct device *dev, 678 struct device_attribute *attr, char *buf) 679{ 680 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); 681 682} 683DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); 684 685/* 686 * show_flags - read method for flags file in sysfs 687 */ 688static ssize_t show_flags(struct device *dev, 689 struct device_attribute *attr, char *buf) 690{ 691 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); 692 693} 694DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); 695 696/* 697 * write_undock - write method for "undock" file in sysfs 698 */ 699static ssize_t write_undock(struct device *dev, struct device_attribute *attr, 700 const char *buf, size_t count) 701{ 702 int ret; 703 704 if (!count) 705 return -EINVAL; 706 707 ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); 708 return ret ? ret: count; 709} 710DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); 711 712/* 713 * show_dock_uid - read method for "uid" file in sysfs 714 */ 715static ssize_t show_dock_uid(struct device *dev, 716 struct device_attribute *attr, char *buf) 717{ 718 unsigned long lbuf; 719 acpi_status status = acpi_evaluate_integer(dock_station->handle, 720 "_UID", NULL, &lbuf); 721 if (ACPI_FAILURE(status)) 722 return 0; 723 724 return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); 725} 726DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); 727 728/** 729 * dock_add - add a new dock station 730 * @handle: the dock station handle 731 * 732 * allocated and initialize a new dock station device. Find all devices 733 * that are on the dock station, and register for dock event notifications. 734 */ 735static int dock_add(acpi_handle handle) 736{ 737 int ret; 738 acpi_status status; 739 struct dock_dependent_device *dd; 740 741 /* allocate & initialize the dock_station private data */ 742 dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); 743 if (!dock_station) 744 return -ENOMEM; 745 dock_station->handle = handle; 746 dock_station->last_dock_time = jiffies - HZ; 747 INIT_LIST_HEAD(&dock_station->dependent_devices); 748 INIT_LIST_HEAD(&dock_station->hotplug_devices); 749 spin_lock_init(&dock_station->dd_lock); 750 mutex_init(&dock_station->hp_lock); 751 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); 752 753 /* initialize platform device stuff */ 754 dock_device = 755 platform_device_register_simple(dock_device_name, 0, NULL, 0); 756 if (IS_ERR(dock_device)) { 757 kfree(dock_station); 758 dock_station = NULL; 759 return PTR_ERR(dock_device); 760 } 761 762 /* we want the dock device to send uevents */ 763 dock_device->dev.uevent_suppress = 0; 764 765 ret = device_create_file(&dock_device->dev, &dev_attr_docked); 766 if (ret) { 767 printk("Error %d adding sysfs file\n", ret); 768 platform_device_unregister(dock_device); 769 kfree(dock_station); 770 dock_station = NULL; 771 return ret; 772 } 773 ret = device_create_file(&dock_device->dev, &dev_attr_undock); 774 if (ret) { 775 printk("Error %d adding sysfs file\n", ret); 776 device_remove_file(&dock_device->dev, &dev_attr_docked); 777 platform_device_unregister(dock_device); 778 kfree(dock_station); 779 dock_station = NULL; 780 return ret; 781 } 782 ret = device_create_file(&dock_device->dev, &dev_attr_uid); 783 if (ret) { 784 printk("Error %d adding sysfs file\n", ret); 785 device_remove_file(&dock_device->dev, &dev_attr_docked); 786 device_remove_file(&dock_device->dev, &dev_attr_undock); 787 platform_device_unregister(dock_device); 788 kfree(dock_station); 789 dock_station = NULL; 790 return ret; 791 } 792 ret = device_create_file(&dock_device->dev, &dev_attr_flags); 793 if (ret) { 794 printk("Error %d adding sysfs file\n", ret); 795 device_remove_file(&dock_device->dev, &dev_attr_docked); 796 device_remove_file(&dock_device->dev, &dev_attr_undock); 797 device_remove_file(&dock_device->dev, &dev_attr_uid); 798 platform_device_unregister(dock_device); 799 kfree(dock_station); 800 dock_station = NULL; 801 return ret; 802 } 803 804 /* Find dependent devices */ 805 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 806 ACPI_UINT32_MAX, find_dock_devices, dock_station, 807 NULL); 808 809 /* add the dock station as a device dependent on itself */ 810 dd = alloc_dock_dependent_device(handle); 811 if (!dd) { 812 kfree(dock_station); 813 dock_station = NULL; 814 ret = -ENOMEM; 815 goto dock_add_err_unregister; 816 } 817 add_dock_dependent_device(dock_station, dd); 818 819 /* register for dock events */ 820 status = acpi_install_notify_handler(dock_station->handle, 821 ACPI_SYSTEM_NOTIFY, 822 dock_notify, dock_station); 823 824 if (ACPI_FAILURE(status)) { 825 printk(KERN_ERR PREFIX "Error installing notify handler\n"); 826 ret = -ENODEV; 827 goto dock_add_err; 828 } 829 830 printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION); 831 832 return 0; 833 834dock_add_err: 835 kfree(dd); 836dock_add_err_unregister: 837 device_remove_file(&dock_device->dev, &dev_attr_docked); 838 device_remove_file(&dock_device->dev, &dev_attr_undock); 839 device_remove_file(&dock_device->dev, &dev_attr_uid); 840 device_remove_file(&dock_device->dev, &dev_attr_flags); 841 platform_device_unregister(dock_device); 842 kfree(dock_station); 843 dock_station = NULL; 844 return ret; 845} 846 847/** 848 * dock_remove - free up resources related to the dock station 849 */ 850static int dock_remove(void) 851{ 852 struct dock_dependent_device *dd, *tmp; 853 acpi_status status; 854 855 if (!dock_station) 856 return 0; 857 858 /* remove dependent devices */ 859 list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, 860 list) 861 kfree(dd); 862 863 /* remove dock notify handler */ 864 status = acpi_remove_notify_handler(dock_station->handle, 865 ACPI_SYSTEM_NOTIFY, 866 dock_notify); 867 if (ACPI_FAILURE(status)) 868 printk(KERN_ERR "Error removing notify handler\n"); 869 870 /* cleanup sysfs */ 871 device_remove_file(&dock_device->dev, &dev_attr_docked); 872 device_remove_file(&dock_device->dev, &dev_attr_undock); 873 device_remove_file(&dock_device->dev, &dev_attr_uid); 874 device_remove_file(&dock_device->dev, &dev_attr_flags); 875 platform_device_unregister(dock_device); 876 877 /* free dock station memory */ 878 kfree(dock_station); 879 dock_station = NULL; 880 return 0; 881} 882 883/** 884 * find_dock - look for a dock station 885 * @handle: acpi handle of a device 886 * @lvl: unused 887 * @context: counter of dock stations found 888 * @rv: unused 889 * 890 * This is called by acpi_walk_namespace to look for dock stations. 891 */ 892static acpi_status 893find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) 894{ 895 int *count = context; 896 acpi_status status = AE_OK; 897 898 if (is_dock(handle)) { 899 if (dock_add(handle) >= 0) { 900 (*count)++; 901 status = AE_CTRL_TERMINATE; 902 } 903 } 904 return status; 905} 906 907static int __init dock_init(void) 908{ 909 int num = 0; 910 911 dock_station = NULL; 912 913 /* look for a dock station */ 914 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 915 ACPI_UINT32_MAX, find_dock, &num, NULL); 916 917 if (!num) 918 printk(KERN_INFO "No dock devices found.\n"); 919 920 return 0; 921} 922 923static void __exit dock_exit(void) 924{ 925 dock_remove(); 926} 927 928postcore_initcall(dock_init); 929module_exit(dock_exit);