core.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * soundbus
  3. *
  4. * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  5. *
  6. * GPL v2, can be found in COPYING.
  7. */
  8. #include <linux/module.h>
  9. #include "soundbus.h"
  10. MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
  11. MODULE_LICENSE("GPL");
  12. MODULE_DESCRIPTION("Apple Soundbus");
  13. struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev)
  14. {
  15. struct device *tmp;
  16. if (!dev)
  17. return NULL;
  18. tmp = get_device(&dev->ofdev.dev);
  19. if (tmp)
  20. return to_soundbus_device(tmp);
  21. else
  22. return NULL;
  23. }
  24. EXPORT_SYMBOL_GPL(soundbus_dev_get);
  25. void soundbus_dev_put(struct soundbus_dev *dev)
  26. {
  27. if (dev)
  28. put_device(&dev->ofdev.dev);
  29. }
  30. EXPORT_SYMBOL_GPL(soundbus_dev_put);
  31. static int soundbus_probe(struct device *dev)
  32. {
  33. int error = -ENODEV;
  34. struct soundbus_driver *drv;
  35. struct soundbus_dev *soundbus_dev;
  36. drv = to_soundbus_driver(dev->driver);
  37. soundbus_dev = to_soundbus_device(dev);
  38. if (!drv->probe)
  39. return error;
  40. soundbus_dev_get(soundbus_dev);
  41. error = drv->probe(soundbus_dev);
  42. if (error)
  43. soundbus_dev_put(soundbus_dev);
  44. return error;
  45. }
  46. static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
  47. char *buffer, int buffer_size)
  48. {
  49. struct soundbus_dev * soundbus_dev;
  50. struct of_device * of;
  51. char *scratch, *compat, *compat2;
  52. int i = 0;
  53. int length, cplen, cplen2, seen = 0;
  54. if (!dev)
  55. return -ENODEV;
  56. soundbus_dev = to_soundbus_device(dev);
  57. if (!soundbus_dev)
  58. return -ENODEV;
  59. of = &soundbus_dev->ofdev;
  60. /* stuff we want to pass to /sbin/hotplug */
  61. envp[i++] = scratch = buffer;
  62. length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
  63. ++length;
  64. buffer_size -= length;
  65. if ((buffer_size <= 0) || (i >= num_envp))
  66. return -ENOMEM;
  67. scratch += length;
  68. envp[i++] = scratch;
  69. length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
  70. ++length;
  71. buffer_size -= length;
  72. if ((buffer_size <= 0) || (i >= num_envp))
  73. return -ENOMEM;
  74. scratch += length;
  75. /* Since the compatible field can contain pretty much anything
  76. * it's not really legal to split it out with commas. We split it
  77. * up using a number of environment variables instead. */
  78. compat = (char *) get_property(of->node, "compatible", &cplen);
  79. compat2 = compat;
  80. cplen2= cplen;
  81. while (compat && cplen > 0) {
  82. envp[i++] = scratch;
  83. length = scnprintf (scratch, buffer_size,
  84. "OF_COMPATIBLE_%d=%s", seen, compat);
  85. ++length;
  86. buffer_size -= length;
  87. if ((buffer_size <= 0) || (i >= num_envp))
  88. return -ENOMEM;
  89. scratch += length;
  90. length = strlen (compat) + 1;
  91. compat += length;
  92. cplen -= length;
  93. seen++;
  94. }
  95. envp[i++] = scratch;
  96. length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
  97. ++length;
  98. buffer_size -= length;
  99. if ((buffer_size <= 0) || (i >= num_envp))
  100. return -ENOMEM;
  101. scratch += length;
  102. envp[i++] = scratch;
  103. length = scnprintf (scratch, buffer_size, "MODALIAS=%s",
  104. soundbus_dev->modalias);
  105. buffer_size -= length;
  106. if ((buffer_size <= 0) || (i >= num_envp))
  107. return -ENOMEM;
  108. envp[i] = NULL;
  109. return 0;
  110. }
  111. static int soundbus_device_remove(struct device *dev)
  112. {
  113. struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
  114. struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
  115. if (dev->driver && drv->remove)
  116. drv->remove(soundbus_dev);
  117. soundbus_dev_put(soundbus_dev);
  118. return 0;
  119. }
  120. static void soundbus_device_shutdown(struct device *dev)
  121. {
  122. struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
  123. struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
  124. if (dev->driver && drv->shutdown)
  125. drv->shutdown(soundbus_dev);
  126. }
  127. #ifdef CONFIG_PM
  128. static int soundbus_device_suspend(struct device *dev, pm_message_t state)
  129. {
  130. struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
  131. struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
  132. if (dev->driver && drv->suspend)
  133. return drv->suspend(soundbus_dev, state);
  134. return 0;
  135. }
  136. static int soundbus_device_resume(struct device * dev)
  137. {
  138. struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
  139. struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
  140. if (dev->driver && drv->resume)
  141. return drv->resume(soundbus_dev);
  142. return 0;
  143. }
  144. #endif /* CONFIG_PM */
  145. extern struct device_attribute soundbus_dev_attrs[];
  146. static struct bus_type soundbus_bus_type = {
  147. .name = "aoa-soundbus",
  148. .probe = soundbus_probe,
  149. .uevent = soundbus_uevent,
  150. .remove = soundbus_device_remove,
  151. .shutdown = soundbus_device_shutdown,
  152. #ifdef CONFIG_PM
  153. .suspend = soundbus_device_suspend,
  154. .resume = soundbus_device_resume,
  155. #endif
  156. .dev_attrs = soundbus_dev_attrs,
  157. };
  158. int soundbus_add_one(struct soundbus_dev *dev)
  159. {
  160. static int devcount;
  161. /* sanity checks */
  162. if (!dev->attach_codec ||
  163. !dev->ofdev.node ||
  164. dev->pcmname ||
  165. dev->pcmid != -1) {
  166. printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
  167. return -EINVAL;
  168. }
  169. snprintf(dev->ofdev.dev.bus_id, BUS_ID_SIZE, "soundbus:%x", ++devcount);
  170. dev->ofdev.dev.bus = &soundbus_bus_type;
  171. return of_device_register(&dev->ofdev);
  172. }
  173. EXPORT_SYMBOL_GPL(soundbus_add_one);
  174. void soundbus_remove_one(struct soundbus_dev *dev)
  175. {
  176. of_device_unregister(&dev->ofdev);
  177. }
  178. EXPORT_SYMBOL_GPL(soundbus_remove_one);
  179. int soundbus_register_driver(struct soundbus_driver *drv)
  180. {
  181. /* initialize common driver fields */
  182. drv->driver.name = drv->name;
  183. drv->driver.bus = &soundbus_bus_type;
  184. /* register with core */
  185. return driver_register(&drv->driver);
  186. }
  187. EXPORT_SYMBOL_GPL(soundbus_register_driver);
  188. void soundbus_unregister_driver(struct soundbus_driver *drv)
  189. {
  190. driver_unregister(&drv->driver);
  191. }
  192. EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
  193. static int __init soundbus_init(void)
  194. {
  195. return bus_register(&soundbus_bus_type);
  196. }
  197. static void __exit soundbus_exit(void)
  198. {
  199. bus_unregister(&soundbus_bus_type);
  200. }
  201. subsys_initcall(soundbus_init);
  202. module_exit(soundbus_exit);