/* CAUTION: call it with irq disabled (due to internal call to snd_pcm_update_hw_ptr) */ static inline snd_pcm_uframes_t _ksnd_pcm_avail_update(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; /*NICK added if to remove real updates which we do not want*/ #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)) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) if (runtime->sleep_min == 0 && _ksnd_pcm_state(substream) == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); #else if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); #endif #endif if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) return snd_pcm_playback_avail(runtime); else return snd_pcm_capture_avail(runtime); }
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 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; }
snd_pcm_state_t ksnd_pcm_state(ksnd_pcm_t *pcm) { return _ksnd_pcm_state(pcm->substream); }
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; }