···133133 This driver adds support for ACPI fan devices, allowing user-mode 134134 applications to perform basic fan control (on, off, status).135135136136+config ACPI_DOCK137137+ tristate "Dock"138138+ depends on !ACPI_IBM_DOCK139139+ default y140140+ help141141+ This driver adds support for ACPI controlled docking stations142142+136143config ACPI_PROCESSOR137144 tristate "Processor"138145 default y
···11+/*22+ * dock.c - ACPI dock station driver33+ *44+ * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>55+ *66+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License as published by1010+ * the Free Software Foundation; either version 2 of the License, or (at1111+ * your option) any later version.1212+ *1313+ * This program is distributed in the hope that it will be useful, but1414+ * WITHOUT ANY WARRANTY; without even the implied warranty of1515+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1616+ * General Public License for more details.1717+ *1818+ * You should have received a copy of the GNU General Public License along1919+ * with this program; if not, write to the Free Software Foundation, Inc.,2020+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.2121+ *2222+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2323+ */2424+2525+#include <linux/kernel.h>2626+#include <linux/module.h>2727+#include <linux/init.h>2828+#include <linux/types.h>2929+#include <linux/notifier.h>3030+#include <acpi/acpi_bus.h>3131+#include <acpi/acpi_drivers.h>3232+3333+#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver"3434+3535+ACPI_MODULE_NAME("dock")3636+MODULE_AUTHOR("Kristen Carlson Accardi");3737+MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);3838+MODULE_LICENSE("GPL");3939+4040+static struct atomic_notifier_head dock_notifier_list;4141+4242+struct dock_station {4343+ acpi_handle handle;4444+ unsigned long last_dock_time;4545+ u32 flags;4646+ spinlock_t dd_lock;4747+ spinlock_t hp_lock;4848+ struct list_head dependent_devices;4949+ struct list_head hotplug_devices;5050+};5151+5252+struct dock_dependent_device {5353+ struct list_head list;5454+ struct list_head hotplug_list;5555+ acpi_handle handle;5656+ acpi_notify_handler handler;5757+ void *context;5858+};5959+6060+#define DOCK_DOCKING 0x000000016161+#define DOCK_EVENT KOBJ_DOCK6262+#define UNDOCK_EVENT KOBJ_UNDOCK6363+6464+static struct dock_station *dock_station;6565+6666+/*****************************************************************************6767+ * Dock Dependent device functions *6868+ *****************************************************************************/6969+/**7070+ * alloc_dock_dependent_device - allocate and init a dependent device7171+ * @handle: the acpi_handle of the dependent device7272+ *7373+ * Allocate memory for a dependent device structure for a device referenced7474+ * by the acpi handle7575+ */7676+static struct dock_dependent_device *7777+alloc_dock_dependent_device(acpi_handle handle)7878+{7979+ struct dock_dependent_device *dd;8080+8181+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);8282+ if (dd) {8383+ dd->handle = handle;8484+ INIT_LIST_HEAD(&dd->list);8585+ INIT_LIST_HEAD(&dd->hotplug_list);8686+ }8787+ return dd;8888+}8989+9090+/**9191+ * add_dock_dependent_device - associate a device with the dock station9292+ * @ds: The dock station9393+ * @dd: The dependent device9494+ *9595+ * Add the dependent device to the dock's dependent device list.9696+ */9797+static void9898+add_dock_dependent_device(struct dock_station *ds,9999+ struct dock_dependent_device *dd)100100+{101101+ spin_lock(&ds->dd_lock);102102+ list_add_tail(&dd->list, &ds->dependent_devices);103103+ spin_unlock(&ds->dd_lock);104104+}105105+106106+/**107107+ * dock_add_hotplug_device - associate a hotplug handler with the dock station108108+ * @ds: The dock station109109+ * @dd: The dependent device struct110110+ *111111+ * Add the dependent device to the dock's hotplug device list112112+ */113113+static void114114+dock_add_hotplug_device(struct dock_station *ds,115115+ struct dock_dependent_device *dd)116116+{117117+ spin_lock(&ds->hp_lock);118118+ list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);119119+ spin_unlock(&ds->hp_lock);120120+}121121+122122+/**123123+ * dock_del_hotplug_device - remove a hotplug handler from the dock station124124+ * @ds: The dock station125125+ * @dd: the dependent device struct126126+ *127127+ * Delete the dependent device from the dock's hotplug device list128128+ */129129+static void130130+dock_del_hotplug_device(struct dock_station *ds,131131+ struct dock_dependent_device *dd)132132+{133133+ spin_lock(&ds->hp_lock);134134+ list_del(&dd->hotplug_list);135135+ spin_unlock(&ds->hp_lock);136136+}137137+138138+/**139139+ * find_dock_dependent_device - get a device dependent on this dock140140+ * @ds: the dock station141141+ * @handle: the acpi_handle of the device we want142142+ *143143+ * iterate over the dependent device list for this dock. If the144144+ * dependent device matches the handle, return.145145+ */146146+static struct dock_dependent_device *147147+find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)148148+{149149+ struct dock_dependent_device *dd;150150+151151+ spin_lock(&ds->dd_lock);152152+ list_for_each_entry(dd, &ds->dependent_devices, list) {153153+ if (handle == dd->handle) {154154+ spin_unlock(&ds->dd_lock);155155+ return dd;156156+ }157157+ }158158+ spin_unlock(&ds->dd_lock);159159+ return NULL;160160+}161161+162162+/*****************************************************************************163163+ * Dock functions *164164+ *****************************************************************************/165165+/**166166+ * is_dock - see if a device is a dock station167167+ * @handle: acpi handle of the device168168+ *169169+ * If an acpi object has a _DCK method, then it is by definition a dock170170+ * station, so return true.171171+ */172172+static int is_dock(acpi_handle handle)173173+{174174+ acpi_status status;175175+ acpi_handle tmp;176176+177177+ status = acpi_get_handle(handle, "_DCK", &tmp);178178+ if (ACPI_FAILURE(status))179179+ return 0;180180+ return 1;181181+}182182+183183+/**184184+ * is_dock_device - see if a device is on a dock station185185+ * @handle: acpi handle of the device186186+ *187187+ * If this device is either the dock station itself,188188+ * or is a device dependent on the dock station, then it189189+ * is a dock device190190+ */191191+int is_dock_device(acpi_handle handle)192192+{193193+ if (!dock_station)194194+ return 0;195195+196196+ if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))197197+ return 1;198198+199199+ return 0;200200+}201201+202202+EXPORT_SYMBOL_GPL(is_dock_device);203203+204204+/**205205+ * dock_present - see if the dock station is present.206206+ * @ds: the dock station207207+ *208208+ * execute the _STA method. note that present does not209209+ * imply that we are docked.210210+ */211211+static int dock_present(struct dock_station *ds)212212+{213213+ unsigned long sta;214214+ acpi_status status;215215+216216+ if (ds) {217217+ status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);218218+ if (ACPI_SUCCESS(status) && sta)219219+ return 1;220220+ }221221+ return 0;222222+}223223+224224+225225+226226+/**227227+ * dock_create_acpi_device - add new devices to acpi228228+ * @handle - handle of the device to add229229+ *230230+ * This function will create a new acpi_device for the given231231+ * handle if one does not exist already. This should cause232232+ * acpi to scan for drivers for the given devices, and call233233+ * matching driver's add routine.234234+ *235235+ * Returns a pointer to the acpi_device corresponding to the handle.236236+ */237237+static struct acpi_device * dock_create_acpi_device(acpi_handle handle)238238+{239239+ struct acpi_device *device = NULL;240240+ struct acpi_device *parent_device;241241+ acpi_handle parent;242242+ int ret;243243+244244+ if (acpi_bus_get_device(handle, &device)) {245245+ /*246246+ * no device created for this object,247247+ * so we should create one.248248+ */249249+ acpi_get_parent(handle, &parent);250250+ if (acpi_bus_get_device(parent, &parent_device))251251+ parent_device = NULL;252252+253253+ ret = acpi_bus_add(&device, parent_device, handle,254254+ ACPI_BUS_TYPE_DEVICE);255255+ if (ret) {256256+ pr_debug("error adding bus, %x\n",257257+ -ret);258258+ return NULL;259259+ }260260+ }261261+ return device;262262+}263263+264264+/**265265+ * dock_remove_acpi_device - remove the acpi_device struct from acpi266266+ * @handle - the handle of the device to remove267267+ *268268+ * Tell acpi to remove the acpi_device. This should cause any loaded269269+ * driver to have it's remove routine called.270270+ */271271+static void dock_remove_acpi_device(acpi_handle handle)272272+{273273+ struct acpi_device *device;274274+ int ret;275275+276276+ if (!acpi_bus_get_device(handle, &device)) {277277+ ret = acpi_bus_trim(device, 1);278278+ if (ret)279279+ pr_debug("error removing bus, %x\n", -ret);280280+ }281281+}282282+283283+284284+/**285285+ * hotplug_dock_devices - insert or remove devices on the dock station286286+ * @ds: the dock station287287+ * @event: either bus check or eject request288288+ *289289+ * Some devices on the dock station need to have drivers called290290+ * to perform hotplug operations after a dock event has occurred.291291+ * Traverse the list of dock devices that have registered a292292+ * hotplug handler, and call the handler.293293+ */294294+static void hotplug_dock_devices(struct dock_station *ds, u32 event)295295+{296296+ struct dock_dependent_device *dd;297297+298298+ spin_lock(&ds->hp_lock);299299+300300+ /*301301+ * First call driver specific hotplug functions302302+ */303303+ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {304304+ if (dd->handler)305305+ dd->handler(dd->handle, event, dd->context);306306+ }307307+308308+ /*309309+ * Now make sure that an acpi_device is created for each310310+ * dependent device, or removed if this is an eject request.311311+ * This will cause acpi_drivers to be stopped/started if they312312+ * exist313313+ */314314+ list_for_each_entry(dd, &ds->dependent_devices, list) {315315+ if (event == ACPI_NOTIFY_EJECT_REQUEST)316316+ dock_remove_acpi_device(dd->handle);317317+ else318318+ dock_create_acpi_device(dd->handle);319319+ }320320+ spin_unlock(&ds->hp_lock);321321+}322322+323323+static void dock_event(struct dock_station *ds, u32 event, int num)324324+{325325+ struct acpi_device *device;326326+327327+ device = dock_create_acpi_device(ds->handle);328328+ if (device)329329+ kobject_uevent(&device->kobj, num);330330+}331331+332332+/**333333+ * eject_dock - respond to a dock eject request334334+ * @ds: the dock station335335+ *336336+ * This is called after _DCK is called, to execute the dock station's337337+ * _EJ0 method.338338+ */339339+static void eject_dock(struct dock_station *ds)340340+{341341+ struct acpi_object_list arg_list;342342+ union acpi_object arg;343343+ acpi_status status;344344+ acpi_handle tmp;345345+346346+ /* all dock devices should have _EJ0, but check anyway */347347+ status = acpi_get_handle(ds->handle, "_EJ0", &tmp);348348+ if (ACPI_FAILURE(status)) {349349+ pr_debug("No _EJ0 support for dock device\n");350350+ return;351351+ }352352+353353+ arg_list.count = 1;354354+ arg_list.pointer = &arg;355355+ arg.type = ACPI_TYPE_INTEGER;356356+ arg.integer.value = 1;357357+358358+ if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",359359+ &arg_list, NULL)))360360+ pr_debug("Failed to evaluate _EJ0!\n");361361+}362362+363363+/**364364+ * handle_dock - handle a dock event365365+ * @ds: the dock station366366+ * @dock: to dock, or undock - that is the question367367+ *368368+ * Execute the _DCK method in response to an acpi event369369+ */370370+static void handle_dock(struct dock_station *ds, int dock)371371+{372372+ acpi_status status;373373+ struct acpi_object_list arg_list;374374+ union acpi_object arg;375375+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };376376+ struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };377377+ union acpi_object *obj;378378+379379+ acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);380380+ obj = name_buffer.pointer;381381+382382+ printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");383383+384384+ /* _DCK method has one argument */385385+ arg_list.count = 1;386386+ arg_list.pointer = &arg;387387+ arg.type = ACPI_TYPE_INTEGER;388388+ arg.integer.value = dock;389389+ status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);390390+ if (ACPI_FAILURE(status))391391+ pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);392392+ kfree(buffer.pointer);393393+ kfree(name_buffer.pointer);394394+}395395+396396+static inline void dock(struct dock_station *ds)397397+{398398+ handle_dock(ds, 1);399399+}400400+401401+static inline void undock(struct dock_station *ds)402402+{403403+ handle_dock(ds, 0);404404+}405405+406406+static inline void begin_dock(struct dock_station *ds)407407+{408408+ ds->flags |= DOCK_DOCKING;409409+}410410+411411+static inline void complete_dock(struct dock_station *ds)412412+{413413+ ds->flags &= ~(DOCK_DOCKING);414414+ ds->last_dock_time = jiffies;415415+}416416+417417+/**418418+ * dock_in_progress - see if we are in the middle of handling a dock event419419+ * @ds: the dock station420420+ *421421+ * Sometimes while docking, false dock events can be sent to the driver422422+ * because good connections aren't made or some other reason. Ignore these423423+ * if we are in the middle of doing something.424424+ */425425+static int dock_in_progress(struct dock_station *ds)426426+{427427+ if ((ds->flags & DOCK_DOCKING) ||428428+ time_before(jiffies, (ds->last_dock_time + HZ)))429429+ return 1;430430+ return 0;431431+}432432+433433+/**434434+ * register_dock_notifier - add yourself to the dock notifier list435435+ * @nb: the callers notifier block436436+ *437437+ * If a driver wishes to be notified about dock events, they can438438+ * use this function to put a notifier block on the dock notifier list.439439+ * this notifier call chain will be called after a dock event, but440440+ * before hotplugging any new devices.441441+ */442442+int register_dock_notifier(struct notifier_block *nb)443443+{444444+ return atomic_notifier_chain_register(&dock_notifier_list, nb);445445+}446446+447447+EXPORT_SYMBOL_GPL(register_dock_notifier);448448+449449+/**450450+ * unregister_dock_notifier - remove yourself from the dock notifier list451451+ * @nb: the callers notifier block452452+ */453453+void unregister_dock_notifier(struct notifier_block *nb)454454+{455455+ atomic_notifier_chain_unregister(&dock_notifier_list, nb);456456+}457457+458458+EXPORT_SYMBOL_GPL(unregister_dock_notifier);459459+460460+/**461461+ * register_hotplug_dock_device - register a hotplug function462462+ * @handle: the handle of the device463463+ * @handler: the acpi_notifier_handler to call after docking464464+ * @context: device specific data465465+ *466466+ * If a driver would like to perform a hotplug operation after a dock467467+ * event, they can register an acpi_notifiy_handler to be called by468468+ * the dock driver after _DCK is executed.469469+ */470470+int471471+register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,472472+ void *context)473473+{474474+ struct dock_dependent_device *dd;475475+476476+ if (!dock_station)477477+ return -ENODEV;478478+479479+ /*480480+ * make sure this handle is for a device dependent on the dock,481481+ * this would include the dock station itself482482+ */483483+ dd = find_dock_dependent_device(dock_station, handle);484484+ if (dd) {485485+ dd->handler = handler;486486+ dd->context = context;487487+ dock_add_hotplug_device(dock_station, dd);488488+ return 0;489489+ }490490+491491+ return -EINVAL;492492+}493493+494494+EXPORT_SYMBOL_GPL(register_hotplug_dock_device);495495+496496+/**497497+ * unregister_hotplug_dock_device - remove yourself from the hotplug list498498+ * @handle: the acpi handle of the device499499+ */500500+void unregister_hotplug_dock_device(acpi_handle handle)501501+{502502+ struct dock_dependent_device *dd;503503+504504+ if (!dock_station)505505+ return;506506+507507+ dd = find_dock_dependent_device(dock_station, handle);508508+ if (dd)509509+ dock_del_hotplug_device(dock_station, dd);510510+}511511+512512+EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);513513+514514+/**515515+ * dock_notify - act upon an acpi dock notification516516+ * @handle: the dock station handle517517+ * @event: the acpi event518518+ * @data: our driver data struct519519+ *520520+ * If we are notified to dock, then check to see if the dock is521521+ * present and then dock. Notify all drivers of the dock event,522522+ * and then hotplug and devices that may need hotplugging. For undock523523+ * check to make sure the dock device is still present, then undock524524+ * and hotremove all the devices that may need removing.525525+ */526526+static void dock_notify(acpi_handle handle, u32 event, void *data)527527+{528528+ struct dock_station *ds = (struct dock_station *)data;529529+530530+ switch (event) {531531+ case ACPI_NOTIFY_BUS_CHECK:532532+ if (!dock_in_progress(ds) && dock_present(ds)) {533533+ begin_dock(ds);534534+ dock(ds);535535+ if (!dock_present(ds)) {536536+ printk(KERN_ERR PREFIX "Unable to dock!\n");537537+ break;538538+ }539539+ atomic_notifier_call_chain(&dock_notifier_list,540540+ event, NULL);541541+ hotplug_dock_devices(ds, event);542542+ complete_dock(ds);543543+ dock_event(ds, event, DOCK_EVENT);544544+ }545545+ break;546546+ case ACPI_NOTIFY_DEVICE_CHECK:547547+ /*548548+ * According to acpi spec 3.0a, if a DEVICE_CHECK notification549549+ * is sent and _DCK is present, it is assumed to mean an550550+ * undock request. This notify routine will only be called551551+ * for objects defining _DCK, so we will fall through to eject552552+ * request here. However, we will pass an eject request through553553+ * to the driver who wish to hotplug.554554+ */555555+ case ACPI_NOTIFY_EJECT_REQUEST:556556+ if (!dock_in_progress(ds) && dock_present(ds)) {557557+ /*558558+ * here we need to generate the undock559559+ * event prior to actually doing the undock560560+ * so that the device struct still exists.561561+ */562562+ dock_event(ds, event, UNDOCK_EVENT);563563+ hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);564564+ undock(ds);565565+ eject_dock(ds);566566+ if (dock_present(ds))567567+ printk(KERN_ERR PREFIX "Unable to undock!\n");568568+ }569569+ break;570570+ default:571571+ printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);572572+ }573573+}574574+575575+/**576576+ * find_dock_devices - find devices on the dock station577577+ * @handle: the handle of the device we are examining578578+ * @lvl: unused579579+ * @context: the dock station private data580580+ * @rv: unused581581+ *582582+ * This function is called by acpi_walk_namespace. It will583583+ * check to see if an object has an _EJD method. If it does, then it584584+ * will see if it is dependent on the dock station.585585+ */586586+static acpi_status587587+find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)588588+{589589+ acpi_status status;590590+ acpi_handle tmp;591591+ struct dock_station *ds = (struct dock_station *)context;592592+ struct dock_dependent_device *dd;593593+594594+ status = acpi_bus_get_ejd(handle, &tmp);595595+ if (ACPI_FAILURE(status))596596+ return AE_OK;597597+598598+ if (tmp == ds->handle) {599599+ dd = alloc_dock_dependent_device(handle);600600+ if (dd)601601+ add_dock_dependent_device(ds, dd);602602+ }603603+604604+ return AE_OK;605605+}606606+607607+/**608608+ * dock_add - add a new dock station609609+ * @handle: the dock station handle610610+ *611611+ * allocated and initialize a new dock station device. Find all devices612612+ * that are on the dock station, and register for dock event notifications.613613+ */614614+static int dock_add(acpi_handle handle)615615+{616616+ int ret;617617+ acpi_status status;618618+ struct dock_dependent_device *dd;619619+620620+ /* allocate & initialize the dock_station private data */621621+ dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);622622+ if (!dock_station)623623+ return -ENOMEM;624624+ dock_station->handle = handle;625625+ dock_station->last_dock_time = jiffies - HZ;626626+ INIT_LIST_HEAD(&dock_station->dependent_devices);627627+ INIT_LIST_HEAD(&dock_station->hotplug_devices);628628+ spin_lock_init(&dock_station->dd_lock);629629+ spin_lock_init(&dock_station->hp_lock);630630+631631+ /* Find dependent devices */632632+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,633633+ ACPI_UINT32_MAX, find_dock_devices, dock_station,634634+ NULL);635635+636636+ /* add the dock station as a device dependent on itself */637637+ dd = alloc_dock_dependent_device(handle);638638+ if (!dd) {639639+ kfree(dock_station);640640+ return -ENOMEM;641641+ }642642+ add_dock_dependent_device(dock_station, dd);643643+644644+ /* register for dock events */645645+ status = acpi_install_notify_handler(dock_station->handle,646646+ ACPI_SYSTEM_NOTIFY,647647+ dock_notify, dock_station);648648+649649+ if (ACPI_FAILURE(status)) {650650+ printk(KERN_ERR PREFIX "Error installing notify handler\n");651651+ ret = -ENODEV;652652+ goto dock_add_err;653653+ }654654+655655+ printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME);656656+657657+ return 0;658658+659659+dock_add_err:660660+ kfree(dock_station);661661+ kfree(dd);662662+ return ret;663663+}664664+665665+/**666666+ * dock_remove - free up resources related to the dock station667667+ */668668+static int dock_remove(void)669669+{670670+ struct dock_dependent_device *dd, *tmp;671671+ acpi_status status;672672+673673+ if (!dock_station)674674+ return 0;675675+676676+ /* remove dependent devices */677677+ list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,678678+ list)679679+ kfree(dd);680680+681681+ /* remove dock notify handler */682682+ status = acpi_remove_notify_handler(dock_station->handle,683683+ ACPI_SYSTEM_NOTIFY,684684+ dock_notify);685685+ if (ACPI_FAILURE(status))686686+ printk(KERN_ERR "Error removing notify handler\n");687687+688688+ /* free dock station memory */689689+ kfree(dock_station);690690+ return 0;691691+}692692+693693+/**694694+ * find_dock - look for a dock station695695+ * @handle: acpi handle of a device696696+ * @lvl: unused697697+ * @context: counter of dock stations found698698+ * @rv: unused699699+ *700700+ * This is called by acpi_walk_namespace to look for dock stations.701701+ */702702+static acpi_status703703+find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)704704+{705705+ int *count = (int *)context;706706+ acpi_status status = AE_OK;707707+708708+ if (is_dock(handle)) {709709+ if (dock_add(handle) >= 0) {710710+ (*count)++;711711+ status = AE_CTRL_TERMINATE;712712+ }713713+ }714714+ return status;715715+}716716+717717+static int __init dock_init(void)718718+{719719+ int num = 0;720720+721721+ dock_station = NULL;722722+723723+ /* look for a dock station */724724+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,725725+ ACPI_UINT32_MAX, find_dock, &num, NULL);726726+727727+ if (!num)728728+ return -ENODEV;729729+730730+ return 0;731731+}732732+733733+static void __exit dock_exit(void)734734+{735735+ dock_remove();736736+}737737+738738+postcore_initcall(dock_init);739739+module_exit(dock_exit);
+23
drivers/acpi/scan.c
···663663 Device Enumeration664664 -------------------------------------------------------------------------- */665665666666+acpi_status667667+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)668668+{669669+ acpi_status status;670670+ acpi_handle tmp;671671+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};672672+ union acpi_object *obj;673673+674674+ status = acpi_get_handle(handle, "_EJD", &tmp);675675+ if (ACPI_FAILURE(status))676676+ return status;677677+678678+ status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);679679+ if (ACPI_SUCCESS(status)) {680680+ obj = buffer.pointer;681681+ status = acpi_get_handle(NULL, obj->string.pointer, ejd);682682+ kfree(buffer.pointer);683683+ }684684+ return status;685685+}686686+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);687687+688688+666689static int acpi_bus_get_flags(struct acpi_device *device)667690{668691 acpi_status status = AE_OK;