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 42static unsigned int pcm_debug; 43module_param(pcm_debug, int, 0644); 44MODULE_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 52static 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 73static 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=%zu\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 150static 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 163 if (ivtv_init_on_first_open(itv)) { 164 snd_ivtv_unlock(itvsc); 165 return -ENXIO; 166 } 167 168 s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; 169 170 v4l2_fh_init(&item.fh, s->vdev); 171 item.itv = itv; 172 item.type = s->type; 173 174 /* See if the stream is available */ 175 if (ivtv_claim_stream(&item, item.type)) { 176 /* No, it's already in use */ 177 snd_ivtv_unlock(itvsc); 178 return -EBUSY; 179 } 180 181 if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || 182 test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { 183 /* We're already streaming. No additional action required */ 184 snd_ivtv_unlock(itvsc); 185 return 0; 186 } 187 188 189 runtime->hw = snd_ivtv_hw_capture; 190 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 191 itvsc->capture_pcm_substream = substream; 192 runtime->private_data = itv; 193 194 itv->pcm_announce_callback = ivtv_alsa_announce_pcm_data; 195 196 /* Not currently streaming, so start it up */ 197 set_bit(IVTV_F_S_STREAMING, &s->s_flags); 198 ret = ivtv_start_v4l2_encode_stream(s); 199 snd_ivtv_unlock(itvsc); 200 201 return ret; 202} 203 204static int snd_ivtv_pcm_capture_close(struct snd_pcm_substream *substream) 205{ 206 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 207 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; 208 struct ivtv *itv = to_ivtv(v4l2_dev); 209 struct ivtv_stream *s; 210 211 /* Instruct the ivtv to stop sending packets */ 212 snd_ivtv_lock(itvsc); 213 s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; 214 ivtv_stop_v4l2_encode_stream(s, 0); 215 clear_bit(IVTV_F_S_STREAMING, &s->s_flags); 216 217 ivtv_release_stream(s); 218 219 itv->pcm_announce_callback = NULL; 220 snd_ivtv_unlock(itvsc); 221 222 return 0; 223} 224 225static int snd_ivtv_pcm_ioctl(struct snd_pcm_substream *substream, 226 unsigned int cmd, void *arg) 227{ 228 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 229 int ret; 230 231 snd_ivtv_lock(itvsc); 232 ret = snd_pcm_lib_ioctl(substream, cmd, arg); 233 snd_ivtv_unlock(itvsc); 234 return ret; 235} 236 237 238static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, 239 size_t size) 240{ 241 struct snd_pcm_runtime *runtime = subs->runtime; 242 243 dprintk("Allocating vbuffer\n"); 244 if (runtime->dma_area) { 245 if (runtime->dma_bytes > size) 246 return 0; 247 248 vfree(runtime->dma_area); 249 } 250 runtime->dma_area = vmalloc(size); 251 if (!runtime->dma_area) 252 return -ENOMEM; 253 254 runtime->dma_bytes = size; 255 256 return 0; 257} 258 259static int snd_ivtv_pcm_hw_params(struct snd_pcm_substream *substream, 260 struct snd_pcm_hw_params *params) 261{ 262 dprintk("%s called\n", __func__); 263 264 return snd_pcm_alloc_vmalloc_buffer(substream, 265 params_buffer_bytes(params)); 266} 267 268static int snd_ivtv_pcm_hw_free(struct snd_pcm_substream *substream) 269{ 270 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 271 unsigned long flags; 272 273 spin_lock_irqsave(&itvsc->slock, flags); 274 if (substream->runtime->dma_area) { 275 dprintk("freeing pcm capture region\n"); 276 vfree(substream->runtime->dma_area); 277 substream->runtime->dma_area = NULL; 278 } 279 spin_unlock_irqrestore(&itvsc->slock, flags); 280 281 return 0; 282} 283 284static int snd_ivtv_pcm_prepare(struct snd_pcm_substream *substream) 285{ 286 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 287 288 itvsc->hwptr_done_capture = 0; 289 itvsc->capture_transfer_done = 0; 290 291 return 0; 292} 293 294static int snd_ivtv_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 295{ 296 return 0; 297} 298 299static 300snd_pcm_uframes_t snd_ivtv_pcm_pointer(struct snd_pcm_substream *substream) 301{ 302 unsigned long flags; 303 snd_pcm_uframes_t hwptr_done; 304 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream); 305 306 spin_lock_irqsave(&itvsc->slock, flags); 307 hwptr_done = itvsc->hwptr_done_capture; 308 spin_unlock_irqrestore(&itvsc->slock, flags); 309 310 return hwptr_done; 311} 312 313static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, 314 unsigned long offset) 315{ 316 void *pageptr = subs->runtime->dma_area + offset; 317 318 return vmalloc_to_page(pageptr); 319} 320 321static struct snd_pcm_ops snd_ivtv_pcm_capture_ops = { 322 .open = snd_ivtv_pcm_capture_open, 323 .close = snd_ivtv_pcm_capture_close, 324 .ioctl = snd_ivtv_pcm_ioctl, 325 .hw_params = snd_ivtv_pcm_hw_params, 326 .hw_free = snd_ivtv_pcm_hw_free, 327 .prepare = snd_ivtv_pcm_prepare, 328 .trigger = snd_ivtv_pcm_trigger, 329 .pointer = snd_ivtv_pcm_pointer, 330 .page = snd_pcm_get_vmalloc_page, 331}; 332 333int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc) 334{ 335 struct snd_pcm *sp; 336 struct snd_card *sc = itvsc->sc; 337 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; 338 struct ivtv *itv = to_ivtv(v4l2_dev); 339 int ret; 340 341 ret = snd_pcm_new(sc, "CX2341[56] PCM", 342 0, /* PCM device 0, the only one for this card */ 343 0, /* 0 playback substreams */ 344 1, /* 1 capture substream */ 345 &sp); 346 if (ret) { 347 IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n", 348 __func__, ret); 349 goto err_exit; 350 } 351 352 spin_lock_init(&itvsc->slock); 353 354 snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, 355 &snd_ivtv_pcm_capture_ops); 356 sp->info_flags = 0; 357 sp->private_data = itvsc; 358 strlcpy(sp->name, itv->card_name, sizeof(sp->name)); 359 360 return 0; 361 362err_exit: 363 return ret; 364} 365