📄 forte.c
字号:
DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name, format, channel->format); return channel->format;}/** * forte_channel_stereo: * @channel: Channel to toggle * @stereo: 0 for Mono, 1 for Stereo * * Locking: Must be called with lock held. */static intforte_channel_stereo (struct forte_channel *channel, unsigned int stereo){ int ret; if (!channel || !channel->iobase) return -EINVAL; DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo); switch (stereo) { case 0: channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK); channel-> stereo = stereo; ret = stereo; break; case 1: channel->ctrl &= ~FORTE_CHANNELS_MASK; channel->ctrl |= FORTE_STEREO; channel-> stereo = stereo; ret = stereo; break; default: DPRINTK ("Unsupported channel format"); ret = -EINVAL; break; } return ret;}/** * forte_channel_buffer: * @channel: Channel whose buffer to set up * * Locking: Must be called with lock held. */static voidforte_channel_buffer (struct forte_channel *channel, int sz, int num){ unsigned int msecs, shift; /* Go away, I'm busy */ if (channel->filled_frags || channel->bytes) return; /* Fragment size must be a power of 2 */ shift = 0; sz++; while (sz >>= 1) shift++; channel->frag_sz = 1 << shift; /* Round fragment size to something reasonable */ if (channel->frag_sz < FORTE_MIN_FRAG_SIZE) channel->frag_sz = FORTE_MIN_FRAG_SIZE; if (channel->frag_sz > FORTE_MAX_FRAG_SIZE) channel->frag_sz = FORTE_MAX_FRAG_SIZE; /* Find fragment length in milliseconds */ msecs = channel->frag_sz / (channel->format == AFMT_S16_LE ? 2 : 1) / (channel->stereo ? 2 : 1) / (channel->rate / 1000); channel->frag_msecs = msecs; /* Pick a suitable number of fragments */ if (msecs * num < FORTE_MIN_BUF_MSECS) num = FORTE_MIN_BUF_MSECS / msecs; if (msecs * num > FORTE_MAX_BUF_MSECS) num = FORTE_MAX_BUF_MSECS / msecs; /* Fragment number must be a power of 2 */ shift = 0; while (num >>= 1) shift++; channel->frag_num = 1 << (shift + 1); /* Round fragment number to something reasonable */ if (channel->frag_num < FORTE_MIN_FRAGMENTS) channel->frag_num = FORTE_MIN_FRAGMENTS; if (channel->frag_num > FORTE_MAX_FRAGMENTS) channel->frag_num = FORTE_MAX_FRAGMENTS; channel->buf_sz = channel->frag_sz * channel->frag_num; DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n", __FUNCTION__, channel->name, channel->frag_sz, channel->frag_num, channel->buf_sz);}/** * forte_channel_prep: * @channel: Channel whose buffer to prepare * * Locking: Lock held. */static voidforte_channel_prep (struct forte_channel *channel){ struct page *page; int i; if (channel->buf) return; forte_channel_buffer (channel, channel->frag_sz, channel->frag_num); channel->buf_pages = channel->buf_sz >> PAGE_SHIFT; if (channel->buf_sz % PAGE_SIZE) channel->buf_pages++; DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n", __FUNCTION__, channel->name, channel->frag_sz, channel->frag_num, channel->buf_sz, channel->buf_pages); /* DMA buffer */ channel->buf = pci_alloc_consistent (forte->pci_dev, channel->buf_pages * PAGE_SIZE, &channel->buf_handle); if (!channel->buf || !channel->buf_handle) BUG(); page = virt_to_page (channel->buf); /* FIXME: can this go away ? */ for (i = 0 ; i < channel->buf_pages ; i++) SetPageReserved(page++); /* Prep buffer registers */ outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT); outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1); outl (channel->buf_handle + channel->frag_sz, channel->iobase + FORTE_PLY_BUF2); /* Reset hwptr */ channel->hwptr = channel->frag_sz; channel->next_buf = 1; DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name, channel->buf, channel->buf_handle);}/** * forte_channel_drain: * @chip: * @channel: * * Locking: Don't hold the lock. */static inline intforte_channel_drain (struct forte_channel *channel){ DECLARE_WAITQUEUE (wait, current); unsigned long flags; DPRINTK ("%s\n", __FUNCTION__); if (channel->mapped) { spin_lock_irqsave (&forte->lock, flags); forte_channel_stop (channel); spin_unlock_irqrestore (&forte->lock, flags); return 0; } spin_lock_irqsave (&forte->lock, flags); add_wait_queue (&channel->wait, &wait); for (;;) { if (channel->active == 0 || channel->filled_frags == 1) break; spin_unlock_irqrestore (&forte->lock, flags); __set_current_state (TASK_INTERRUPTIBLE); schedule(); spin_lock_irqsave (&forte->lock, flags); } forte_channel_stop (channel); forte_channel_reset (channel); set_current_state (TASK_RUNNING); remove_wait_queue (&channel->wait, &wait); spin_unlock_irqrestore (&forte->lock, flags); return 0;}/** * forte_channel_init: * @chip: Forte chip instance the channel hangs off * @channel: Channel to initialize * * Description: * Initializes a channel, sets defaults, and allocates * buffers. * * Locking: No lock held. */static intforte_channel_init (struct forte_chip *chip, struct forte_channel *channel){ DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase); spin_lock_irq (&chip->lock); memset (channel, 0x0, sizeof (*channel)); if (channel == &chip->play) { channel->name = "PCM_OUT"; channel->iobase = chip->iobase; DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__, (void *) channel->iobase); } else if (channel == &chip->rec) { channel->name = "PCM_IN"; channel->iobase = chip->iobase + FORTE_CAP_OFFSET; channel->record = 1; DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__, (void *) channel->iobase); } else BUG(); init_waitqueue_head (&channel->wait); /* Defaults: 48kHz, 16-bit, stereo */ channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL); forte_channel_reset (channel); forte_channel_stereo (channel, 1); forte_channel_format (channel, AFMT_S16_LE); forte_channel_rate (channel, 48000); channel->frag_sz = FORTE_DEF_FRAG_SIZE; channel->frag_num = FORTE_DEF_FRAGMENTS; chip->trigger = 0; spin_unlock_irq (&chip->lock); return 0;}/** * forte_channel_free: * @chip: Chip this channel hangs off * @channel: Channel to nuke * * Description: * Resets channel and frees buffers. * * Locking: Hold your horses. */static voidforte_channel_free (struct forte_chip *chip, struct forte_channel *channel){ DPRINTK ("%s: %s\n", __FUNCTION__, channel->name); if (!channel->buf_handle) return; pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE, channel->buf, channel->buf_handle); memset (channel, 0x0, sizeof (*channel));}/* DSP --------------------------------------------------------------------- *//** * forte_dsp_ioctl: */static intforte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int ival=0, ret, rval=0, rd, wr, count; struct forte_chip *chip; struct audio_buf_info abi; struct count_info cinfo; void __user *argp = (void __user *)arg; int __user *p = argp; chip = file->private_data; if (file->f_mode & FMODE_WRITE) wr = 1; else wr = 0; if (file->f_mode & FMODE_READ) rd = 1; else rd = 0; switch (cmd) { case OSS_GETVERSION: return put_user (SOUND_VERSION, p); case SNDCTL_DSP_GETCAPS: DPRINTK ("%s: GETCAPS\n", __FUNCTION__); ival = FORTE_CAPS; /* DUPLEX */ return put_user (ival, p); case SNDCTL_DSP_GETFMTS: DPRINTK ("%s: GETFMTS\n", __FUNCTION__); ival = FORTE_FMTS; /* U8, 16LE */ return put_user (ival, p); case SNDCTL_DSP_SETFMT: /* U8, 16LE */ DPRINTK ("%s: SETFMT\n", __FUNCTION__); if (get_user (ival, p)) return -EFAULT; spin_lock_irq (&chip->lock); if (rd) { forte_channel_stop (&chip->rec); rval = forte_channel_format (&chip->rec, ival); } if (wr) { forte_channel_stop (&chip->rec); rval = forte_channel_format (&chip->play, ival); } spin_unlock_irq (&chip->lock); return put_user (rval, p); case SNDCTL_DSP_STEREO: /* 0 - mono, 1 - stereo */ DPRINTK ("%s: STEREO\n", __FUNCTION__); if (get_user (ival, p)) return -EFAULT; spin_lock_irq (&chip->lock); if (rd) { forte_channel_stop (&chip->rec); rval = forte_channel_stereo (&chip->rec, ival); } if (wr) { forte_channel_stop (&chip->rec); rval = forte_channel_stereo (&chip->play, ival); } spin_unlock_irq (&chip->lock); return put_user (rval, p); case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */ DPRINTK ("%s: CHANNELS\n", __FUNCTION__); if (get_user (ival, p)) return -EFAULT; spin_lock_irq (&chip->lock); if (rd) { forte_channel_stop (&chip->rec); rval = forte_channel_stereo (&chip->rec, ival-1) + 1; } if (wr) { forte_channel_stop (&chip->play); rval = forte_channel_stereo (&chip->play, ival-1) + 1; } spin_unlock_irq (&chip->lock); return put_user (rval, p); case SNDCTL_DSP_SPEED: DPRINTK ("%s: SPEED\n", __FUNCTION__); if (get_user (ival, p)) return -EFAULT; spin_lock_irq (&chip->lock); if (rd) { forte_channel_stop (&chip->rec); rval = forte_channel_rate (&chip->rec, ival); } if (wr) { forte_channel_stop (&chip->play); rval = forte_channel_rate (&chip->play, ival); } spin_unlock_irq (&chip->lock); return put_user(rval, p); case SNDCTL_DSP_GETBLKSIZE: DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__); spin_lock_irq (&chip->lock); if (rd) ival = chip->rec.frag_sz; if (wr) ival = chip->play.frag_sz; spin_unlock_irq (&chip->lock); return put_user (ival, p); case SNDCTL_DSP_RESET: DPRINTK ("%s: RESET\n", __FUNCTION__); spin_lock_irq (&chip->lock); if (rd) forte_channel_reset (&chip->rec); if (wr) forte_channel_reset (&chip->play); spin_unlock_irq (&chip->lock); return 0; case SNDCTL_DSP_SYNC: DPRINTK ("%s: SYNC\n", __FUNCTION__); if (wr) ret = forte_channel_drain (&chip->play); return 0; case SNDCTL_DSP_POST: DPRINTK ("%s: POST\n", __FUNCTION__); if (wr) { spin_lock_irq (&chip->lock); if (chip->play.filled_frags) forte_channel_start (&chip->play); spin_unlock_irq (&chip->lock); } return 0; case SNDCTL_DSP_SETFRAGMENT: DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__); if (get_user (ival, p)) return -EFAULT; spin_lock_irq (&chip->lock); if (rd) { forte_channel_buffer (&chip->rec, ival & 0xffff, (ival >> 16) & 0xffff); ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz; } if (wr) { forte_channel_buffer (&chip->play, ival & 0xffff, (ival >> 16) & 0xffff); ival = (chip->play.frag_num << 16) +chip->play.frag_sz; } spin_unlock_irq (&chip->lock); return put_user (ival, p); case SNDCTL_DSP_GETISPACE: DPRINTK ("%s: GETISPACE\n", __FUNCTION__); if (!rd) return -EINVAL; spin_lock_irq (&chip->lock); abi.fragstotal = chip->rec.frag_num; abi.fragsize = chip->rec.frag_sz; if (chip->rec.mapped) { abi.fragments = chip->rec.frag_num - 2; abi.bytes = abi.fragments * abi.fragsize; } else { abi.fragments = chip->rec.filled_frags; abi.bytes = abi.fragments * abi.fragsize; } spin_unlock_irq (&chip->lock); return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0; case SNDCTL_DSP_GETIPTR: DPRINTK ("%s: GETIPTR\n", __FUNCTION__);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -