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