ivtv-alsa-main.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * ALSA interface to ivtv PCM capture streams
  3. *
  4. * Copyright (C) 2009,2012 Andy Walls <awalls@md.metrocast.net>
  5. * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
  6. *
  7. * Portions of this work were sponsored by ONELAN Limited for the cx18 driver
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. */
  19. #include "ivtv-driver.h"
  20. #include "ivtv-version.h"
  21. #include "ivtv-alsa.h"
  22. #include "ivtv-alsa-mixer.h"
  23. #include "ivtv-alsa-pcm.h"
  24. #include <sound/core.h>
  25. #include <sound/initval.h>
  26. int ivtv_alsa_debug;
  27. static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  28. #define IVTV_DEBUG_ALSA_INFO(__fmt, __arg...) \
  29. do { \
  30. if (ivtv_alsa_debug & 2) \
  31. printk(KERN_INFO pr_fmt("%s: alsa:" __fmt), \
  32. __func__, ##__arg); \
  33. } while (0)
  34. module_param_named(debug, ivtv_alsa_debug, int, 0644);
  35. MODULE_PARM_DESC(debug,
  36. "Debug level (bitmask). Default: 0\n"
  37. "\t\t\t 1/0x0001: warning\n"
  38. "\t\t\t 2/0x0002: info\n");
  39. module_param_array(index, int, NULL, 0444);
  40. MODULE_PARM_DESC(index,
  41. "Index value for IVTV ALSA capture interface(s).\n");
  42. MODULE_AUTHOR("Andy Walls");
  43. MODULE_DESCRIPTION("CX23415/CX23416 ALSA Interface");
  44. MODULE_SUPPORTED_DEVICE("CX23415/CX23416 MPEG2 encoder");
  45. MODULE_LICENSE("GPL");
  46. MODULE_VERSION(IVTV_VERSION);
  47. static inline
  48. struct snd_ivtv_card *to_snd_ivtv_card(struct v4l2_device *v4l2_dev)
  49. {
  50. return to_ivtv(v4l2_dev)->alsa;
  51. }
  52. static inline
  53. struct snd_ivtv_card *p_to_snd_ivtv_card(struct v4l2_device **v4l2_dev)
  54. {
  55. return container_of(v4l2_dev, struct snd_ivtv_card, v4l2_dev);
  56. }
  57. static void snd_ivtv_card_free(struct snd_ivtv_card *itvsc)
  58. {
  59. if (itvsc == NULL)
  60. return;
  61. if (itvsc->v4l2_dev != NULL)
  62. to_ivtv(itvsc->v4l2_dev)->alsa = NULL;
  63. /* FIXME - take any other stopping actions needed */
  64. kfree(itvsc);
  65. }
  66. static void snd_ivtv_card_private_free(struct snd_card *sc)
  67. {
  68. if (sc == NULL)
  69. return;
  70. snd_ivtv_card_free(sc->private_data);
  71. sc->private_data = NULL;
  72. sc->private_free = NULL;
  73. }
  74. static int snd_ivtv_card_create(struct v4l2_device *v4l2_dev,
  75. struct snd_card *sc,
  76. struct snd_ivtv_card **itvsc)
  77. {
  78. *itvsc = kzalloc(sizeof(struct snd_ivtv_card), GFP_KERNEL);
  79. if (*itvsc == NULL)
  80. return -ENOMEM;
  81. (*itvsc)->v4l2_dev = v4l2_dev;
  82. (*itvsc)->sc = sc;
  83. sc->private_data = *itvsc;
  84. sc->private_free = snd_ivtv_card_private_free;
  85. return 0;
  86. }
  87. static int snd_ivtv_card_set_names(struct snd_ivtv_card *itvsc)
  88. {
  89. struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
  90. struct snd_card *sc = itvsc->sc;
  91. /* sc->driver is used by alsa-lib's configurator: simple, unique */
  92. strlcpy(sc->driver, "CX2341[56]", sizeof(sc->driver));
  93. /* sc->shortname is a symlink in /proc/asound: IVTV-M -> cardN */
  94. snprintf(sc->shortname, sizeof(sc->shortname), "IVTV-%d",
  95. itv->instance);
  96. /* sc->longname is read from /proc/asound/cards */
  97. snprintf(sc->longname, sizeof(sc->longname),
  98. "CX2341[56] #%d %s TV/FM Radio/Line-In Capture",
  99. itv->instance, itv->card_name);
  100. return 0;
  101. }
  102. static int snd_ivtv_init(struct v4l2_device *v4l2_dev)
  103. {
  104. struct ivtv *itv = to_ivtv(v4l2_dev);
  105. struct snd_card *sc = NULL;
  106. struct snd_ivtv_card *itvsc;
  107. int ret, idx;
  108. /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */
  109. /* (1) Check and increment the device index */
  110. /* This is a no-op for us. We'll use the itv->instance */
  111. /* (2) Create a card instance */
  112. /* use first available id if not specified otherwise*/
  113. idx = index[itv->instance] == -1 ? SNDRV_DEFAULT_IDX1 : index[itv->instance];
  114. ret = snd_card_new(&itv->pdev->dev,
  115. idx,
  116. SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
  117. THIS_MODULE, 0, &sc);
  118. if (ret) {
  119. IVTV_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
  120. __func__, ret);
  121. goto err_exit;
  122. }
  123. /* (3) Create a main component */
  124. ret = snd_ivtv_card_create(v4l2_dev, sc, &itvsc);
  125. if (ret) {
  126. IVTV_ALSA_ERR("%s: snd_ivtv_card_create() failed with err %d\n",
  127. __func__, ret);
  128. goto err_exit_free;
  129. }
  130. /* (4) Set the driver ID and name strings */
  131. snd_ivtv_card_set_names(itvsc);
  132. /* (5) Create other components: mixer, PCM, & proc files */
  133. #if 0
  134. ret = snd_ivtv_mixer_create(itvsc);
  135. if (ret) {
  136. IVTV_ALSA_WARN("%s: snd_ivtv_mixer_create() failed with err %d: proceeding anyway\n",
  137. __func__, ret);
  138. }
  139. #endif
  140. ret = snd_ivtv_pcm_create(itvsc);
  141. if (ret) {
  142. IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n",
  143. __func__, ret);
  144. goto err_exit_free;
  145. }
  146. /* FIXME - proc files */
  147. /* (7) Set the driver data and return 0 */
  148. /* We do this out of normal order for PCI drivers to avoid races */
  149. itv->alsa = itvsc;
  150. /* (6) Register the card instance */
  151. ret = snd_card_register(sc);
  152. if (ret) {
  153. itv->alsa = NULL;
  154. IVTV_ALSA_ERR("%s: snd_card_register() failed with err %d\n",
  155. __func__, ret);
  156. goto err_exit_free;
  157. }
  158. IVTV_ALSA_INFO("%s: Instance %d registered as ALSA card %d\n",
  159. __func__, itv->instance, sc->number);
  160. return 0;
  161. err_exit_free:
  162. if (sc != NULL)
  163. snd_card_free(sc);
  164. kfree(itvsc);
  165. err_exit:
  166. return ret;
  167. }
  168. static int ivtv_alsa_load(struct ivtv *itv)
  169. {
  170. struct v4l2_device *v4l2_dev = &itv->v4l2_dev;
  171. struct ivtv_stream *s;
  172. if (v4l2_dev == NULL) {
  173. pr_err("ivtv-alsa: %s: struct v4l2_device * is NULL\n",
  174. __func__);
  175. return 0;
  176. }
  177. itv = to_ivtv(v4l2_dev);
  178. if (itv == NULL) {
  179. pr_err("ivtv-alsa itv is NULL\n");
  180. return 0;
  181. }
  182. s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
  183. if (s->vdev.v4l2_dev == NULL) {
  184. IVTV_DEBUG_ALSA_INFO("PCM stream for card is disabled - skipping\n");
  185. return 0;
  186. }
  187. if (itv->alsa != NULL) {
  188. IVTV_ALSA_ERR("%s: struct snd_ivtv_card * already exists\n",
  189. __func__);
  190. return 0;
  191. }
  192. if (snd_ivtv_init(v4l2_dev)) {
  193. IVTV_ALSA_ERR("%s: failed to create struct snd_ivtv_card\n",
  194. __func__);
  195. } else {
  196. IVTV_DEBUG_ALSA_INFO("created ivtv ALSA interface instance\n");
  197. }
  198. return 0;
  199. }
  200. static int __init ivtv_alsa_init(void)
  201. {
  202. pr_info("ivtv-alsa: module loading...\n");
  203. ivtv_ext_init = &ivtv_alsa_load;
  204. return 0;
  205. }
  206. static void __exit snd_ivtv_exit(struct snd_ivtv_card *itvsc)
  207. {
  208. struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
  209. /* FIXME - pointer checks & shutdown itvsc */
  210. snd_card_free(itvsc->sc);
  211. itv->alsa = NULL;
  212. }
  213. static int __exit ivtv_alsa_exit_callback(struct device *dev, void *data)
  214. {
  215. struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
  216. struct snd_ivtv_card *itvsc;
  217. if (v4l2_dev == NULL) {
  218. pr_err("ivtv-alsa: %s: struct v4l2_device * is NULL\n",
  219. __func__);
  220. return 0;
  221. }
  222. itvsc = to_snd_ivtv_card(v4l2_dev);
  223. if (itvsc == NULL) {
  224. IVTV_ALSA_WARN("%s: struct snd_ivtv_card * is NULL\n",
  225. __func__);
  226. return 0;
  227. }
  228. snd_ivtv_exit(itvsc);
  229. return 0;
  230. }
  231. static void __exit ivtv_alsa_exit(void)
  232. {
  233. struct device_driver *drv;
  234. int ret;
  235. pr_info("ivtv-alsa: module unloading...\n");
  236. drv = driver_find("ivtv", &pci_bus_type);
  237. ret = driver_for_each_device(drv, NULL, NULL, ivtv_alsa_exit_callback);
  238. (void)ret; /* suppress compiler warning */
  239. ivtv_ext_init = NULL;
  240. pr_info("ivtv-alsa: module unload complete\n");
  241. }
  242. module_init(ivtv_alsa_init);
  243. module_exit(ivtv_alsa_exit);