core.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Apple Onboard Audio driver core
  3. *
  4. * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  5. *
  6. * GPL v2, can be found in COPYING.
  7. */
  8. #include <linux/init.h>
  9. #include <linux/module.h>
  10. #include <linux/list.h>
  11. #include "../aoa.h"
  12. #include "alsa.h"
  13. MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
  14. MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
  15. MODULE_LICENSE("GPL");
  16. /* We allow only one fabric. This simplifies things,
  17. * and more don't really make that much sense */
  18. static struct aoa_fabric *fabric;
  19. static LIST_HEAD(codec_list);
  20. static int attach_codec_to_fabric(struct aoa_codec *c)
  21. {
  22. int err;
  23. if (!try_module_get(c->owner))
  24. return -EBUSY;
  25. /* found_codec has to be assigned */
  26. err = -ENOENT;
  27. if (fabric->found_codec)
  28. err = fabric->found_codec(c);
  29. if (err) {
  30. module_put(c->owner);
  31. printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n",
  32. c->name);
  33. return err;
  34. }
  35. c->fabric = fabric;
  36. err = 0;
  37. if (c->init)
  38. err = c->init(c);
  39. if (err) {
  40. printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name);
  41. c->fabric = NULL;
  42. if (fabric->remove_codec)
  43. fabric->remove_codec(c);
  44. module_put(c->owner);
  45. return err;
  46. }
  47. if (fabric->attached_codec)
  48. fabric->attached_codec(c);
  49. return 0;
  50. }
  51. int aoa_codec_register(struct aoa_codec *codec)
  52. {
  53. int err = 0;
  54. /* if there's a fabric already, we can tell if we
  55. * will want to have this codec, so propagate error
  56. * through. Otherwise, this will happen later... */
  57. if (fabric)
  58. err = attach_codec_to_fabric(codec);
  59. if (!err)
  60. list_add(&codec->list, &codec_list);
  61. return err;
  62. }
  63. EXPORT_SYMBOL_GPL(aoa_codec_register);
  64. void aoa_codec_unregister(struct aoa_codec *codec)
  65. {
  66. list_del(&codec->list);
  67. if (codec->fabric && codec->exit)
  68. codec->exit(codec);
  69. if (fabric && fabric->remove_codec)
  70. fabric->remove_codec(codec);
  71. codec->fabric = NULL;
  72. module_put(codec->owner);
  73. }
  74. EXPORT_SYMBOL_GPL(aoa_codec_unregister);
  75. int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
  76. {
  77. struct aoa_codec *c;
  78. int err;
  79. /* allow querying for presence of fabric
  80. * (i.e. do this test first!) */
  81. if (new_fabric == fabric) {
  82. err = -EALREADY;
  83. goto attach;
  84. }
  85. if (fabric)
  86. return -EEXIST;
  87. if (!new_fabric)
  88. return -EINVAL;
  89. err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
  90. if (err)
  91. return err;
  92. fabric = new_fabric;
  93. attach:
  94. list_for_each_entry(c, &codec_list, list) {
  95. if (c->fabric != fabric)
  96. attach_codec_to_fabric(c);
  97. }
  98. return err;
  99. }
  100. EXPORT_SYMBOL_GPL(aoa_fabric_register);
  101. void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
  102. {
  103. struct aoa_codec *c;
  104. if (fabric != old_fabric)
  105. return;
  106. list_for_each_entry(c, &codec_list, list) {
  107. if (c->fabric)
  108. aoa_fabric_unlink_codec(c);
  109. }
  110. aoa_alsa_cleanup();
  111. fabric = NULL;
  112. }
  113. EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
  114. void aoa_fabric_unlink_codec(struct aoa_codec *codec)
  115. {
  116. if (!codec->fabric) {
  117. printk(KERN_ERR "snd-aoa: fabric unassigned "
  118. "in aoa_fabric_unlink_codec\n");
  119. dump_stack();
  120. return;
  121. }
  122. if (codec->exit)
  123. codec->exit(codec);
  124. if (codec->fabric->remove_codec)
  125. codec->fabric->remove_codec(codec);
  126. codec->fabric = NULL;
  127. module_put(codec->owner);
  128. }
  129. EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
  130. static int __init aoa_init(void)
  131. {
  132. return 0;
  133. }
  134. static void __exit aoa_exit(void)
  135. {
  136. aoa_alsa_cleanup();
  137. }
  138. module_init(aoa_init);
  139. module_exit(aoa_exit);