📄 via82cxxx_audio.c
字号:
assert (card != NULL); if (ppos != &file->f_pos) { DPRINTK ("EXIT, returning -ESPIPE\n"); return -ESPIPE; } rc = via_syscall_down (card, nonblock); if (rc) goto out; if (card->ch_out.is_mapped) { rc = -ENXIO; goto out_up; } rc = via_dsp_do_write (card, buffer, count, nonblock);out_up: up (&card->syscall_sem);out: DPRINTK("EXIT, returning %ld\n",(long) rc); return rc;}static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait){ struct via_info *card; unsigned int mask = 0, rd, wr; DPRINTK ("ENTER\n"); assert (file != NULL); card = file->private_data; assert (card != NULL); rd = (file->f_mode & FMODE_READ); wr = (file->f_mode & FMODE_WRITE); if (wr && (atomic_read (&card->ch_out.n_bufs) == 0)) { assert (card->ch_out.is_active); poll_wait(file, &card->ch_out.wait, wait); } if (rd) { /* XXX is it ok, spec-wise, to start DMA here? */ via_chan_maybe_start (&card->ch_in); if (atomic_read (&card->ch_in.n_bufs) == 0) poll_wait(file, &card->ch_in.wait, wait); } if (wr && (atomic_read (&card->ch_out.n_bufs) > 0)) mask |= POLLOUT | POLLWRNORM; if (rd && (atomic_read (&card->ch_in.n_bufs) > 0)) mask |= POLLIN | POLLRDNORM; DPRINTK("EXIT, returning %u\n", mask); return mask;}/** * via_dsp_drain_playback - sleep until all playback samples are flushed * @card: Private info for specified board * @chan: Channel to drain * @nonblock: boolean, non-zero if O_NONBLOCK is set * * Sleeps until all playback has been flushed to the audio * hardware. * * Locking: inside card->syscall_sem */static int via_dsp_drain_playback (struct via_info *card, struct via_channel *chan, int nonblock){ DPRINTK ("ENTER, nonblock = %d\n", nonblock); if (chan->slop_len > 0) via_chan_flush_frag (chan); if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS) goto out; via_chan_maybe_start (chan); while (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS) { if (nonblock) { DPRINTK ("EXIT, returning -EAGAIN\n"); return -EAGAIN; }#ifdef VIA_DEBUG { u8 r40,r41,r42,r43,r44,r48; pci_read_config_byte (card->pdev, 0x40, &r40); pci_read_config_byte (card->pdev, 0x41, &r41); pci_read_config_byte (card->pdev, 0x42, &r42); pci_read_config_byte (card->pdev, 0x43, &r43); pci_read_config_byte (card->pdev, 0x44, &r44); pci_read_config_byte (card->pdev, 0x48, &r48); DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n", r40,r41,r42,r43,r44,r48); DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", inb (card->baseaddr + 0x00), inb (card->baseaddr + 0x01), inb (card->baseaddr + 0x02), inl (card->baseaddr + 0x04), inl (card->baseaddr + 0x0C), inl (card->baseaddr + 0x80), inl (card->baseaddr + 0x84)); } if (!chan->is_active) printk (KERN_ERR "sleeping but not active\n");#endif DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_bufs)); interruptible_sleep_on (&chan->wait); if (signal_pending (current)) { DPRINTK ("EXIT, returning -ERESTARTSYS\n"); return -ERESTARTSYS; } }#ifdef VIA_DEBUG { u8 r40,r41,r42,r43,r44,r48; pci_read_config_byte (card->pdev, 0x40, &r40); pci_read_config_byte (card->pdev, 0x41, &r41); pci_read_config_byte (card->pdev, 0x42, &r42); pci_read_config_byte (card->pdev, 0x43, &r43); pci_read_config_byte (card->pdev, 0x44, &r44); pci_read_config_byte (card->pdev, 0x48, &r48); DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n", r40,r41,r42,r43,r44,r48); DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", inb (card->baseaddr + 0x00), inb (card->baseaddr + 0x01), inb (card->baseaddr + 0x02), inl (card->baseaddr + 0x04), inl (card->baseaddr + 0x0C), inl (card->baseaddr + 0x80), inl (card->baseaddr + 0x84)); DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_bufs)); }#endifout: DPRINTK ("EXIT, returning 0\n"); return 0;}/** * via_dsp_ioctl_space - get information about channel buffering * @card: Private info for specified board * @chan: pointer to channel-specific info * @arg: user buffer for returned information * * Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE. * * Locking: inside card->syscall_sem */static int via_dsp_ioctl_space (struct via_info *card, struct via_channel *chan, void *arg){ audio_buf_info info; info.fragstotal = VIA_DMA_BUFFERS; info.fragsize = VIA_DMA_BUF_SIZE; /* number of full fragments we can read/write without blocking */ info.fragments = atomic_read (&chan->n_bufs); if ((chan->slop_len > 0) && (info.fragments > 0)) info.fragments--; /* number of bytes that can be read or written immediately * without blocking. */ info.bytes = (info.fragments * VIA_DMA_BUF_SIZE); if (chan->slop_len > 0) info.bytes += VIA_DMA_BUF_SIZE - chan->slop_len; DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n", info.fragstotal, info.fragsize, info.fragments, info.bytes); return copy_to_user (arg, &info, sizeof (info));}/** * via_dsp_ioctl_ptr - get information about hardware buffer ptr * @card: Private info for specified board * @chan: pointer to channel-specific info * @arg: user buffer for returned information * * Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR. * * Locking: inside card->syscall_sem */static int via_dsp_ioctl_ptr (struct via_info *card, struct via_channel *chan, void *arg){ count_info info; spin_lock_irq (&card->lock); info.bytes = chan->bytes; info.blocks = chan->n_irqs; chan->n_irqs = 0; spin_unlock_irq (&card->lock); if (chan->is_active) { unsigned long extra; info.ptr = atomic_read (&chan->hw_ptr) * VIA_DMA_BUF_SIZE; extra = VIA_DMA_BUF_SIZE - inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT); info.ptr += extra; info.bytes += extra; } else { info.ptr = 0; } DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n", info.bytes, info.blocks, info.ptr); return copy_to_user (arg, &info, sizeof (info));}static int via_dsp_ioctl_trigger (struct via_channel *chan, int val){ int enable, do_something; if (chan->is_record) enable = (val & PCM_ENABLE_INPUT); else enable = (val & PCM_ENABLE_OUTPUT); if (!chan->is_enabled && enable) { do_something = 1; } else if (chan->is_enabled && !enable) { do_something = -1; } else { do_something = 0; } DPRINTK ("enable=%d, do_something=%d\n", enable, do_something); if (chan->is_active && do_something) return -EINVAL; if (do_something == 1) { chan->is_enabled = 1; via_chan_maybe_start (chan); DPRINTK ("Triggering input\n"); } else if (do_something == -1) { chan->is_enabled = 0; DPRINTK ("Setup input trigger\n"); } return 0;}static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int rc, rd=0, wr=0, val=0; struct via_info *card; struct via_channel *chan; int nonblock = (file->f_flags & O_NONBLOCK); assert (file != NULL); card = file->private_data; assert (card != NULL); if (file->f_mode & FMODE_WRITE) wr = 1; if (file->f_mode & FMODE_READ) rd = 1; rc = via_syscall_down (card, nonblock); if (rc) return rc; rc = -EINVAL; switch (cmd) { /* OSS API version. XXX unverified */ case OSS_GETVERSION: DPRINTK("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n"); rc = put_user (SOUND_VERSION, (int *)arg); break; /* list of supported PCM data formats */ case SNDCTL_DSP_GETFMTS: DPRINTK("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n"); rc = put_user (AFMT_U8 | AFMT_S16_LE, (int *)arg); break; /* query or set current channel's PCM data format */ case SNDCTL_DSP_SETFMT: if (get_user(val, (int *)arg)) { rc = -EFAULT; break; } DPRINTK("DSP_SETFMT, val==%d\n", val); if (val != AFMT_QUERY) { rc = 0; if (rc == 0 && rd) rc = via_chan_set_fmt (card, &card->ch_in, val); if (rc == 0 && wr) rc = via_chan_set_fmt (card, &card->ch_out, val); if (rc <= 0) { if (rc == 0) rc = -EINVAL; break; } val = rc; } else { if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) || (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT))) val = AFMT_S16_LE; else val = AFMT_U8; } DPRINTK("SETFMT EXIT, returning %d\n", val); rc = put_user (val, (int *)arg); break; /* query or set number of channels (1=mono, 2=stereo) */ case SNDCTL_DSP_CHANNELS: if (get_user(val, (int *)arg)) { rc = -EFAULT; break; } DPRINTK("DSP_CHANNELS, val==%d\n", val); if (val != 0) { rc = 0; if (rc == 0 && rd) rc = via_chan_set_stereo (card, &card->ch_in, val); if (rc == 0 && wr) rc = via_chan_set_stereo (card, &card->ch_out, val); if (rc <= 0) { if (rc == 0) rc = -EINVAL; break; } val = rc; } else { if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) || (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_STEREO))) val = 2; else val = 1; } DPRINTK("CHANNELS EXIT, returning %d\n", val); rc = put_user (val, (int *)arg); break; /* enable (val is not zero) or disable (val == 0) stereo */ case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) { rc = -EFAULT; break; } DPRINTK("DSP_STEREO, val==%d\n", val); rc = 0; if (rc == 0 && rd) rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1); if (rc == 0 && wr) rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1); if (rc <= 0) { if (rc == 0) rc = -EINVAL; break; } DPRINTK("STEREO EXIT, returning %d\n", val); rc = 0; break; /* query or set sampling rate */ case SNDCTL_DSP_SPEED: if (get_user(val, (int *)arg)) { rc = -EFAULT; break; } DPRINTK("DSP_SPEED, val==%d\n", val); if (val < 0) { rc = -EINVAL; break; } if (val > 0) { rc = 0; if (rc == 0 && rd) rc = via_chan_set_speed (card, &card->ch_in, val); if (rc == 0 && wr) rc = via_chan_set_speed (card, &card->ch_out, val); if (rc <= 0) { if (rc == 0) rc = -EINVAL; break; } val = rc; } else { if (rd) val = card->ch_in.rate; else if (wr) val = card->ch_out.rate; else val = 0; } DPRINTK("SPEED EXIT, returning %d\n", val); rc = put_user (val, (int *)arg); break; /* wait until all buffers have been played, and then stop device */ case SNDCTL_DSP_SYNC: DPRINTK ("DSP_SYNC\n"); if (wr) { DPRINTK("SYNC EXIT (after calling via_dsp_drain_playback)\n"); rc = via_dsp_drain_playback (card, &card->ch_out, nonblock); } break; /* stop recording/playback immediately */ case SNDCTL_DSP_RESET: DPRINTK ("DSP_RESET\n"); if (rd) { via_chan_clear (&card->ch_in); via_chan_pcm_fmt (&card->ch_in, 1); } if (wr) { via_chan_clear (&card->ch_out); via_chan_pcm_fmt (&card->ch_out, 1); } rc = 0; break; /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ case SNDCTL_DSP_GETCAPS: DPRINTK("DSP_GETCAPS\n"); rc = put_user(VIA_DSP_CAP, (int *)arg); break; /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ case SNDCTL_DSP_GETBLKSIZE: DPRINTK("DSP_GETBLKSIZE\n"); rc = put_user(VIA_DMA_BUF_SIZE, (int *)arg); break; /* obtain information about input buffering */ case SNDCTL_DSP_GETISPACE: DPRINTK("DSP_GETISPACE\n"); if (rd) rc = via_dsp_ioctl_space (card, &card->ch_in, (void*) arg); break; /* obtain information about output buffering */ case SNDCTL_DSP_GETOSPACE: DPRINTK("DSP_GETOSPACE\n"); if (wr) rc = via_dsp_ioctl_space (card, &card->ch_out, (void*) arg); break; /* obtain information about input hardware pointer */ case SNDCTL_DSP_GETIPTR: DPRINTK("DSP_GETIPTR\n"); if (rd) rc = via_dsp_ioctl_ptr (card, &card->ch_in, (void*) arg); break; /* obtain information about output hardware pointer */ case SNDCTL_DSP_GETOPTR: DPRINTK("DSP_GETOPTR\n"); if (wr) rc = via_dsp_ioctl_ptr (card, &card->ch_out, (void*) arg); break; /* return number of bytes remaining to be played by DMA engine */ case SNDCTL_DSP_GETODELAY: { DPRINTK("DSP_GETODELAY\n"); chan = &card->ch_out; if (!wr) break; val = VIA_DMA_BUFFERS - atomic_read (&chan->n_bufs); if (val > 0) { val *= VIA_DMA_BUF_SIZE; val -= VIA_DMA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -