📄 i810_audio.c
字号:
printk("COMP %d ", dmabuf->hwptr / dmabuf->fragsize);#endif } if(status & (DMA_INT_LVI | DMA_INT_DCH)) { /* wake_up() unconditionally on LVI and DCH */ i810_update_ptr(state); wake_up(&dmabuf->wait);#ifdef DEBUG_INTERRUPTS if(status & DMA_INT_LVI) printk("LVI "); if(status & DMA_INT_DCH) printk("DCH -");#endif count = dmabuf->count; if(dmabuf->enable & ADC_RUNNING) count = dmabuf->dmasize - count; if (count >= (int)dmabuf->fragsize) { I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR);#ifdef DEBUG_INTERRUPTS printk(" CONTINUE ");#endif } else { if (dmabuf->enable & DAC_RUNNING) __stop_dac(state); if (dmabuf->enable & ADC_RUNNING) __stop_adc(state); dmabuf->enable = 0;#ifdef DEBUG_INTERRUPTS printk(" STOP ");#endif } } if(card->pci_id == PCI_DEVICE_ID_SI_7012) I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB); else I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR); }#ifdef DEBUG_INTERRUPTS printk(")\n");#endif}static irqreturn_t i810_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct i810_card *card = (struct i810_card *)dev_id; u32 status; spin_lock(&card->lock); status = I810_IOREADL(card, GLOB_STA); if(!(status & INT_MASK)) { spin_unlock(&card->lock); return IRQ_NONE; /* not for us */ } if(status & (INT_PO|INT_PI|INT_MC)) i810_channel_interrupt(card); /* clear 'em */ I810_IOWRITEL(status & INT_MASK, card, GLOB_STA); spin_unlock(&card->lock); return IRQ_HANDLED;}/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to the user's buffer. It is filled by the dma machine and drained by this loop. */static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos){ struct i810_state *state = (struct i810_state *)file->private_data; struct i810_card *card=state ? state->card : NULL; struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; unsigned int swptr; int cnt; int pending; DECLARE_WAITQUEUE(waita, current);#ifdef DEBUG2 printk("i810_audio: i810_read called, count = %d\n", count);#endif if (dmabuf->mapped) return -ENXIO; if (dmabuf->enable & DAC_RUNNING) return -ENODEV; if (!dmabuf->read_channel) { dmabuf->ready = 0; dmabuf->read_channel = card->alloc_rec_pcm_channel(card); if (!dmabuf->read_channel) { return -EBUSY; } } if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; pending = 0; add_wait_queue(&dmabuf->wait, &waita); while (count > 0) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&card->lock, flags); if (PM_SUSPENDED(card)) { spin_unlock_irqrestore(&card->lock, flags); schedule(); if (signal_pending(current)) { if (!ret) ret = -EAGAIN; break; } continue; } cnt = i810_get_available_read_data(state); swptr = dmabuf->swptr; // this is to make the copy_to_user simpler below if(cnt > (dmabuf->dmasize - swptr)) cnt = dmabuf->dmasize - swptr; spin_unlock_irqrestore(&card->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { unsigned long tmo; /* * Don't let us deadlock. The ADC won't start if * dmabuf->trigger isn't set. A call to SETTRIGGER * could have turned it off after we set it to on * previously. */ dmabuf->trigger = PCM_ENABLE_INPUT; /* * This does three things. Updates LVI to be correct, * makes sure the ADC is running, and updates the * hwptr. */ i810_update_lvi(state,1); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; goto done; } /* Set the timeout to how long it would take to fill * two of our buffers. If we haven't been woke up * by then, then we know something is wrong. */ 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 overrun. And worse, there is NOTHING we can do to prevent it. */ if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {#ifdef DEBUG printk(KERN_ERR "i810_audio: recording schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr);#endif /* a buffer overrun, we delay the recovery until next time the while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { ret = ret ? ret : -ERESTARTSYS; goto done; } continue; } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; goto done; } swptr = MODULOP2(swptr + cnt, dmabuf->dmasize); spin_lock_irqsave(&card->lock, flags); if (PM_SUSPENDED(card)) { spin_unlock_irqrestore(&card->lock, flags); continue; } dmabuf->swptr = swptr; pending = dmabuf->count -= cnt; spin_unlock_irqrestore(&card->lock, flags); count -= cnt; buffer += cnt; ret += cnt; } done: pending = dmabuf->dmasize - pending; if (dmabuf->enable || pending >= dmabuf->userfragsize) i810_update_lvi(state, 1); set_current_state(TASK_RUNNING); remove_wait_queue(&dmabuf->wait, &waita); return ret;}/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to the soundcard. it is drained by the dma machine and filled by this loop. */static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){ struct i810_state *state = (struct i810_state *)file->private_data; struct i810_card *card=state ? state->card : NULL; struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; unsigned int swptr = 0; int pending; int cnt; DECLARE_WAITQUEUE(waita, current);#ifdef DEBUG2 printk("i810_audio: i810_write called, count = %d\n", count);#endif if (dmabuf->mapped) return -ENXIO; if (dmabuf->enable & ADC_RUNNING) return -ENODEV; if (!dmabuf->write_channel) { dmabuf->ready = 0; dmabuf->write_channel = card->alloc_pcm_channel(card); if(!dmabuf->write_channel) return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; pending = 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; } cnt = i810_get_free_write_space(state); swptr = dmabuf->swptr; /* 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 "i810_audio: i810_write: %d bytes available space\n", cnt);#endif if (cnt > count) cnt = count; 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 */ dmabuf->trigger = PCM_ENABLE_OUTPUT; i810_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. */ if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {#ifdef DEBUG printk(KERN_ERR "i810_audio: playback schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr);#endif /* a buffer underrun, we delay the recovery until next time the while loop begin and we REALLY have data to play */ //return ret; } 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 = MODULOP2(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; pending = dmabuf->count += cnt; count -= cnt; buffer += cnt; ret += cnt; spin_unlock_irqrestore(&state->card->lock, flags); }ret: if (dmabuf->enable || pending >= dmabuf->userfragsize) i810_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 i810_poll(struct file *file, struct poll_table_struct *wait){ struct i810_state *state = (struct i810_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); if (dmabuf->enable & ADC_RUNNING || dmabuf->trigger & PCM_ENABLE_INPUT) { if (i810_get_available_read_data(state) >= (signed)dmabuf->userfragsize) mask |= POLLIN | POLLRDNORM; } if (dmabuf->enable & DAC_RUNNING || dmabuf->trigger & PCM_ENABLE_OUTPUT) { if (i810_get_free_write_space(state) >= (signed)dmabuf->userfragsize) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&state->card->lock, flags); return mask;}static int i810_mmap(struct file *file, struct vm_area_struct *vma){ struct i810_state *state = (struct i810_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;#ifdef DEBUG_MMAP printk("i810_audio: mmap'ed %ld bytes of data space\n", size);#endifout: unlock_kernel(); return ret;}static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct i810_state *state = (struct i810_state *)file->private_data; struct i810_channel *c = NULL; struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; audio_buf_info abinfo; count_info cinfo; unsigned int i_glob_cnt; 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("i810_audio: i810_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -