core.c 3.3 KB

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