/* acquires lock */ int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) { struct audio_operations *adev = audio_devs[dev]; unsigned long flags; int err = -EIO; struct dma_buffparms *dmap = adev->dmap_out; if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ return -EINVAL; } spin_lock_irqsave(&dmap->lock,flags); if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ spin_unlock_irqrestore(&dmap->lock,flags); DMAbuf_reset(dev); spin_lock_irqsave(&dmap->lock,flags); } dmap->dma_mode = DMODE_OUTPUT; while (find_output_space(dev, buf, size) <= 0) { spin_unlock_irqrestore(&dmap->lock,flags); if ((err = output_sleep(dev, dontblock)) < 0) { return err; } spin_lock_irqsave(&dmap->lock,flags); } spin_unlock_irqrestore(&dmap->lock,flags); return 0; }
int DMAbuf_release(int dev, int mode) { struct audio_operations *adev = audio_devs[dev]; unsigned long flags; if (adev->open_mode & OPEN_WRITE) adev->dmap_out->closing = 1; if (adev->open_mode & OPEN_READ) adev->dmap_in->closing = 1; if (adev->open_mode & OPEN_WRITE) if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)) if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) DMAbuf_sync(dev); if (adev->dmap_out->dma_mode == DMODE_OUTPUT) memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use); save_flags(flags); cli(); DMAbuf_reset(dev); adev->d->close(dev); if (adev->open_mode & OPEN_WRITE) close_dmap(adev, adev->dmap_out); if (adev->open_mode == OPEN_READ || (adev->open_mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) close_dmap(adev, adev->dmap_in); adev->open_mode = 0; restore_flags(flags); return 0; }
int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) { struct audio_operations *adev = audio_devs[dev]; int err; if (!(adev->open_mode & OPEN_READ)) return 0; if (!(adev->enable_bits & PCM_ENABLE_INPUT)) return 0; if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ DMAbuf_sync(dev); DMAbuf_reset(dev); dmap->dma_mode = DMODE_NONE; } if (!dmap->dma_mode) { reorganize_buffers(dev, dmap, 1); if ((err = adev->d->prepare_for_input(dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; dmap->dma_mode = DMODE_INPUT; } if (!(dmap->flags & DMA_ACTIVE)) { if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 0); dmap->flags |= DMA_ACTIVE; if (adev->d->trigger) adev->d->trigger(dev, adev->enable_bits * adev->go); } return 0; }
int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) { int val, count; unsigned long flags; struct dma_buffparms *dmap; int __user *p = arg; dev = dev >> 4; if (_IOC_TYPE(cmd) == 'C') { if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); /* else printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */ return -ENXIO; } else switch (cmd) { case SNDCTL_DSP_SYNC: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return 0; if (audio_devs[dev]->dmap_out->fragment_size == 0) return 0; sync_output(dev); DMAbuf_sync(dev); DMAbuf_reset(dev); return 0; case SNDCTL_DSP_POST: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return 0; if (audio_devs[dev]->dmap_out->fragment_size == 0) return 0; audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; sync_output(dev); dma_ioctl(dev, SNDCTL_DSP_POST, NULL); return 0; case SNDCTL_DSP_RESET: audio_devs[dev]->audio_mode = AM_NONE; DMAbuf_reset(dev); return 0; case SNDCTL_DSP_GETFMTS: val = audio_devs[dev]->format_mask | AFMT_MU_LAW; break; case SNDCTL_DSP_SETFMT: if (get_user(val, p)) return -EFAULT; val = set_format(dev, val); break; case SNDCTL_DSP_GETISPACE: if (!(audio_devs[dev]->open_mode & OPEN_READ)) return 0; if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) return -EBUSY; return dma_ioctl(dev, cmd, arg); case SNDCTL_DSP_GETOSPACE: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -EPERM; if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) return -EBUSY; return dma_ioctl(dev, cmd, arg); case SNDCTL_DSP_NONBLOCK: spin_lock(&file->f_lock); file->f_flags |= O_NONBLOCK; spin_unlock(&file->f_lock); return 0; case SNDCTL_DSP_GETCAPS: val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ if (audio_devs[dev]->flags & DMA_DUPLEX && audio_devs[dev]->open_mode == OPEN_READWRITE) val |= DSP_CAP_DUPLEX; if (audio_devs[dev]->coproc) val |= DSP_CAP_COPROC; if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ val |= DSP_CAP_BATCH; if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ val |= DSP_CAP_TRIGGER; break; case SOUND_PCM_WRITE_RATE: if (get_user(val, p)) return -EFAULT; val = audio_devs[dev]->d->set_speed(dev, val); break; case SOUND_PCM_READ_RATE: val = audio_devs[dev]->d->set_speed(dev, 0); break; case SNDCTL_DSP_STEREO: if (get_user(val, p)) return -EFAULT; if (val > 1 || val < 0) return -EINVAL; val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; break; case SOUND_PCM_WRITE_CHANNELS: if (get_user(val, p)) return -EFAULT; val = audio_devs[dev]->d->set_channels(dev, val); break; case SOUND_PCM_READ_CHANNELS: val = audio_devs[dev]->d->set_channels(dev, 0); break; case SOUND_PCM_READ_BITS: val = audio_devs[dev]->d->set_bits(dev, 0); break; case SNDCTL_DSP_SETDUPLEX: if (audio_devs[dev]->open_mode != OPEN_READWRITE) return -EPERM; return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; case SNDCTL_DSP_PROFILE: if (get_user(val, p)) return -EFAULT; if (audio_devs[dev]->open_mode & OPEN_WRITE) audio_devs[dev]->dmap_out->applic_profile = val; if (audio_devs[dev]->open_mode & OPEN_READ) audio_devs[dev]->dmap_in->applic_profile = val; return 0; case SNDCTL_DSP_GETODELAY: dmap = audio_devs[dev]->dmap_out; if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -EINVAL; if (!(dmap->flags & DMA_ALLOC_DONE)) { val=0; break; } spin_lock_irqsave(&dmap->lock,flags); /* Compute number of bytes that have been played */ count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); if (count < dmap->fragment_size && dmap->qhead != 0) count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ count += dmap->byte_counter; /* Subtract current count from the number of bytes written by app */ count = dmap->user_counter - count; if (count < 0) count = 0; spin_unlock_irqrestore(&dmap->lock,flags); val = count; break; default: return dma_ioctl(dev, cmd, arg); } return put_user(val, p); }