/* Stop substream if still running. */ static void pcm_disconnect_substream(struct snd_pcm_substream *substream) { if (substream->runtime && snd_pcm_running(substream)) { snd_pcm_stream_lock_irq(substream); snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); snd_pcm_stream_unlock_irq(substream); } }
snd_pcm_uframes_t ksnd_pcm_avail_update(ksnd_pcm_t *kpcm) { snd_pcm_substream_t *substream = kpcm->substream; snd_pcm_uframes_t avail; snd_pcm_stream_lock_irq(substream); avail = _ksnd_pcm_avail_update(substream); snd_pcm_stream_unlock_irq(substream); return avail; }
static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, struct snd_pcm_sync_ptr32 __user *src) { struct snd_pcm_runtime *runtime = substream->runtime; volatile struct snd_pcm_mmap_status *status; volatile struct snd_pcm_mmap_control *control; u32 sflags; struct snd_pcm_mmap_control scontrol; struct snd_pcm_mmap_status sstatus; snd_pcm_uframes_t boundary; int err; if (snd_BUG_ON(!runtime)) return -EINVAL; if (get_user(sflags, &src->flags) || get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || get_user(scontrol.avail_min, &src->c.control.avail_min)) return -EFAULT; if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { err = snd_pcm_hwsync(substream); if (err < 0) return err; } status = runtime->status; control = runtime->control; boundary = recalculate_boundary(runtime); if (! boundary) boundary = 0x7fffffff; snd_pcm_stream_lock_irq(substream); /* FIXME: we should consider the boundary for the sync from app */ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) control->appl_ptr = scontrol.appl_ptr; else scontrol.appl_ptr = control->appl_ptr % boundary; if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) control->avail_min = scontrol.avail_min; else scontrol.avail_min = control->avail_min; sstatus.state = status->state; sstatus.hw_ptr = status->hw_ptr % boundary; sstatus.tstamp = status->tstamp; sstatus.suspended_state = status->suspended_state; sstatus.audio_tstamp = status->audio_tstamp; snd_pcm_stream_unlock_irq(substream); if (put_user(sstatus.state, &src->s.status.state) || put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || put_user(sstatus.suspended_state, &src->s.status.suspended_state) || compat_put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) || put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || put_user(scontrol.avail_min, &src->c.control.avail_min)) return -EFAULT; return 0; }
static int stop_lock_stream(struct snd_pcm_substream *substream) { if (substream) { snd_pcm_stream_lock_irq(substream); if (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING && substream->ops) substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); } return 0; }
/** * \brief Obtain last position update hi-res timestamp * \param pcm PCM handle * \param avail Number of available frames when timestamp was grabbed * \param tstamp Hi-res timestamp * \return 0 on success otherwise a negative error code * * The alsa-lib doxygen comments include the following: * Note this function does not update the actual r/w pointer * for applications. * * However examining the implementation of snd_pcm_hw_htimestamp() * there is a call to snd_pcm_hw_avail_update(). This implementation * therefore makes an equivalent call. */ int ksnd_pcm_htimestamp(ksnd_pcm_t *kpcm, snd_pcm_uframes_t *avail, struct timespec *tstamp) { snd_pcm_substream_t *substream = kpcm->substream; snd_pcm_runtime_t *runtime; snd_pcm_uframes_t myavail; struct timespec mystamp; /* we can use a radically different approach to the userspace library (which loops making sure * avail is not modified). this is primarily because we can lock out interrupts. */ snd_pcm_stream_lock_irq(substream); runtime = substream->runtime; /*NICK made changes here, first he did as suggested by Dan and changed myavail to be obtained by checking the data structure without doing any update. Then he realised that myavail actually just confuses the issue, it is almost always 8, because the timestamp was taken after the hardware started to read the first 8 sample block. Even when it isn't 8, this is simply showing the jitter in the timestamp. The purpose of myavail is to try and correct that jitter, however because it is quantized to 8 samples, it actually makes the jitter much worse, since you have a jitter that varies by 10 or 20 us, and you correct for it by adjusting by lumps of around 160 us. So I set myavail to be zero always. Also I added a a return failure if the timestamp is set to zero. */ /* Dagobert: Also add UFS922 here for the "bad" 7101BWC cpu * currently it seems so that this works for both cpu types * (BWC vs. BWD) */ #if defined(__TDT__) \ && (defined(FORTIS_HDBOX) \ || defined(UFS922) \ || defined(UFC960) \ || defined(HL101) \ || defined(VIP1_V2) \ || defined(VIP2_V1) \ || defined(OCTAGON1008) \ || defined(IPBOX9900) \ || defined(IPBOX99) \ || defined(IPBOX55) \ || defined(CUBEREVO_250HD) \ || defined(CUBEREVO)) myavail = _ksnd_pcm_avail_update(kpcm->substream); #else myavail = 0; #endif /*NICK*/ mystamp = runtime->status->tstamp; snd_pcm_stream_unlock_irq(substream); if ((mystamp.tv_sec == 0) && (mystamp.tv_nsec == 0)) return -1; if (myavail < 0) return myavail; *avail = myavail; *tstamp = mystamp; return 0; }
static void hdmi_dai_abort(struct device *dev) { struct hdmi_audio_data *ad = dev_get_drvdata(dev); mutex_lock(&ad->current_stream_lock); if (ad->current_stream && ad->current_stream->runtime && snd_pcm_running(ad->current_stream)) { dev_err(dev, "HDMI display disabled, aborting playback\n"); snd_pcm_stream_lock_irq(ad->current_stream); snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED); snd_pcm_stream_unlock_irq(ad->current_stream); } mutex_unlock(&ad->current_stream_lock); }
int ksnd_pcm_mmap_begin(ksnd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames) { snd_pcm_substream_t *substream = pcm->substream; snd_pcm_channel_area_t *xareas = pcm->hwareas; if (snd_BUG_ON(!substream || !areas || !offset || !frames)) return -EFAULT; snd_pcm_stream_lock_irq(substream); _ksnd_pcm_mmap_begin(substream, offset, frames); snd_pcm_stream_unlock_irq(substream); *areas = xareas; KSND_DEBUG("Allocated %lu frames offset by %lu\n", *frames, *offset); return 0; }
static void stb7100_capture_start_playback(snd_pcm_substream_t *substream) { pcm_hw_t *chip = snd_pcm_substream_chip(substream); STAUD_StreamParams_t StartParams; U32 Error = 0; StartParams.StreamContent = STAUD_STREAM_CONTENT_ALSA; // STAUD_STREAM_CONTENT_MAX; // For ALSA Added in STAUDLX // StartParams.StreamType= STAUD_STREAM_TYPE_ES; StartParams.SamplingFrequency = substream->runtime->rate; snd_pcm_stream_unlock_irq(substream); Error=STAUD_DRStart(chip->AudioHandle,STAUD_OBJECT_DECODER_COMPRESSED0,&StartParams); if(Error!=0) { printk(KERN_ALERT "STAUD_DRSTART Failed Error code =%d and device is =%d \n",Error,chip->card_data->major); } snd_pcm_stream_lock_irq(substream); // spin_unlock(&chip->lock); }
snd_pcm_sframes_t ksnd_pcm_mmap_commit(ksnd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames) { snd_pcm_substream_t *substream = pcm->substream; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t appl_ptr; snd_pcm_sframes_t res = frames; int err; if (snd_BUG_ON(!substream)) return -EFAULT; /* for SPDIF we need to run though the just committed PCM samples and * add formating (unless raw mode is enabled) */ // BUG_ON(substream->pcm->card->number == 2); /* TODO: magic number */ snd_pcm_stream_lock_irq(substream); switch (_ksnd_pcm_state(substream)) { case SNDRV_PCM_STATE_XRUN: res = -EPIPE; goto _end_unlock; case SNDRV_PCM_STATE_SUSPENDED: res = -ESTRPIPE; goto _end_unlock; } appl_ptr = runtime->control->appl_ptr; /* verify no-one is interleaving access to the playback */ // TODO: what about capture? BUG_ON(substream->stream == SNDRV_PCM_STREAM_PLAYBACK && (appl_ptr % runtime->buffer_size) != offset); appl_ptr += frames; if (appl_ptr >= runtime->boundary) appl_ptr = 0; err = _ksnd_pcm_update_appl_ptr(substream, appl_ptr); if (err < 0) res = err; _end_unlock: snd_pcm_stream_unlock_irq(substream); return res; }
static void stb7100_capture_stop_playback(snd_pcm_substream_t *substream) { pcm_hw_t *chip = snd_pcm_substream_chip(substream); STAUD_Stop_t StopMode; U32 Error=0; STAUD_Fade_t Fade; StopMode = STAUD_STOP_NOW; Fade.FadeType = STAUD_FADE_SOFT_MUTE; //spin_lock(&chip->lock); DEBUG_PRINT((" Debug : stb7100_capture_stop_playback Unlocking Stream \n ")); snd_pcm_stream_unlock_irq(substream); DEBUG_PRINT((" Debug : Unlocked Stream And DR Stop \n ")); Error = STAUD_DRStop(chip->AudioHandle,STAUD_OBJECT_DECODER_COMPRESSED0,StopMode,&Fade); if(Error!=0) { printk(KERN_ALERT "STAUD_DRStop Failed Error code =%d Device =%d \n",Error,chip->card_data->major); } snd_pcm_stream_lock_irq(substream); }
static int _ksnd_pcm_wait(snd_pcm_substream_t *substream, int timeout) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t avail; int res = 1; /* success is a positive integer */ snd_pcm_stream_lock_irq(substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) avail = snd_pcm_playback_avail(runtime); else avail = snd_pcm_capture_avail(runtime); if (avail < runtime->control->avail_min) { wait_queue_t wait; long jiffies; if (timeout >= 0) jiffies = (timeout * HZ) / 1000; else jiffies = 10 * HZ; init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); do { if (signal_pending(current)) { res = -ERESTARTSYS; break; } set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); jiffies = schedule_timeout(jiffies); snd_pcm_stream_lock_irq(substream); if (jiffies == 0) { if (timeout < 0) { snd_printd("ksnd: [hw:%d,%d] playback write error " "(DMA or IRQ trouble?)\n", substream->pcm->card->number, substream->pcm->device); jiffies = 10 * HZ; } else { res = 0; /* timeout */ } } switch (_ksnd_pcm_state(substream)) { case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_XRUN: case SNDRV_PCM_STATE_DRAINING: res = -EPIPE; break; case SNDRV_PCM_STATE_SUSPENDED: printk("%s: result ESTRPIPE %d\n", __FUNCTION__, __LINE__); res = -ESTRPIPE; break; case SNDRV_PCM_STATE_PAUSED: printk("%s: Waiting for buffer %d\n", __FUNCTION__, __LINE__); break; default: break; } if (1 != res) break; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) avail = snd_pcm_playback_avail(runtime); else avail = snd_pcm_capture_avail(runtime); } while (avail < runtime->control->avail_min); remove_wait_queue(&runtime->sleep, &wait); } snd_pcm_stream_unlock_irq(substream); return res; }
static int _ksnd_pcm_writei1(snd_pcm_substream_t *substream, unsigned long data, snd_pcm_uframes_t size, int srcchannels, transfer_f transfer) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; int err = 0; if (size == 0) return 0; snd_pcm_stream_lock_irq(substream); switch (_ksnd_pcm_state(substream)) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PAUSED: break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; goto _end_unlock; case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; goto _end_unlock; default: err = -EBADFD; goto _end_unlock; } while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; snd_pcm_uframes_t cont; avail = _ksnd_pcm_avail_update(substream); #if defined(__TDT__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) // attribute xfer_align is not used any more /* #warning Do we have to check the values 'size' and 'avail'? */ if ((avail < runtime->control->avail_min) && (size > avail)) { #else if (((avail < runtime->control->avail_min && size > avail) || (size >= runtime->xfer_align && avail < runtime->xfer_align))) { #endif int res; snd_pcm_stream_unlock_irq(substream); do { res = _ksnd_pcm_wait(substream, 10000); } while (res == 0 && _ksnd_pcm_state(substream) != SNDRV_PCM_STATE_PREPARED && _ksnd_pcm_state(substream) != SNDRV_PCM_STATE_PAUSED); snd_pcm_stream_lock_irq(substream); if (res == 0) /* timeout */ { if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_SUSPENDED) { err = -ESTRPIPE; goto _end_unlock; } else { snd_printd("playback write error " "(DMA or IRQ trouble?)\n"); err = -EIO; goto _end_unlock; } } else if (res < 0) /* error */ { err = res; goto _end_unlock; } avail = snd_pcm_playback_avail(runtime); } frames = size > avail ? avail : size; cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); err = transfer(substream, appl_ofs, data, offset, frames, srcchannels); snd_pcm_stream_lock_irq(substream); if (err < 0) goto _end; switch (_ksnd_pcm_state(substream)) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; goto _end_unlock; case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; goto _end_unlock; default: break; } appl_ptr += frames; if (appl_ptr >= runtime->boundary) { runtime->control->appl_ptr = 0; } else { runtime->control->appl_ptr = appl_ptr; } if (substream->ops->ack) substream->ops->ack(substream); offset += frames; size -= frames; xfer += frames; if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_PREPARED && snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t) runtime->start_threshold) { err = snd_pcm_start(substream); if (err < 0) goto _end_unlock; } } _end_unlock: snd_pcm_stream_unlock_irq(substream); _end: return xfer > 0 ? (snd_pcm_sframes_t) xfer : err; } int ksnd_pcm_writei(ksnd_pcm_t *kpcm, int *data, unsigned int size, unsigned int srcchannels) { snd_pcm_substream_t *substream = kpcm->substream; snd_pcm_runtime_t *runtime; int err; transfer_f out_func = 0; runtime = substream->runtime; if (substream->pcm->card->number == 2) { out_func = _ksnd_pcm_IEC60958_transfer; } else { out_func = _ksnd_pcm_write_transfer; } if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && runtime->channels > 1) return -EINVAL; if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return -EINVAL; if (size == 0) return 0; do { err = _ksnd_pcm_writei1(substream, (unsigned long)data, size, srcchannels, out_func); if (err < 0) { if (err == -EAGAIN) { continue; } if (err == -EPIPE) { printk("ALSA Aud underrun for hw:%d,%d\n", substream->pcm->card->number, substream->pcm->device); if ((err = ksnd_pcm_prepare(kpcm)) < 0) return err; continue; } return err; } else { data += samples_to_bytes(runtime, err * srcchannels); size -= err; } } while (size > 0); return 0; }
static void stb7100_pcm_start_playback(snd_pcm_substream_t *substream) { pcm_hw_t *chip = snd_pcm_substream_chip(substream); STAUD_StreamParams_t StartParams; U32 Error = 0; StartParams.StreamContent = STAUD_STREAM_CONTENT_ALSA; // STAUD_STREAM_CONTENT_MAX; // For ALSA Added in STAUDLX // StartParams.StreamType= STAUD_STREAM_TYPE_ES; StartParams.SamplingFrequency = substream->runtime->rate; //spin_lock(&chip->lock); if(chip->card_data->major == SPDIF_DEVICE) { STAUD_DigitalMode_t SPDIFMode=0; if(chip->iec60958_rawmode) { SPDIFMode = STAUD_DIGITAL_MODE_NONCOMPRESSED; } else { SPDIFMode = STAUD_DIGITAL_MODE_NONCOMPRESSED; switch(chip->iec_encoding_mode) { // Fill the desired Start Stream Contents case ENCODING_IEC61937_MPEG_384_FRAME: case ENCODING_IEC61937_MPEG_1152_FRAME: case ENCODING_IEC61937_MPEG_2304_FRAME: case ENCODING_IEC61937_MPEG_768_FRAME: case ENCODING_IEC61937_MPEG_2304_FRAME_LSF: case ENCODING_IEC61937_MPEG_768_FRAME_LSF: StartParams.StreamContent = STAUD_STREAM_CONTENT_MPEG2; break; case ENCODING_IEC61937_MPEG_1024_FRAME: StartParams.StreamContent = STAUD_STREAM_CONTENT_MPEG_AAC; break; case ENCODING_IEC61937_AC3: StartParams.StreamContent = STAUD_STREAM_CONTENT_AC3; break; case ENCODING_IEC61937_DTS_1: case ENCODING_IEC61937_DTS_2: case ENCODING_IEC61937_DTS_3: StartParams.StreamContent = STAUD_STREAM_CONTENT_DTS; break; default: break; } } // Here set the SPDIF Mode Error = STAUD_OPSetDigitalMode(chip->AudioHandle, STAUD_OBJECT_OUTPUT_SPDIF0,SPDIFMode); } snd_pcm_stream_unlock_irq(substream); Error=STAUD_DRStart(chip->AudioHandle,STAUD_OBJECT_DECODER_COMPRESSED0,&StartParams); if(Error!=0) { printk(KERN_ALERT "STAUD_DRSTART Failed Error code =%d and device is =%d \n",Error,chip->card_data->major); } // Set the Volume After Start as indicated by Mixer Interface, if any { STAUD_Attenuation_t Attenuatation; memset(&Attenuatation,0,sizeof(STAUD_Attenuation_t)) ; Attenuatation.Left = chip->Volume[LEFTCHANNEL]; Attenuatation.Right = chip->Volume[RIGHTCHANNEL]; switch(chip->card_data->major) { case PCM0_DEVICE: Error=STAUD_PPSetAttenuation(chip->AudioHandle,STAUD_OBJECT_DECODER_COMPRESSED0, &Attenuatation); break; case PCM1_DEVICE: Error=STAUD_PPSetAttenuation(chip->AudioHandle,STAUD_OBJECT_DECODER_COMPRESSED1, &Attenuatation); break; case SPDIF_DEVICE: Error=STAUD_PPSetAttenuation(chip->AudioHandle,STAUD_OBJECT_DECODER_COMPRESSED2, &Attenuatation); break; default: printk("oops in vol Set + Start \n"); break; } DEBUG_PRINT((" Volume l=%d, r=%d", chip->Volume[LEFTCHANNEL], chip->Volume[RIGHTCHANNEL])); DEBUG_PRINT(("Set Attenuatation Error is =%d, Device is =%d",Error,chip->card_data->major)); } snd_pcm_stream_lock_irq(substream); // spin_unlock(&chip->lock); }