1 /* 2 * ALSA PCM device for the 3 * ALSA interface to ivtv PCM capture streams 4 * 5 * Copyright (C) 2009,2012 Andy Walls <awalls@md.metrocast.net> 6 * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> 7 * 8 * Portions of this work were sponsored by ONELAN Limited for the cx18 driver 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 23 * 02111-1307 USA 24 */ 25 26 #include <linux/init.h> 27 #include <linux/kernel.h> 28 #include <linux/vmalloc.h> 29 30 #include <media/v4l2-device.h> 31 32 #include <sound/core.h> 33 #include <sound/pcm.h> 34 35 #include "ivtv-driver.h" 36 #include "ivtv-queue.h" 37 #include "ivtv-streams.h" 38 #include "ivtv-fileops.h" 39 #include "ivtv-alsa.h" 40 #include "ivtv-alsa-pcm.h" 41 42 static unsigned int pcm_debug; 43 module_param(pcm_debug, int, 0644); 44 MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); 45 46 #define dprintk(fmt, arg...) \ 47 do { \ 48 if (pcm_debug) \ 49 pr_info("ivtv-alsa-pcm %s: " fmt, __func__, ##arg); \ 50 } while (0) 51 52 static struct snd_pcm_hardware snd_ivtv_hw_capture = { 53 .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | 54 SNDRV_PCM_INFO_MMAP | 55 SNDRV_PCM_INFO_INTERLEAVED | 56 SNDRV_PCM_INFO_MMAP_VALID, 57 58 .formats = SNDRV_PCM_FMTBIT_S16_LE, 59 60 .rates = SNDRV_PCM_RATE_48000, 61 62 .rate_min = 48000, 63 .rate_max = 48000, 64 .channels_min = 2, 65 .channels_max = 2, 66 .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ 67 .period_bytes_min = 64, /* 12544/2, */ 68 .period_bytes_max = 12544, 69 .periods_min = 2, 70 .periods_max = 98, /* 12544, */ 71 }; 72 73 static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc, 74 u8 *pcm_data, 75 size_t num_bytes) 76 { 77 struct snd_pcm_substream *substream; 78 struct snd_pcm_runtime *runtime; 79 unsigned int oldptr; 80 unsigned int stride; 81 int period_elapsed = 0; 82 int length; 83 84 dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc, 85 pcm_data, num_bytes); 86 87 substream = itvsc->capture_pcm_substream; 88 if (substream == NULL) { 89 dprintk("substream was NULL\n"); 90 return; 91 } 92 93 runtime = substream->runtime; 94 if (runtime == NULL) { 95 dprintk("runtime was NULL\n"); 96 return; 97 } 98 99 stride = runtime->frame_bits >> 3; 100 if (stride == 0) { 101 dprintk("stride is zero\n"); 102 return; 103 } 104 105 length = num_bytes / stride; 106 if (length == 0) { 107 dprintk("%s: length was zero\n", __func__); 108 return; 109 } 110 111 if (runtime->dma_area == NULL) { 112 dprintk("dma area was NULL - ignoring\n"); 113 return; 114 } 115 116 oldptr = itvsc->hwptr_done_capture; 117 if (oldptr + length >= runtime->buffer_size) { 118 unsigned int cnt = 119 runtime->buffer_size - oldptr; 120 memcpy(runtime->dma_area + oldptr * stride, pcm_data, 121 cnt * stride); 122 memcpy(runtime->dma_area, pcm_data + cnt * stride, 123 length * stride - cnt * stride); 124 } else { 125 memcpy(runtime->dma_area + oldptr * stride, pcm_data, 126 length * stride); 127 } 128 snd_pcm_stream_lock(substream); 129 130 itvsc->hwptr_done_capture += length; 131 if (itvsc->hwptr_done_capture >= 132 runtime->buffer_size) 133 itvsc->hwptr_done_capture -= 134 runtime->buffer_size; 135 136 itvsc->capture_transfer_done += length; 137 if (itvsc->capture_transfer_done >= 138 runtime->period_size) { 139 itvsc->capture_transfer_done -= 140 runtime->period_size; 141 period_elapsed = 1; 142 } 143 144 snd_pcm_stream_unlock(substream); 145 146 if (period_elapsed) 147 snd_pcm_period_elapsed(substream); 148 } 149 150 static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream) 151 { 152 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 153 struct snd_pcm_runtime *runtime = substream->runtime; 154 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; 155 struct ivtv *itv = to_ivtv(v4l2_dev); 156 struct ivtv_stream *s; 157 struct ivtv_open_id item; 158 int ret; 159 160 /* Instruct the CX2341[56] to start sending packets */ 161 snd_ivtv_lock(itvsc); 162 s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; 163 164 v4l2_fh_init(&item.fh, s->vdev); 165 item.itv = itv; 166 item.type = s->type; 167 168 /* See if the stream is available */ 169 if (ivtv_claim_stream(&item, item.type)) { 170 /* No, it's already in use */ 171 snd_ivtv_unlock(itvsc); 172 return -EBUSY; 173 } 174 175 if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || 176 test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { 177 /* We're already streaming. No additional action required */ 178 snd_ivtv_unlock(itvsc); 179 return 0; 180 } 181 182 183 runtime->hw = snd_ivtv_hw_capture; 184 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 185 itvsc->capture_pcm_substream = substream; 186 runtime->private_data = itv; 187 188 itv->pcm_announce_callback = ivtv_alsa_announce_pcm_data; 189 190 /* Not currently streaming, so start it up */ 191 set_bit(IVTV_F_S_STREAMING, &s->s_flags); 192 ret = ivtv_start_v4l2_encode_stream(s); 193 snd_ivtv_unlock(itvsc); 194 195 return ret; 196 } 197 198 static int snd_ivtv_pcm_capture_close(struct snd_pcm_substream *substream) 199 { 200 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 201 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; 202 struct ivtv *itv = to_ivtv(v4l2_dev); 203 struct ivtv_stream *s; 204 205 /* Instruct the ivtv to stop sending packets */ 206 snd_ivtv_lock(itvsc); 207 s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; 208 ivtv_stop_v4l2_encode_stream(s, 0); 209 clear_bit(IVTV_F_S_STREAMING, &s->s_flags); 210 211 ivtv_release_stream(s); 212 213 itv->pcm_announce_callback = NULL; 214 snd_ivtv_unlock(itvsc); 215 216 return 0; 217 } 218 219 static int snd_ivtv_pcm_ioctl(struct snd_pcm_substream *substream, 220 unsigned int cmd, void *arg) 221 { 222 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 223 int ret; 224 225 snd_ivtv_lock(itvsc); 226 ret = snd_pcm_lib_ioctl(substream, cmd, arg); 227 snd_ivtv_unlock(itvsc); 228 return ret; 229 } 230 231 232 static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, 233 size_t size) 234 { 235 struct snd_pcm_runtime *runtime = subs->runtime; 236 237 dprintk("Allocating vbuffer\n"); 238 if (runtime->dma_area) { 239 if (runtime->dma_bytes > size) 240 return 0; 241 242 vfree(runtime->dma_area); 243 } 244 runtime->dma_area = vmalloc(size); 245 if (!runtime->dma_area) 246 return -ENOMEM; 247 248 runtime->dma_bytes = size; 249 250 return 0; 251 } 252 253 static int snd_ivtv_pcm_hw_params(struct snd_pcm_substream *substream, 254 struct snd_pcm_hw_params *params) 255 { 256 dprintk("%s called\n", __func__); 257 258 return snd_pcm_alloc_vmalloc_buffer(substream, 259 params_buffer_bytes(params)); 260 } 261 262 static int snd_ivtv_pcm_hw_free(struct snd_pcm_substream *substream) 263 { 264 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 265 unsigned long flags; 266 267 spin_lock_irqsave(&itvsc->slock, flags); 268 if (substream->runtime->dma_area) { 269 dprintk("freeing pcm capture region\n"); 270 vfree(substream->runtime->dma_area); 271 substream->runtime->dma_area = NULL; 272 } 273 spin_unlock_irqrestore(&itvsc->slock, flags); 274 275 return 0; 276 } 277 278 static int snd_ivtv_pcm_prepare(struct snd_pcm_substream *substream) 279 { 280 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 281 282 itvsc->hwptr_done_capture = 0; 283 itvsc->capture_transfer_done = 0; 284 285 return 0; 286 } 287 288 static int snd_ivtv_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 289 { 290 return 0; 291 } 292 293 static 294 snd_pcm_uframes_t snd_ivtv_pcm_pointer(struct snd_pcm_substream *substream) 295 { 296 unsigned long flags; 297 snd_pcm_uframes_t hwptr_done; 298 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 299 300 spin_lock_irqsave(&itvsc->slock, flags); 301 hwptr_done = itvsc->hwptr_done_capture; 302 spin_unlock_irqrestore(&itvsc->slock, flags); 303 304 return hwptr_done; 305 } 306 307 static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, 308 unsigned long offset) 309 { 310 void *pageptr = subs->runtime->dma_area + offset; 311 312 return vmalloc_to_page(pageptr); 313 } 314 315 static struct snd_pcm_ops snd_ivtv_pcm_capture_ops = { 316 .open = snd_ivtv_pcm_capture_open, 317 .close = snd_ivtv_pcm_capture_close, 318 .ioctl = snd_ivtv_pcm_ioctl, 319 .hw_params = snd_ivtv_pcm_hw_params, 320 .hw_free = snd_ivtv_pcm_hw_free, 321 .prepare = snd_ivtv_pcm_prepare, 322 .trigger = snd_ivtv_pcm_trigger, 323 .pointer = snd_ivtv_pcm_pointer, 324 .page = snd_pcm_get_vmalloc_page, 325 }; 326 327 int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc) 328 { 329 struct snd_pcm *sp; 330 struct snd_card *sc = itvsc->sc; 331 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; 332 struct ivtv *itv = to_ivtv(v4l2_dev); 333 int ret; 334 335 ret = snd_pcm_new(sc, "CX2341[56] PCM", 336 0, /* PCM device 0, the only one for this card */ 337 0, /* 0 playback substreams */ 338 1, /* 1 capture substream */ 339 &sp); 340 if (ret) { 341 IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n", 342 __func__, ret); 343 goto err_exit; 344 } 345 346 spin_lock_init(&itvsc->slock); 347 348 snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, 349 &snd_ivtv_pcm_capture_ops); 350 sp->info_flags = 0; 351 sp->private_data = itvsc; 352 strlcpy(sp->name, itv->card_name, sizeof(sp->name)); 353 354 return 0; 355 356 err_exit: 357 return ret; 358 } 359