static void audio_stop_dma(audio_stream_t *s) { u_int pos; unsigned long flags; audio_buf_t *b; if (!s->buffers) return; local_irq_save(flags); s->stopped = 1; pos = audio_get_dma_pos(s); s3c2410_dma_ctrl(s->dma, S3C2410_DMAOP_FLUSH); local_irq_restore(flags); /* back up pointers to be ready to restart from the same spot */ while (s->dma_head != s->dma_tail) { b = &s->buffers[s->dma_head]; if (b->dma_ref) { b->dma_ref = 0; b->offset = 0; } s->pending_frags++; if (s->dma_head == 0) s->dma_head = s->nbfrags; s->dma_head--; } b = &s->buffers[s->dma_head]; if (b->dma_ref) { b->offset = pos; b->dma_ref = 0; } }
static void audio_stop_dma(audio_stream_t *s) { u_int pos; unsigned long flags; audio_buf_t *b; if (s->dma_spinref > 0 || !s->buffers) return; local_irq_save(flags); s->stopped = 1; DMA_STOP(s); pos = audio_get_dma_pos(s); DMA_CLEAR(s); if (s->spin_idle) { DMA_START(s, SPIN_ADDR, SPIN_SIZE); DMA_START(s, SPIN_ADDR, SPIN_SIZE); s->dma_spinref = 2; } else s->dma_spinref = 0; local_irq_restore(flags); /* back up pointers to be ready to restart from the same spot */ while (s->dma_head != s->dma_tail) { b = &s->buffers[s->dma_head]; if (b->dma_ref) { b->dma_ref = 0; b->offset = 0; } s->pending_frags++; if (s->dma_head == 0) s->dma_head = s->nbfrags; s->dma_head--; } b = &s->buffers[s->dma_head]; if (b->dma_ref) { b->offset = pos; b->dma_ref = 0; } }
static int audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { audio_state_t *state = file->private_data; audio_stream_t *os = state->output_stream; audio_stream_t *is = state->input_stream; long val; DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd); /* dispatch based on command */ switch (cmd) { case OSS_GETVERSION: return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) return put_user(os->fragsize, (int *)arg); else return put_user(is->fragsize, (int *)arg); case SNDCTL_DSP_GETCAPS: val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP; if (is && os) val |= DSP_CAP_DUPLEX; return put_user(val, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (long *) arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { int ret = audio_set_fragments(is, val); if (ret < 0) return ret; ret = put_user(ret, (int *)arg); if (ret) return ret; } if (file->f_mode & FMODE_WRITE) { int ret = audio_set_fragments(os, val); if (ret < 0) return ret; ret = put_user(ret, (int *)arg); if (ret) return ret; } return 0; case SNDCTL_DSP_SYNC: return audio_sync(file); case SNDCTL_DSP_SETDUPLEX: return 0; case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETTRIGGER: val = 0; if (file->f_mode & FMODE_READ && is->active && !is->stopped) val |= PCM_ENABLE_INPUT; if (file->f_mode & FMODE_WRITE && os->active && !os->stopped) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { unsigned long flags; if (!is->active) { if (!is->buffers && audio_setup_buf(is)) return -ENOMEM; audio_prime_rx(state); } local_irq_save(flags); is->stopped = 0; audio_process_dma(is); local_irq_restore(flags); } else { audio_stop_dma(is); } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { unsigned long flags; if (!os->buffers && audio_setup_buf(os)) return -ENOMEM; local_irq_save(flags); if (os->mapped && !os->pending_frags) { os->pending_frags = os->nbfrags; sema_init(&os->sem, 0); os->active = 1; } os->stopped = 0; audio_process_dma(os); local_irq_restore(flags); } else { audio_stop_dma(os); } } return 0; case SNDCTL_DSP_GETOPTR: case SNDCTL_DSP_GETIPTR: { count_info inf = { 0, }; audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; int bytecount, offset; unsigned long flags; if ((s == is && !(file->f_mode & FMODE_READ)) || (s == os && !(file->f_mode & FMODE_WRITE))) return -EINVAL; if (s->active) { local_irq_save(flags); offset = audio_get_dma_pos(s); inf.ptr = s->dma_tail * s->fragsize + offset; bytecount = s->bytecount + offset; s->bytecount = -offset; inf.blocks = s->fragcount; s->fragcount = 0; local_irq_restore(flags); if (bytecount < 0) bytecount = 0; inf.bytes = bytecount; } return copy_to_user((void *)arg, &inf, sizeof(inf)); } case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: { audio_buf_info inf = { 0, }; audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is; if ((s == is && !(file->f_mode & FMODE_READ)) || (s == os && !(file->f_mode & FMODE_WRITE))) return -EINVAL; if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; inf.bytes = atomic_read(&s->sem.count) * s->fragsize; /* inf.bytes -= s->buffers[s->usr_head].offset; */ inf.fragments = inf.bytes / s->fragsize; inf.fragsize = s->fragsize; inf.fragstotal = s->nbfrags; return copy_to_user((void *)arg, &inf, sizeof(inf)); } case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_READ) { audio_reset(is); if (state->need_tx_for_rx) { unsigned long flags; local_irq_save(flags); os->spin_idle = 0; local_irq_restore(flags); } } if (file->f_mode & FMODE_WRITE) { audio_reset(os); } return 0; default: /* * Let the client of this module handle the * non generic ioctls */ return state->client_ioctl(inode, file, cmd, arg); } return 0; }