📄 forte.c
字号:
if (!rd) return -EINVAL; spin_lock_irq (&chip->lock); if (chip->rec.active) cinfo.ptr = chip->rec.hwptr; else cinfo.ptr = 0; cinfo.bytes = chip->rec.bytes; cinfo.blocks = chip->rec.nr_irqs; chip->rec.nr_irqs = 0; spin_unlock_irq (&chip->lock); return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETOSPACE: if (!wr) return -EINVAL; spin_lock_irq (&chip->lock); abi.fragstotal = chip->play.frag_num; abi.fragsize = chip->play.frag_sz; if (chip->play.mapped) { abi.fragments = chip->play.frag_num - 2; abi.bytes = chip->play.buf_sz; } else { abi.fragments = chip->play.frag_num - chip->play.filled_frags; if (chip->play.residue) abi.fragments--; abi.bytes = abi.fragments * abi.fragsize + chip->play.residue; } spin_unlock_irq (&chip->lock); return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0; case SNDCTL_DSP_GETOPTR: if (!wr) return -EINVAL; spin_lock_irq (&chip->lock); if (chip->play.active) cinfo.ptr = chip->play.hwptr; else cinfo.ptr = 0; cinfo.bytes = chip->play.bytes; cinfo.blocks = chip->play.nr_irqs; chip->play.nr_irqs = 0; spin_unlock_irq (&chip->lock); return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETODELAY: if (!wr) return -EINVAL; spin_lock_irq (&chip->lock); if (!chip->play.active) { ival = 0; } else if (chip->play.mapped) { count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1; ival = chip->play.frag_sz - count; } else { ival = chip->play.filled_frags * chip->play.frag_sz; if (chip->play.residue) ival += chip->play.frag_sz - chip->play.residue; } spin_unlock_irq (&chip->lock); return put_user (ival, p); case SNDCTL_DSP_SETDUPLEX: DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__); return -EINVAL; case SNDCTL_DSP_GETTRIGGER: DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__); return put_user (chip->trigger, p); case SNDCTL_DSP_SETTRIGGER: if (get_user (ival, p)) return -EFAULT; DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival); if (wr) { spin_lock_irq (&chip->lock); if (ival & PCM_ENABLE_OUTPUT) forte_channel_start (&chip->play); else { chip->trigger = 1; forte_channel_prep (&chip->play); forte_channel_stop (&chip->play); } spin_unlock_irq (&chip->lock); } else if (rd) { spin_lock_irq (&chip->lock); if (ival & PCM_ENABLE_INPUT) forte_channel_start (&chip->rec); else { chip->trigger = 1; forte_channel_prep (&chip->rec); forte_channel_stop (&chip->rec); } spin_unlock_irq (&chip->lock); } return 0; case SOUND_PCM_READ_RATE: DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__); return put_user (chip->play.rate, p); case SOUND_PCM_READ_CHANNELS: DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__); return put_user (chip->play.stereo, p); case SOUND_PCM_READ_BITS: DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__); return put_user (chip->play.format, p); case SNDCTL_DSP_NONBLOCK: DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__); file->f_flags |= O_NONBLOCK; return 0; default: DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, argp); break; } return -EINVAL;}/** * forte_dsp_open: */static int forte_dsp_open (struct inode *inode, struct file *file){ struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */ if (file->f_flags & O_NONBLOCK) { if (down_trylock (&chip->open_sem)) { DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__); return -EAGAIN; } } else { if (down_interruptible (&chip->open_sem)) { DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__); return -ERESTARTSYS; } } file->private_data = forte; DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid); if (file->f_mode & FMODE_WRITE) forte_channel_init (forte, &forte->play); if (file->f_mode & FMODE_READ) forte_channel_init (forte, &forte->rec); return nonseekable_open(inode, file);}/** * forte_dsp_release: */static int forte_dsp_release (struct inode *inode, struct file *file){ struct forte_chip *chip = file->private_data; int ret = 0; DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip); if (file->f_mode & FMODE_WRITE) { forte_channel_drain (&chip->play); spin_lock_irq (&chip->lock); forte_channel_free (chip, &chip->play); spin_unlock_irq (&chip->lock); } if (file->f_mode & FMODE_READ) { while (chip->rec.filled_frags > 0) interruptible_sleep_on (&chip->rec.wait); spin_lock_irq (&chip->lock); forte_channel_stop (&chip->rec); forte_channel_free (chip, &chip->rec); spin_unlock_irq (&chip->lock); } up (&chip->open_sem); return ret;}/** * forte_dsp_poll: * */static unsigned int forte_dsp_poll (struct file *file, struct poll_table_struct *wait){ struct forte_chip *chip; struct forte_channel *channel; unsigned int mask = 0; chip = file->private_data; if (file->f_mode & FMODE_WRITE) { channel = &chip->play; if (channel->active) poll_wait (file, &channel->wait, wait); spin_lock_irq (&chip->lock); if (channel->frag_num - channel->filled_frags > 0) mask |= POLLOUT | POLLWRNORM; spin_unlock_irq (&chip->lock); } if (file->f_mode & FMODE_READ) { channel = &chip->rec; if (channel->active) poll_wait (file, &channel->wait, wait); spin_lock_irq (&chip->lock); if (channel->filled_frags > 0) mask |= POLLIN | POLLRDNORM; spin_unlock_irq (&chip->lock); } return mask;}/** * forte_dsp_mmap: */static intforte_dsp_mmap (struct file *file, struct vm_area_struct *vma){ struct forte_chip *chip; struct forte_channel *channel; unsigned long size; int ret; chip = file->private_data; DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff); spin_lock_irq (&chip->lock); if (vma->vm_flags & VM_WRITE && chip->play.active) { ret = -EBUSY; goto out; } if (vma->vm_flags & VM_READ && chip->rec.active) { ret = -EBUSY; goto out; } if (file->f_mode & FMODE_WRITE) channel = &chip->play; else if (file->f_mode & FMODE_READ) channel = &chip->rec; else { ret = -EINVAL; goto out; } forte_channel_prep (channel); channel->mapped = 1; if (vma->vm_pgoff != 0) { ret = -EINVAL; goto out; } size = vma->vm_end - vma->vm_start; if (size > channel->buf_pages * PAGE_SIZE) { DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__, size, channel->buf_sz); ret = -EINVAL; goto out; } if (remap_page_range (vma, vma->vm_start, virt_to_phys (channel->buf), size, vma->vm_page_prot)) { DPRINTK ("%s: remap el a no worko\n", __FUNCTION__); ret = -EAGAIN; goto out; } ret = 0; out: spin_unlock_irq (&chip->lock); return ret;}/** * forte_dsp_write: */static ssize_t forte_dsp_write (struct file *file, const char __user *buffer, size_t bytes, loff_t *ppos){ struct forte_chip *chip; struct forte_channel *channel; unsigned int i = bytes, sz = 0; unsigned long flags; if (!access_ok (VERIFY_READ, buffer, bytes)) return -EFAULT; chip = (struct forte_chip *) file->private_data; if (!chip) BUG(); channel = &chip->play; if (!channel) BUG(); spin_lock_irqsave (&chip->lock, flags); /* Set up buffers with the right fragment size */ forte_channel_prep (channel); while (i) { /* All fragment buffers in use -> wait */ if (channel->frag_num - channel->filled_frags == 0) { DECLARE_WAITQUEUE (wait, current); /* For trigger or non-blocking operation, get out */ if (chip->trigger || file->f_flags & O_NONBLOCK) { spin_unlock_irqrestore (&chip->lock, flags); return -EAGAIN; } /* Otherwise wait for buffers */ add_wait_queue (&channel->wait, &wait); for (;;) { spin_unlock_irqrestore (&chip->lock, flags); set_current_state (TASK_INTERRUPTIBLE); schedule(); spin_lock_irqsave (&chip->lock, flags); if (channel->frag_num - channel->filled_frags) break; } remove_wait_queue (&channel->wait, &wait); set_current_state (TASK_RUNNING); if (signal_pending (current)) { spin_unlock_irqrestore (&chip->lock, flags); return -ERESTARTSYS; } } if (channel->residue) sz = channel->residue; else if (i > channel->frag_sz) sz = channel->frag_sz; else sz = i; spin_unlock_irqrestore (&chip->lock, flags); if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz)) return -EFAULT; spin_lock_irqsave (&chip->lock, flags); /* Advance software pointer */ buffer += sz; channel->swptr += sz; channel->swptr %= channel->buf_sz; i -= sz; /* Only bump filled_frags if a full fragment has been written */ if (channel->swptr % channel->frag_sz == 0) { channel->filled_frags++; channel->residue = 0; } else channel->residue = channel->frag_sz - sz; /* If playback isn't active, start it */ if (channel->active == 0 && chip->trigger == 0) forte_channel_start (channel); } spin_unlock_irqrestore (&chip->lock, flags); return bytes - i;}/** * forte_dsp_read: */static ssize_t forte_dsp_read (struct file *file, char __user *buffer, size_t bytes, loff_t *ppos){ struct forte_chip *chip; struct forte_channel *channel; unsigned int i = bytes, sz; unsigned long flags; if (!access_ok (VERIFY_WRITE, buffer, bytes)) return -EFAULT; chip = (struct forte_chip *) file->private_data; if (!chip) BUG(); channel = &chip->rec; if (!channel) BUG(); spin_lock_irqsave (&chip->lock, flags); /* Set up buffers with the right fragment size */ forte_channel_prep (channel); /* Start recording */ if (!chip->trigger) forte_channel_start (channel); while (i) { /* No fragment buffers in use -> wait */ if (channel->filled_frags == 0) { DECLARE_WAITQUEUE (wait, current); /* For trigger mode operation, get out */ if (chip->trigger) { spin_unlock_irqrestore (&chip->lock, flags); return -EAGAIN; } add_wait_queue (&channel->wait, &wait); for (;;) { if (channel->active == 0) break; if (channel->filled_frags) break; spin_unlock_irqrestore (&chip->lock, flags); set_current_state (TASK_INTERRUPTIBLE); schedule(); spin_lock_irqsave (&chip->lock, flags); } set_current_state (TASK_RUNNING); remove_wait_queue (&channel->wait, &wait); } if (i > channel->frag_sz) sz = channel->frag_sz; else sz = i; spin_unlock_irqrestore (&chip->lock, flags); if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) { DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__); return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -