📄 ali5455.c
字号:
} else { if (controller_independent_spdif_locked > 0) { if (!dmabuf->controller_spdifout_channel) { dmabuf->ready = 0; dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card); if (!dmabuf->controller_spdifout_channel) return -EBUSY; } } else { if (!dmabuf->write_channel) { dmabuf->ready = 0; dmabuf->write_channel = card->alloc_pcm_channel(card); if (!dmabuf->write_channel) return -EBUSY; } } } if (codec_independent_spdif_locked > 0) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 2))) return ret; } else { if (controller_independent_spdif_locked > 0) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 3))) return ret; } else { if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; } } if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; add_wait_queue(&dmabuf->wait, &waita); while (count > 0) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&state->card->lock, flags); if (PM_SUSPENDED(card)) { spin_unlock_irqrestore(&card->lock, flags); schedule(); if (signal_pending(current)) { if (!ret) ret = -EAGAIN; break; } continue; } swptr = dmabuf->swptr; cnt = ali_get_free_write_space(state); /* Bound the maximum size to how much we can copy to the * dma buffer before we hit the end. If we have more to * copy then it will get done in a second pass of this * loop starting from the beginning of the buffer. */ if (cnt > (dmabuf->dmasize - swptr)) cnt = dmabuf->dmasize - swptr; spin_unlock_irqrestore(&state->card->lock, flags);#ifdef DEBUG2 printk(KERN_INFO "ali_audio: ali_write: %d bytes available space\n", cnt);#endif if (cnt > count) cnt = count; /* Lop off the last two bits to force the code to always * write in full samples. This keeps software that sets * O_NONBLOCK but doesn't check the return value of the * write call from getting things out of state where they * think a full 4 byte sample was written when really only * a portion was, resulting in odd sound and stereo * hysteresis. */ cnt &= ~0x3; if (cnt <= 0) { unsigned long tmo; // There is data waiting to be played /* * Force the trigger setting since we would * deadlock with it set any other way */ if (codec_independent_spdif_locked > 0) { dmabuf->trigger = SPDIF_ENABLE_OUTPUT; ali_update_lvi(state, 2); } else { if (controller_independent_spdif_locked > 0) { dmabuf->trigger = SPDIF_ENABLE_OUTPUT; ali_update_lvi(state, 3); } else { dmabuf->trigger = PCM_ENABLE_OUTPUT; ali_update_lvi(state, 0); } } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; goto ret; } /* Not strictly correct but works */ tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that either interrupt is NOT serviced correctly (pending interrupt) or it is TOO LATE for the process to be scheduled to run (scheduler latency) which results in a (potential) buffer underrun. And worse, there is NOTHING we can do to prevent it. */ /* FIXME - do timeout handling here !! */ schedule_timeout(tmo >= 2 ? tmo : 2); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto ret; } continue; } if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; goto ret; } swptr = (swptr + cnt) % dmabuf->dmasize; spin_lock_irqsave(&state->card->lock, flags); if (PM_SUSPENDED(card)) { spin_unlock_irqrestore(&card->lock, flags); continue; } dmabuf->swptr = swptr; dmabuf->count += cnt; count -= cnt; buffer += cnt; ret += cnt; spin_unlock_irqrestore(&state->card->lock, flags); } if (swptr % dmabuf->fragsize) { x = dmabuf->fragsize - (swptr % dmabuf->fragsize); memset(dmabuf->rawbuf + swptr, '\0', x); }ret: if (codec_independent_spdif_locked > 0) { ali_update_lvi(state, 2); } else { if (controller_independent_spdif_locked > 0) { ali_update_lvi(state, 3); } else { ali_update_lvi(state, 0); } } set_current_state(TASK_RUNNING); remove_wait_queue(&dmabuf->wait, &waita); return ret;}/* No kernel lock - we have our own spinlock */static unsigned int ali_poll(struct file *file, struct poll_table_struct *wait){ struct ali_state *state = (struct ali_state *) file->private_data; struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; unsigned int mask = 0; if (!dmabuf->ready) return 0; poll_wait(file, &dmabuf->wait, wait); spin_lock_irqsave(&state->card->lock, flags); ali_update_ptr(state); if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) { if (dmabuf->count >= (signed) dmabuf->fragsize) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) { if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&state->card->lock, flags); return mask;}static int ali_mmap(struct file *file, struct vm_area_struct *vma){ struct ali_state *state = (struct ali_state *) file->private_data; struct dmabuf *dmabuf = &state->dmabuf; int ret = -EINVAL; unsigned long size; lock_kernel(); if (vma->vm_flags & VM_WRITE) { if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) { ret = -EBUSY; goto out; } } if (vma->vm_flags & VM_READ) { if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) { ret = -EBUSY; goto out; } } if ((ret = prog_dmabuf(state, 0)) != 0) goto out; ret = -EINVAL; if (vma->vm_pgoff != 0) goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << dmabuf->buforder)) goto out; ret = -EAGAIN; if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) goto out; dmabuf->mapped = 1; dmabuf->trigger = 0; ret = 0;out: unlock_kernel(); return ret;}static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct ali_state *state = (struct ali_state *) file->private_data; struct ali_channel *c = NULL; struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; audio_buf_info abinfo; count_info cinfo; unsigned int i_scr; int val = 0, ret; struct ac97_codec *codec = state->card->ac97_codec[0]; void __user *argp = (void __user *)arg; int __user *p = argp;#ifdef DEBUG printk("ali_audio: ali_ioctl, arg=0x%x, cmd=", arg ? *p : 0);#endif switch (cmd) { case OSS_GETVERSION:#ifdef DEBUG printk("OSS_GETVERSION\n");#endif return put_user(SOUND_VERSION, p); case SNDCTL_DSP_RESET:#ifdef DEBUG printk("SNDCTL_DSP_RESET\n");#endif spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->enable == DAC_RUNNING) { c = dmabuf->write_channel; __stop_dac(state); } if (dmabuf->enable == ADC_RUNNING) { c = dmabuf->read_channel; __stop_adc(state); } if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { c = dmabuf->codec_spdifout_channel; __stop_spdifout(state); } if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { c = dmabuf->controller_spdifout_channel; __stop_spdifout(state); } if (c != NULL) { outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */ outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR); outb(0, state->card->iobase + c->port + OFF_CIV); outb(0, state->card->iobase + c->port + OFF_LVI); } spin_unlock_irqrestore(&state->card->lock, flags); synchronize_irq(state->card->pci_dev->irq); dmabuf->ready = 0; dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; return 0; case SNDCTL_DSP_SYNC:#ifdef DEBUG printk("SNDCTL_DSP_SYNC\n");#endif if (codec_independent_spdif_locked > 0) { if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING || file->f_flags & O_NONBLOCK) return 0; if ((val = drain_spdifout(state, 1))) return val; } else { if (controller_independent_spdif_locked > 0) { if (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING || file->f_flags & O_NONBLOCK) return 0; if ((val = drain_spdifout(state, 1))) return val; } else { if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK) return 0; if ((val = drain_dac(state, 1))) return val; } } dmabuf->total_bytes = 0; return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */#ifdef DEBUG printk("SNDCTL_DSP_SPEED\n");#endif if (get_user(val, p)) return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_WRITE) { if ((state->card->ac97_status & SPDIF_ON)) { /* S/PDIF Enabled */ /* RELTEK ALC650 only support 48000, need to check that */ if (ali_valid_spdif_rate(codec, val)) { if (codec_independent_spdif_locked > 0) { ali_set_spdif_output(state, -1, 0); stop_spdifout(state); dmabuf->ready = 0; /* I add test codec independent spdif out */ spin_lock_irqsave(&state->card->lock, flags); ali_set_codecspdifout_rate(state, val); // I modified spin_unlock_irqrestore(&state->card->lock, flags); /* Set S/PDIF transmitter rate. */ i_scr = inl(state->card->iobase + ALI_SCR); if ((i_scr & 0x00300000) == 0x00100000) { ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); } else { if ((i_scr&0x00300000) == 0x00200000) { ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); } else { if ((i_scr & 0x00300000) == 0x00300000) { ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); } else { ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); } } } if (!(state->card->ac97_status & SPDIF_ON)) { val = dmabuf->rate; } } else { if (controller_independent_spdif_locked > 0) { stop_spdifout(state); dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); ali_set_spdifout_rate(state, controller_independent_spdif_locked); spin_unlock_irqrestore(&state->card->lock, flags); } else { /* Set DAC rate */ ali_set_spdif_output(state, -1, 0); stop_dac(state); dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); ali_set_dac_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); /* Set S/PDIF transmitter rate. */ ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val); if (!(state->card->ac97_status & SPDIF_ON)) { val = dmabuf->rate; } } } } else { /* Not a valid rate for S/PDIF, ignore it */ val = dmabuf->rate; } } else { stop_dac(state); dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); ali_set_dac_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } } if (file->f_mode & FMODE_READ) { stop_adc(state); dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); ali_set_adc_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } } return put_user(dmabuf->rate, p); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */#ifdef DEBUG printk("SNDCTL_DSP_STEREO\n");#endif if (dmabuf->enable & DAC_RUNNING) { stop_dac(state); } if (dmabuf->enable & ADC_RUNNING) { stop_adc(state); } if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { stop_spdifout(state); } if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) { stop_spdifout(state); } return put_user(1, p); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if (codec_independent_spdif_locked > 0) { if (!dmabuf->ready && (val = prog_dmabuf(state, 2))) return val; } else { if (controller_independent_spdif_locked > 0) { if (!dmabuf->ready && (val = prog_dmabuf(state, 3))) return val; } else { if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) return val; } } } if (file->f_mode & FMODE_READ) { if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) return val; }#ifdef DEBUG printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);#endif return put_user(dmabuf->userfragsize, p); case SNDCTL_DSP_GETFMTS: /* Returns a mask of suppo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -