dock.c 24 KB

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