📄 audio.c
字号:
wave_dev->card->pt.enable_gpr_name) >= 0) val |= AFMT_AC3; } return put_user(val, p); case SNDCTL_DSP_SETFMT: /* Same as SNDCTL_DSP_SAMPLESIZE */ DPF(2, "SNDCTL_DSP_SETFMT:\n"); if (get_user(val, p)) return -EFAULT; DPD(2, " val is %d\n", val); if (val != AFMT_QUERY) { if (file->f_mode & FMODE_READ) { struct wave_format format; spin_lock_irqsave(&wiinst->lock, flags); format = wiinst->format; format.id = val; if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { spin_unlock_irqrestore(&wiinst->lock, flags); return -EINVAL; } val = wiinst->format.id; spin_unlock_irqrestore(&wiinst->lock, flags); DPD(2, "set recording format -> %d\n", val); } if (file->f_mode & FMODE_WRITE) { struct wave_format format; spin_lock_irqsave(&woinst->lock, flags); format = woinst->format; format.id = val; if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { spin_unlock_irqrestore(&woinst->lock, flags); return -EINVAL; } val = woinst->format.id; spin_unlock_irqrestore(&woinst->lock, flags); DPD(2, "set playback format -> %d\n", val); } return put_user(val, p); } else { if (file->f_mode & FMODE_READ) val = wiinst->format.id; else if (file->f_mode & FMODE_WRITE) val = woinst->format.id; return put_user(val, p); } break; case SOUND_PCM_READ_BITS: if (file->f_mode & FMODE_READ) val = wiinst->format.bitsperchannel; else if (file->f_mode & FMODE_WRITE) val = woinst->format.bitsperchannel; return put_user(val, p); case SOUND_PCM_READ_RATE: if (file->f_mode & FMODE_READ) val = wiinst->format.samplingrate; else if (file->f_mode & FMODE_WRITE) val = woinst->format.samplingrate; return put_user(val, p); case SOUND_PCM_READ_CHANNELS: if (file->f_mode & FMODE_READ) val = wiinst->format.channels; else if (file->f_mode & FMODE_WRITE) val = woinst->format.channels; return put_user(val, p); case SOUND_PCM_WRITE_FILTER: DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n"); break; case SOUND_PCM_READ_FILTER: DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n"); break; case SNDCTL_DSP_SETSYNCRO: DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n"); break; case SNDCTL_DSP_GETTRIGGER: DPF(2, "SNDCTL_DSP_GETTRIGGER:\n"); if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)) val |= PCM_ENABLE_OUTPUT; if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT)) val |= PCM_ENABLE_INPUT; return put_user(val, p); case SNDCTL_DSP_SETTRIGGER: DPF(2, "SNDCTL_DSP_SETTRIGGER:\n"); if (get_user(val, p)) return -EFAULT; if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); if (val & PCM_ENABLE_OUTPUT) { wave_dev->enablebits |= PCM_ENABLE_OUTPUT; if (woinst->state & WAVE_STATE_OPEN) emu10k1_waveout_start(wave_dev); } else { wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT; if (woinst->state & WAVE_STATE_STARTED) emu10k1_waveout_stop(wave_dev); } spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); if (val & PCM_ENABLE_INPUT) { wave_dev->enablebits |= PCM_ENABLE_INPUT; if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_start(wave_dev); } else { wave_dev->enablebits &= ~PCM_ENABLE_INPUT; if (wiinst->state & WAVE_STATE_STARTED) emu10k1_wavein_stop(wave_dev); } spin_unlock_irqrestore(&wiinst->lock, flags); } break; case SNDCTL_DSP_GETOSPACE: { audio_buf_info info; DPF(4, "SNDCTL_DSP_GETOSPACE:\n"); if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&woinst->lock, flags); if (woinst->state & WAVE_STATE_OPEN) { emu10k1_waveout_update(woinst); emu10k1_waveout_getxfersize(woinst, &bytestocopy); info.bytes = bytestocopy; } else { calculate_ofrag(woinst); info.bytes = woinst->buffer.size; } spin_unlock_irqrestore(&woinst->lock, flags); info.bytes *= woinst->num_voices; info.fragsize = woinst->buffer.fragment_size * woinst->num_voices; info.fragstotal = woinst->buffer.numfrags * woinst->num_voices; info.fragments = info.bytes / info.fragsize; if (copy_to_user(p, &info, sizeof(info))) return -EFAULT; } break; case SNDCTL_DSP_GETISPACE: { audio_buf_info info; DPF(4, "SNDCTL_DSP_GETISPACE:\n"); if (!(file->f_mode & FMODE_READ)) return -EINVAL; spin_lock_irqsave(&wiinst->lock, flags); if (wiinst->state & WAVE_STATE_OPEN) { emu10k1_wavein_update(wave_dev->card, wiinst); emu10k1_wavein_getxfersize(wiinst, &bytestocopy); info.bytes = bytestocopy; } else { calculate_ifrag(wiinst); info.bytes = 0; } spin_unlock_irqrestore(&wiinst->lock, flags); info.fragstotal = wiinst->buffer.numfrags; info.fragments = info.bytes / wiinst->buffer.fragment_size; info.fragsize = wiinst->buffer.fragment_size; if (copy_to_user(p, &info, sizeof(info))) return -EFAULT; } break; case SNDCTL_DSP_NONBLOCK: DPF(2, "SNDCTL_DSP_NONBLOCK:\n"); file->f_flags |= O_NONBLOCK; break; case SNDCTL_DSP_GETODELAY: DPF(4, "SNDCTL_DSP_GETODELAY:\n"); if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&woinst->lock, flags); if (woinst->state & WAVE_STATE_OPEN) { emu10k1_waveout_update(woinst); emu10k1_waveout_getxfersize(woinst, &bytestocopy); val = woinst->buffer.size - bytestocopy; } else val = 0; val *= woinst->num_voices; spin_unlock_irqrestore(&woinst->lock, flags); return put_user(val, p); case SNDCTL_DSP_GETIPTR: { count_info cinfo; DPF(4, "SNDCTL_DSP_GETIPTR: \n"); if (!(file->f_mode & FMODE_READ)) return -EINVAL; spin_lock_irqsave(&wiinst->lock, flags); if (wiinst->state & WAVE_STATE_OPEN) { emu10k1_wavein_update(wave_dev->card, wiinst); cinfo.ptr = wiinst->buffer.hw_pos; cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % wiinst->buffer.size; cinfo.blocks = cinfo.bytes / wiinst->buffer.fragment_size - wiinst->blocks; wiinst->blocks = cinfo.bytes / wiinst->buffer.fragment_size; } else { cinfo.ptr = 0; cinfo.bytes = 0; cinfo.blocks = 0; } if (wiinst->mmapped) wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size; spin_unlock_irqrestore(&wiinst->lock, flags); if (copy_to_user(p, &cinfo, sizeof(cinfo))) return -EFAULT; } break; case SNDCTL_DSP_GETOPTR: { count_info cinfo; DPF(4, "SNDCTL_DSP_GETOPTR:\n"); if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&woinst->lock, flags); if (woinst->state & WAVE_STATE_OPEN || ((woinst->format.passthrough == 1) && wave_dev->card->pt.state)) { int num_fragments; if (woinst->format.passthrough == 1) { emu10k1_pt_waveout_update(wave_dev); cinfo.bytes = woinst->total_played; } else { emu10k1_waveout_update(woinst); cinfo.bytes = woinst->total_played; } cinfo.ptr = woinst->buffer.hw_pos; num_fragments = cinfo.bytes / woinst->buffer.fragment_size; cinfo.blocks = num_fragments - woinst->blocks; woinst->blocks = num_fragments; cinfo.bytes *= woinst->num_voices; cinfo.ptr *= woinst->num_voices; } else { cinfo.ptr = 0; cinfo.bytes = 0; cinfo.blocks = 0; } if (woinst->mmapped) woinst->buffer.free_bytes %= woinst->buffer.fragment_size; spin_unlock_irqrestore(&woinst->lock, flags); if (copy_to_user(p, &cinfo, sizeof(cinfo))) return -EFAULT; } break; case SNDCTL_DSP_GETBLKSIZE: DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n"); if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); calculate_ofrag(woinst); val = woinst->buffer.fragment_size * woinst->num_voices; spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); calculate_ifrag(wiinst); val = wiinst->buffer.fragment_size; spin_unlock_irqrestore(&wiinst->lock, flags); } return put_user(val, p); break; case SNDCTL_DSP_POST: if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); if (!(woinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) && (woinst->total_copied > 0)) emu10k1_waveout_start(wave_dev); spin_unlock_irqrestore(&woinst->lock, flags); } break; case SNDCTL_DSP_SUBDIVIDE: DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n"); break; case SNDCTL_DSP_SETFRAGMENT: DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n"); if (get_user(val, p)) return -EFAULT; DPD(2, "val is %#x\n", val); if (val == 0) return -EIO; if (file->f_mode & FMODE_WRITE) { /* digital pass-through fragment count and size are fixed values */ if (woinst->state & WAVE_STATE_OPEN || (woinst->format.passthrough == 1)) return -EINVAL; /* too late to change */ woinst->buffer.ossfragshift = val & 0xffff; woinst->buffer.numfrags = (val >> 16) & 0xffff; } if (file->f_mode & FMODE_READ) { if (wiinst->state & WAVE_STATE_OPEN) return -EINVAL; /* too late to change */ wiinst->buffer.ossfragshift = val & 0xffff; wiinst->buffer.numfrags = (val >> 16) & 0xffff; } break; case SNDCTL_COPR_LOAD: { copr_buffer *buf; u32 i; DPF(4, "SNDCTL_COPR_LOAD:\n"); buf = kmalloc(sizeof(copr_buffer), GFP_KERNEL); if (!buf) return -ENOMEM; if (copy_from_user(buf, p, sizeof(copr_buffer))) { kfree (buf); return -EFAULT; } if ((buf->command != CMD_READ) && (buf->command != CMD_WRITE)) { kfree (buf); return -EINVAL; } if (buf->command == CMD_WRITE) { #ifdef DBGEMU if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {#else if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000) ) && !( //any register allowed raw access to users goes here: (buf->offs == DBG || buf->offs == A_DBG) && (buf->len == 1))) {#endif kfree(buf); return -EINVAL; } } else { if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) { kfree(buf); return -EINVAL; } } if (((unsigned)buf->flags) > 0x3f) buf->flags = 0; if (buf->command == CMD_READ) { for (i = 0; i < buf->len; i++) ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, buf->flags); if (copy_to_user(p, buf, sizeof(copr_buffer))) { kfree(buf); return -EFAULT; } } else { for (i = 0; i < buf->len; i++) sblive_writeptr(wave_dev->card, buf->offs + i, buf->flags, ((u32 *) buf->data)[i]); } kfree (buf); break; } default: /* Default is unrecognized command */ DPD(2, "default: %#x\n", cmd); return -EINVAL; } return 0;}static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned long address, int *type){ struct emu10k1_wavedevice *wave_dev = vma->vm_private_data; struct woinst *woinst = wave_dev->woinst; struct wiinst *wiinst = wave_dev->wiinst; struct page *dmapage; unsigned long pgoff; int rd, wr; DPF(3, "emu10k1_mm_nopage()\n"); DPD(3, "addr: %#lx\n", address); if (address > vma->vm_end) { DPF(1, "EXIT, returning NOPAGE_SIGBUS\n"); return NOPAGE_SIGBUS; /* Disallow mremap */ } pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT); if (woinst != NULL) wr = woinst->mmapped; else wr = 0; if (wiinst != NULL) rd = wiinst->mmapped; else rd = 0; /* if full-duplex (read+write) and we have two sets of bufs, * then the playback buffers come first, sez soundcard.c */ if (wr) { if (pgoff >= woinst->buffer.pages) { pgoff -= woinst->buffer.pages; dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE); } else dmapage = virt_to_page (woinst->voice[0].mem.addr[pgoff]); } else { dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE); } get_page (dmapage); DPD(3, "page: %#lx\n", (unsigned long) dmapage); if (type) *type = VM_FAULT_MINOR; return dmapage;}static struct vm_operations_struct emu10k1_mm_ops = { .nopage = emu10k1_mm_nopage,};static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma){ struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; unsigned long max_pages, n_pages, pgoffset; struct woinst *woinst = NULL; struct wiinst *wiinst = NULL; unsigned long flags; DPF(2, "emu10k1_audio_mmap()\n"); max_pages = 0; if (vma->vm_flags & VM_WRITE) { woinst = wave_dev->woinst; spin_lock_irqsave(&woinst->lock, flags); /* No m'mapping possible for multichannel */ if (woinst->num_voices > 1) { spin_unlock_irqrestore(&woinst->lock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -