ivtv-alsa-pcm.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * ALSA PCM device for the
  4. * ALSA interface to ivtv PCM capture streams
  5. *
  6. * Copyright (C) 2009,2012 Andy Walls <[email protected]>
  7. * Copyright (C) 2009 Devin Heitmueller <[email protected]>
  8. *
  9. * Portions of this work were sponsored by ONELAN Limited for the cx18 driver
  10. */
  11. #include "ivtv-driver.h"
  12. #include "ivtv-queue.h"
  13. #include "ivtv-streams.h"
  14. #include "ivtv-fileops.h"
  15. #include "ivtv-alsa.h"
  16. #include "ivtv-alsa-pcm.h"
  17. #include <sound/core.h>
  18. #include <sound/pcm.h>
  19. static unsigned int pcm_debug;
  20. module_param(pcm_debug, int, 0644);
  21. MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm");
  22. #define dprintk(fmt, arg...) \
  23. do { \
  24. if (pcm_debug) \
  25. pr_info("ivtv-alsa-pcm %s: " fmt, __func__, ##arg); \
  26. } while (0)
  27. static const struct snd_pcm_hardware snd_ivtv_hw_capture = {
  28. .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
  29. SNDRV_PCM_INFO_MMAP |
  30. SNDRV_PCM_INFO_INTERLEAVED |
  31. SNDRV_PCM_INFO_MMAP_VALID,
  32. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  33. .rates = SNDRV_PCM_RATE_48000,
  34. .rate_min = 48000,
  35. .rate_max = 48000,
  36. .channels_min = 2,
  37. .channels_max = 2,
  38. .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
  39. .period_bytes_min = 64, /* 12544/2, */
  40. .period_bytes_max = 12544,
  41. .periods_min = 2,
  42. .periods_max = 98, /* 12544, */
  43. };
  44. static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc,
  45. u8 *pcm_data,
  46. size_t num_bytes)
  47. {
  48. struct snd_pcm_substream *substream;
  49. struct snd_pcm_runtime *runtime;
  50. unsigned int oldptr;
  51. unsigned int stride;
  52. int period_elapsed = 0;
  53. int length;
  54. dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc,
  55. pcm_data, num_bytes);
  56. substream = itvsc->capture_pcm_substream;
  57. if (substream == NULL) {
  58. dprintk("substream was NULL\n");
  59. return;
  60. }
  61. runtime = substream->runtime;
  62. if (runtime == NULL) {
  63. dprintk("runtime was NULL\n");
  64. return;
  65. }
  66. stride = runtime->frame_bits >> 3;
  67. if (stride == 0) {
  68. dprintk("stride is zero\n");
  69. return;
  70. }
  71. length = num_bytes / stride;
  72. if (length == 0) {
  73. dprintk("%s: length was zero\n", __func__);
  74. return;
  75. }
  76. if (runtime->dma_area == NULL) {
  77. dprintk("dma area was NULL - ignoring\n");
  78. return;
  79. }
  80. oldptr = itvsc->hwptr_done_capture;
  81. if (oldptr + length >= runtime->buffer_size) {
  82. unsigned int cnt =
  83. runtime->buffer_size - oldptr;
  84. memcpy(runtime->dma_area + oldptr * stride, pcm_data,
  85. cnt * stride);
  86. memcpy(runtime->dma_area, pcm_data + cnt * stride,
  87. length * stride - cnt * stride);
  88. } else {
  89. memcpy(runtime->dma_area + oldptr * stride, pcm_data,
  90. length * stride);
  91. }
  92. snd_pcm_stream_lock(substream);
  93. itvsc->hwptr_done_capture += length;
  94. if (itvsc->hwptr_done_capture >=
  95. runtime->buffer_size)
  96. itvsc->hwptr_done_capture -=
  97. runtime->buffer_size;
  98. itvsc->capture_transfer_done += length;
  99. if (itvsc->capture_transfer_done >=
  100. runtime->period_size) {
  101. itvsc->capture_transfer_done -=
  102. runtime->period_size;
  103. period_elapsed = 1;
  104. }
  105. snd_pcm_stream_unlock(substream);
  106. if (period_elapsed)
  107. snd_pcm_period_elapsed(substream);
  108. }
  109. static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream)
  110. {
  111. struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
  112. struct snd_pcm_runtime *runtime = substream->runtime;
  113. struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
  114. struct ivtv *itv = to_ivtv(v4l2_dev);
  115. struct ivtv_stream *s;
  116. struct ivtv_open_id item;
  117. int ret;
  118. /* Instruct the CX2341[56] to start sending packets */
  119. snd_ivtv_lock(itvsc);
  120. if (ivtv_init_on_first_open(itv)) {
  121. snd_ivtv_unlock(itvsc);
  122. return -ENXIO;
  123. }
  124. s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
  125. v4l2_fh_init(&item.fh, &s->vdev);
  126. item.itv = itv;
  127. item.type = s->type;
  128. /* See if the stream is available */
  129. if (ivtv_claim_stream(&item, item.type)) {
  130. /* No, it's already in use */
  131. v4l2_fh_exit(&item.fh);
  132. snd_ivtv_unlock(itvsc);
  133. return -EBUSY;
  134. }
  135. if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) ||
  136. test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
  137. /* We're already streaming. No additional action required */
  138. snd_ivtv_unlock(itvsc);
  139. return 0;
  140. }
  141. runtime->hw = snd_ivtv_hw_capture;
  142. snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
  143. itvsc->capture_pcm_substream = substream;
  144. runtime->private_data = itv;
  145. itv->pcm_announce_callback = ivtv_alsa_announce_pcm_data;
  146. /* Not currently streaming, so start it up */
  147. set_bit(IVTV_F_S_STREAMING, &s->s_flags);
  148. ret = ivtv_start_v4l2_encode_stream(s);
  149. snd_ivtv_unlock(itvsc);
  150. return ret;
  151. }
  152. static int snd_ivtv_pcm_capture_close(struct snd_pcm_substream *substream)
  153. {
  154. struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
  155. struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
  156. struct ivtv *itv = to_ivtv(v4l2_dev);
  157. struct ivtv_stream *s;
  158. /* Instruct the ivtv to stop sending packets */
  159. snd_ivtv_lock(itvsc);
  160. s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
  161. ivtv_stop_v4l2_encode_stream(s, 0);
  162. clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
  163. ivtv_release_stream(s);
  164. itv->pcm_announce_callback = NULL;
  165. snd_ivtv_unlock(itvsc);
  166. return 0;
  167. }
  168. static int snd_ivtv_pcm_prepare(struct snd_pcm_substream *substream)
  169. {
  170. struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
  171. itvsc->hwptr_done_capture = 0;
  172. itvsc->capture_transfer_done = 0;
  173. return 0;
  174. }
  175. static int snd_ivtv_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  176. {
  177. return 0;
  178. }
  179. static
  180. snd_pcm_uframes_t snd_ivtv_pcm_pointer(struct snd_pcm_substream *substream)
  181. {
  182. unsigned long flags;
  183. snd_pcm_uframes_t hwptr_done;
  184. struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
  185. spin_lock_irqsave(&itvsc->slock, flags);
  186. hwptr_done = itvsc->hwptr_done_capture;
  187. spin_unlock_irqrestore(&itvsc->slock, flags);
  188. return hwptr_done;
  189. }
  190. static const struct snd_pcm_ops snd_ivtv_pcm_capture_ops = {
  191. .open = snd_ivtv_pcm_capture_open,
  192. .close = snd_ivtv_pcm_capture_close,
  193. .prepare = snd_ivtv_pcm_prepare,
  194. .trigger = snd_ivtv_pcm_trigger,
  195. .pointer = snd_ivtv_pcm_pointer,
  196. };
  197. int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc)
  198. {
  199. struct snd_pcm *sp;
  200. struct snd_card *sc = itvsc->sc;
  201. struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
  202. struct ivtv *itv = to_ivtv(v4l2_dev);
  203. int ret;
  204. ret = snd_pcm_new(sc, "CX2341[56] PCM",
  205. 0, /* PCM device 0, the only one for this card */
  206. 0, /* 0 playback substreams */
  207. 1, /* 1 capture substream */
  208. &sp);
  209. if (ret) {
  210. IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n",
  211. __func__, ret);
  212. goto err_exit;
  213. }
  214. spin_lock_init(&itvsc->slock);
  215. snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
  216. &snd_ivtv_pcm_capture_ops);
  217. snd_pcm_set_managed_buffer_all(sp, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
  218. sp->info_flags = 0;
  219. sp->private_data = itvsc;
  220. strscpy(sp->name, itv->card_name, sizeof(sp->name));
  221. return 0;
  222. err_exit:
  223. return ret;
  224. }