sysfs.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * linux/drivers/mmc/core/sysfs.c
  3. *
  4. * Copyright (C) 2003 Russell King, All Rights Reserved.
  5. * Copyright 2007 Pierre Ossman
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * MMC sysfs/driver model support.
  12. */
  13. #include <linux/module.h>
  14. #include <linux/init.h>
  15. #include <linux/device.h>
  16. #include <linux/idr.h>
  17. #include <linux/workqueue.h>
  18. #include <linux/mmc/card.h>
  19. #include <linux/mmc/host.h>
  20. #include "bus.h"
  21. #include "sysfs.h"
  22. #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
  23. #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
  24. int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs)
  25. {
  26. int error = 0;
  27. int i;
  28. for (i = 0; attr_name(attrs[i]); i++) {
  29. error = device_create_file(&card->dev, &attrs[i]);
  30. if (error) {
  31. while (--i >= 0)
  32. device_remove_file(&card->dev, &attrs[i]);
  33. break;
  34. }
  35. }
  36. return error;
  37. }
  38. void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs)
  39. {
  40. int i;
  41. for (i = 0; attr_name(attrs[i]); i++)
  42. device_remove_file(&card->dev, &attrs[i]);
  43. }
  44. static void mmc_host_classdev_release(struct device *dev)
  45. {
  46. struct mmc_host *host = cls_dev_to_mmc_host(dev);
  47. kfree(host);
  48. }
  49. static struct class mmc_host_class = {
  50. .name = "mmc_host",
  51. .dev_release = mmc_host_classdev_release,
  52. };
  53. static DEFINE_IDR(mmc_host_idr);
  54. static DEFINE_SPINLOCK(mmc_host_lock);
  55. /*
  56. * Internal function. Allocate a new MMC host.
  57. */
  58. struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
  59. {
  60. struct mmc_host *host;
  61. host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
  62. if (host) {
  63. memset(host, 0, sizeof(struct mmc_host) + extra);
  64. host->parent = dev;
  65. host->class_dev.parent = dev;
  66. host->class_dev.class = &mmc_host_class;
  67. device_initialize(&host->class_dev);
  68. }
  69. return host;
  70. }
  71. /*
  72. * Internal function. Register a new MMC host with the MMC class.
  73. */
  74. int mmc_add_host_sysfs(struct mmc_host *host)
  75. {
  76. int err;
  77. if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
  78. return -ENOMEM;
  79. spin_lock(&mmc_host_lock);
  80. err = idr_get_new(&mmc_host_idr, host, &host->index);
  81. spin_unlock(&mmc_host_lock);
  82. if (err)
  83. return err;
  84. snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
  85. "mmc%d", host->index);
  86. return device_add(&host->class_dev);
  87. }
  88. /*
  89. * Internal function. Unregister a MMC host with the MMC class.
  90. */
  91. void mmc_remove_host_sysfs(struct mmc_host *host)
  92. {
  93. device_del(&host->class_dev);
  94. spin_lock(&mmc_host_lock);
  95. idr_remove(&mmc_host_idr, host->index);
  96. spin_unlock(&mmc_host_lock);
  97. }
  98. /*
  99. * Internal function. Free a MMC host.
  100. */
  101. void mmc_free_host_sysfs(struct mmc_host *host)
  102. {
  103. put_device(&host->class_dev);
  104. }
  105. static struct workqueue_struct *workqueue;
  106. /*
  107. * Internal function. Schedule delayed work in the MMC work queue.
  108. */
  109. int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay)
  110. {
  111. return queue_delayed_work(workqueue, work, delay);
  112. }
  113. /*
  114. * Internal function. Flush all scheduled work from the MMC work queue.
  115. */
  116. void mmc_flush_scheduled_work(void)
  117. {
  118. flush_workqueue(workqueue);
  119. }
  120. static int __init mmc_init(void)
  121. {
  122. int ret;
  123. workqueue = create_singlethread_workqueue("kmmcd");
  124. if (!workqueue)
  125. return -ENOMEM;
  126. ret = mmc_register_bus();
  127. if (ret == 0) {
  128. ret = class_register(&mmc_host_class);
  129. if (ret)
  130. mmc_unregister_bus();
  131. }
  132. return ret;
  133. }
  134. static void __exit mmc_exit(void)
  135. {
  136. class_unregister(&mmc_host_class);
  137. mmc_unregister_bus();
  138. destroy_workqueue(workqueue);
  139. }
  140. module_init(mmc_init);
  141. module_exit(mmc_exit);