1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ALSA PCM device for the 4 * ALSA interface to cx18 PCM capture streams 5 * 6 * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> 7 * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> 8 * 9 * Portions of this work were sponsored by ONELAN Limited. 10 */ 11 12 #include <linux/init.h> 13 #include <linux/kernel.h> 14 15 #include <media/v4l2-device.h> 16 17 #include <sound/core.h> 18 #include <sound/pcm.h> 19 20 #include "cx18-driver.h" 21 #include "cx18-queue.h" 22 #include "cx18-streams.h" 23 #include "cx18-fileops.h" 24 #include "cx18-alsa.h" 25 #include "cx18-alsa-pcm.h" 26 27 static unsigned int pcm_debug; 28 module_param(pcm_debug, int, 0644); 29 MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); 30 31 #define dprintk(fmt, arg...) do { \ 32 if (pcm_debug) \ 33 printk(KERN_INFO "cx18-alsa-pcm %s: " fmt, \ 34 __func__, ##arg); \ 35 } while (0) 36 37 static const struct snd_pcm_hardware snd_cx18_hw_capture = { 38 .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | 39 SNDRV_PCM_INFO_MMAP | 40 SNDRV_PCM_INFO_INTERLEAVED | 41 SNDRV_PCM_INFO_MMAP_VALID, 42 43 .formats = SNDRV_PCM_FMTBIT_S16_LE, 44 45 .rates = SNDRV_PCM_RATE_48000, 46 47 .rate_min = 48000, 48 .rate_max = 48000, 49 .channels_min = 2, 50 .channels_max = 2, 51 .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ 52 .period_bytes_min = 64, /* 12544/2, */ 53 .period_bytes_max = 12544, 54 .periods_min = 2, 55 .periods_max = 98, /* 12544, */ 56 }; 57 58 void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, 59 size_t num_bytes) 60 { 61 struct snd_pcm_substream *substream; 62 struct snd_pcm_runtime *runtime; 63 unsigned int oldptr; 64 unsigned int stride; 65 int period_elapsed = 0; 66 int length; 67 68 dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc, 69 pcm_data, num_bytes); 70 71 substream = cxsc->capture_pcm_substream; 72 if (substream == NULL) { 73 dprintk("substream was NULL\n"); 74 return; 75 } 76 77 runtime = substream->runtime; 78 if (runtime == NULL) { 79 dprintk("runtime was NULL\n"); 80 return; 81 } 82 83 stride = runtime->frame_bits >> 3; 84 if (stride == 0) { 85 dprintk("stride is zero\n"); 86 return; 87 } 88 89 length = num_bytes / stride; 90 if (length == 0) { 91 dprintk("%s: length was zero\n", __func__); 92 return; 93 } 94 95 if (runtime->dma_area == NULL) { 96 dprintk("dma area was NULL - ignoring\n"); 97 return; 98 } 99 100 oldptr = cxsc->hwptr_done_capture; 101 if (oldptr + length >= runtime->buffer_size) { 102 unsigned int cnt = 103 runtime->buffer_size - oldptr; 104 memcpy(runtime->dma_area + oldptr * stride, pcm_data, 105 cnt * stride); 106 memcpy(runtime->dma_area, pcm_data + cnt * stride, 107 length * stride - cnt * stride); 108 } else { 109 memcpy(runtime->dma_area + oldptr * stride, pcm_data, 110 length * stride); 111 } 112 snd_pcm_stream_lock(substream); 113 114 cxsc->hwptr_done_capture += length; 115 if (cxsc->hwptr_done_capture >= 116 runtime->buffer_size) 117 cxsc->hwptr_done_capture -= 118 runtime->buffer_size; 119 120 cxsc->capture_transfer_done += length; 121 if (cxsc->capture_transfer_done >= 122 runtime->period_size) { 123 cxsc->capture_transfer_done -= 124 runtime->period_size; 125 period_elapsed = 1; 126 } 127 128 snd_pcm_stream_unlock(substream); 129 130 if (period_elapsed) 131 snd_pcm_period_elapsed(substream); 132 } 133 134 static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream) 135 { 136 struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); 137 struct snd_pcm_runtime *runtime = substream->runtime; 138 struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; 139 struct cx18 *cx = to_cx18(v4l2_dev); 140 struct cx18_stream *s; 141 struct cx18_open_id item; 142 int ret; 143 144 /* Instruct the cx18 to start sending packets */ 145 snd_cx18_lock(cxsc); 146 s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; 147 148 item.cx = cx; 149 item.type = s->type; 150 item.open_id = cx->open_id++; 151 152 /* See if the stream is available */ 153 if (cx18_claim_stream(&item, item.type)) { 154 /* No, it's already in use */ 155 snd_cx18_unlock(cxsc); 156 return -EBUSY; 157 } 158 159 if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || 160 test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { 161 /* We're already streaming. No additional action required */ 162 snd_cx18_unlock(cxsc); 163 return 0; 164 } 165 166 167 runtime->hw = snd_cx18_hw_capture; 168 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 169 cxsc->capture_pcm_substream = substream; 170 runtime->private_data = cx; 171 172 cx->pcm_announce_callback = cx18_alsa_announce_pcm_data; 173 174 /* Not currently streaming, so start it up */ 175 set_bit(CX18_F_S_STREAMING, &s->s_flags); 176 ret = cx18_start_v4l2_encode_stream(s); 177 snd_cx18_unlock(cxsc); 178 179 return ret; 180 } 181 182 static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) 183 { 184 struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); 185 struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; 186 struct cx18 *cx = to_cx18(v4l2_dev); 187 struct cx18_stream *s; 188 189 /* Instruct the cx18 to stop sending packets */ 190 snd_cx18_lock(cxsc); 191 s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; 192 cx18_stop_v4l2_encode_stream(s, 0); 193 clear_bit(CX18_F_S_STREAMING, &s->s_flags); 194 195 cx18_release_stream(s); 196 197 cx->pcm_announce_callback = NULL; 198 snd_cx18_unlock(cxsc); 199 200 return 0; 201 } 202 203 static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, 204 unsigned int cmd, void *arg) 205 { 206 struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); 207 int ret; 208 209 snd_cx18_lock(cxsc); 210 ret = snd_pcm_lib_ioctl(substream, cmd, arg); 211 snd_cx18_unlock(cxsc); 212 return ret; 213 } 214 215 static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream) 216 { 217 struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); 218 219 cxsc->hwptr_done_capture = 0; 220 cxsc->capture_transfer_done = 0; 221 222 return 0; 223 } 224 225 static int snd_cx18_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 226 { 227 return 0; 228 } 229 230 static 231 snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream) 232 { 233 unsigned long flags; 234 snd_pcm_uframes_t hwptr_done; 235 struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); 236 237 spin_lock_irqsave(&cxsc->slock, flags); 238 hwptr_done = cxsc->hwptr_done_capture; 239 spin_unlock_irqrestore(&cxsc->slock, flags); 240 241 return hwptr_done; 242 } 243 244 static const struct snd_pcm_ops snd_cx18_pcm_capture_ops = { 245 .open = snd_cx18_pcm_capture_open, 246 .close = snd_cx18_pcm_capture_close, 247 .ioctl = snd_cx18_pcm_ioctl, 248 .prepare = snd_cx18_pcm_prepare, 249 .trigger = snd_cx18_pcm_trigger, 250 .pointer = snd_cx18_pcm_pointer, 251 }; 252 253 int snd_cx18_pcm_create(struct snd_cx18_card *cxsc) 254 { 255 struct snd_pcm *sp; 256 struct snd_card *sc = cxsc->sc; 257 struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; 258 struct cx18 *cx = to_cx18(v4l2_dev); 259 int ret; 260 261 ret = snd_pcm_new(sc, "CX23418 PCM", 262 0, /* PCM device 0, the only one for this card */ 263 0, /* 0 playback substreams */ 264 1, /* 1 capture substream */ 265 &sp); 266 if (ret) { 267 CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", 268 __func__, ret); 269 goto err_exit; 270 } 271 272 spin_lock_init(&cxsc->slock); 273 274 snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, 275 &snd_cx18_pcm_capture_ops); 276 snd_pcm_set_managed_buffer_all(sp, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); 277 sp->info_flags = 0; 278 sp->private_data = cxsc; 279 strscpy(sp->name, cx->card_name, sizeof(sp->name)); 280 281 return 0; 282 283 err_exit: 284 return ret; 285 } 286