static ssize_t pcm_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct pcm *pcm = file->private_data; struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; AUDIO_INFO("%s: size = %d\n", __func__, count); if (!pcm->ac) pcm_ioctl(file, AUDIO_START, 0); ac = pcm->ac; if (!ac) return -ENODEV; while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("pcm_write: timeout. dsp dead?\n"); //BUG(); return -EFAULT; } xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_from_user(ab->data, buf, xfer)) return -EFAULT; buf += xfer; count -= xfer; ab->used = xfer; q6audio_write(ac, ab); ac->cpu_buf ^= 1; } return buf - start; }
static ssize_t mp3_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct mp3 *mp3 = file->private_data; struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; if (!mp3->ac) mp3_ioctl(file, AUDIO_START, 0); ac = mp3->ac; if (!ac) return -ENODEV; while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_from_user(ab->data, buf, xfer)) return -EFAULT; buf += xfer; count -= xfer; ab->used = xfer; q6audio_write(ac, ab); ac->cpu_buf ^= 1; } return buf - start; }
static int snd_qsd_fake_playback_dma_thread(void *data) { int rc = 0; int rcopy; struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; struct snd_pcm_runtime *runtime = substream->runtime; struct qsd_audio *prtd = runtime->private_data; struct audio_buffer *ab; struct audio_client *ac; unsigned char *ptr; while (prtd->thread_exit == 0) { DBG(" start handler"); // wait until state is changed // at this point this thread waits until SNDRV_PCM_TRIGGER_START comes // SNDRV_PCM_TRIGGER_STOP // wait_event_interruptible(prtd->fake_wait, (prtd->start == 1 || prtd->thread_exit == 1)); DBG(" wake up %d %d", prtd->start, prtd->thread_exit); if (prtd->thread_exit) break; ac = prtd->ac; while (prtd->start == 1) { // wait until new buffer appear // // DBG(" ac = %X, prtd = %X, substream = %X", ac, prtd, substream); ab = ac->buf + ac->cpu_buf; if (ab->used) { DBG("wait a buffer %d", ac->cpu_buf); if (!wait_event_timeout(ac->wait, (ab->used == 0), 5 * HZ)) { DBG("timeout. dsp dead?\n"); rc = -EFAULT; goto fail; } // some buffer become free, report about state change now // snd_pcm_period_elapsed(prtd->substream); } mutex_lock(&prtd->mlock); if (prtd->start == 0) { DBG("flag is set - exit thread"); mutex_unlock(&prtd->mlock); break; // EXIT FROM LOOP } // send buffer to DSP // ptr = runtime->dma_area + prtd->buf_curoff; rcopy = prtd->buf_chunk; if (rcopy > ab->size) rcopy = ab->size; memcpy(ab->data, ptr, rcopy); ab->used = rcopy; q6audio_write(ac, ab); ac->cpu_buf ^= 1; // move fake dma pointer forward // spin_lock(&prtd->lock); prtd->buf_curoff += prtd->buf_chunk; if (prtd->buf_curoff >= prtd->buf_maxoff) prtd->buf_curoff = 0; spin_unlock(&prtd->lock); // update stream settings if required // if (qsd_glb_ctl.update) { rc = qsd_audio_volume_update(prtd); qsd_glb_ctl.update = 0; } mutex_unlock(&prtd->mlock); fail: ; // CotullaTODO: handle this fault somehow. } DBG(" end handler"); } DBG(" exit"); return 0; }
// Jagan- static ssize_t pcm_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct pcm *pcm = file->private_data; struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; #if 0 // Jagan+ if(!task_has_rt_policy(current)) { struct sched_param param = { .sched_priority = 99 }; printk(KERN_INFO "pcm_write to change to RT tid = %d\n", current->pid); if(sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m )!=0) { printk(KERN_ERR "pcm_write fail to change to RT\n"); } } // Jagan- #endif if (!pcm->ac) pcm_ioctl(file, AUDIO_START, 0); ac = pcm->ac; if (!ac) return -ENODEV; while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("[%s:%s] timeout. dsp dead?\n", __MM_FILE__, __func__); q6audio_dsp_not_responding(); } xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_from_user(ab->data, buf, xfer)) return -EFAULT; buf += xfer; count -= xfer; ab->used = 1; ab->actual_size = xfer; q6audio_write(ac, ab); ac->cpu_buf ^= 1; } return buf - start; } static int pcm_release(struct inode *inode, struct file *file) { struct pcm *pcm = file->private_data; if (pcm->ac) q6audio_close(pcm->ac); kfree(pcm); pr_info("[%s:%s] release\n", __MM_FILE__, __func__); // Jagan+ if (unlikely(1 == Is_first_boot_flag)) Is_first_boot_flag = 0; // Jagan- return 0; } static struct file_operations pcm_fops = { .owner = THIS_MODULE, .open = pcm_open, .write = pcm_write, .release = pcm_release, .unlocked_ioctl = pcm_ioctl, }; struct miscdevice pcm_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "msm_pcm_out", .fops = &pcm_fops, }; static int __init pcm_init(void) { return misc_register(&pcm_misc); } device_initcall(pcm_init);