📄 pcm_oss.c
字号:
return err; } if ((err = psubstream->ops->open(psubstream)) < 0) { snd_pcm_oss_release_file(pcm_oss_file); return err; } psubstream->ffile = file; err = snd_pcm_hw_constraints_complete(psubstream); if (err < 0) { snd_printd("snd_pcm_hw_constraint_complete failed\n"); snd_pcm_oss_release_file(pcm_oss_file); return err; } snd_pcm_oss_init_substream(psubstream, psetup, minor); } if (csubstream != NULL) { csubstream->oss.file = pcm_oss_file; err = snd_pcm_hw_constraints_init(csubstream); if (err < 0) { snd_printd("snd_pcm_hw_constraint_init failed\n"); snd_pcm_oss_release_file(pcm_oss_file); return err; } if ((err = csubstream->ops->open(csubstream)) < 0) { snd_pcm_oss_release_file(pcm_oss_file); return err; } csubstream->ffile = file; err = snd_pcm_hw_constraints_complete(csubstream); if (err < 0) { snd_printd("snd_pcm_hw_constraint_complete failed\n"); snd_pcm_oss_release_file(pcm_oss_file); return err; } snd_pcm_oss_init_substream(csubstream, csetup, minor); } file->private_data = pcm_oss_file; *rpcm_oss_file = pcm_oss_file; return 0;}static int snd_task_name(struct task_struct *task, char *name, size_t size){ unsigned int idx; snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL); for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++) name[idx] = task->comm[idx]; name[idx] = '\0'; return 0;}static int snd_pcm_oss_open(struct inode *inode, struct file *file){ int minor = iminor(inode); int cardnum = SNDRV_MINOR_OSS_CARD(minor); int device; int err; char task_name[32]; snd_pcm_t *pcm; snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_oss_setup_t *psetup = NULL, *csetup = NULL; int nonblock; wait_queue_t wait; snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); device = SNDRV_MINOR_OSS_DEVICE(minor) == SNDRV_MINOR_OSS_PCM1 ? adsp_map[cardnum] : dsp_map[cardnum]; pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + device]; if (pcm == NULL) { err = -ENODEV; goto __error1; } err = snd_card_file_add(pcm->card, file); if (err < 0) goto __error1; if (!try_module_get(pcm->card->module)) { err = -EFAULT; goto __error2; } if (snd_task_name(current, task_name, sizeof(task_name)) < 0) { err = -EFAULT; goto __error; } if (file->f_mode & FMODE_WRITE) psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name); if (file->f_mode & FMODE_READ) csetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name); nonblock = !!(file->f_flags & O_NONBLOCK); if (psetup && !psetup->disable) { if (psetup->nonblock) nonblock = 1; else if (psetup->block) nonblock = 0; } else if (csetup && !csetup->disable) { if (csetup->nonblock) nonblock = 1; else if (csetup->block) nonblock = 0; } if (!nonblock) nonblock = nonblock_open; init_waitqueue_entry(&wait, current); add_wait_queue(&pcm->open_wait, &wait); down(&pcm->open_mutex); while (1) { err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file, minor, psetup, csetup); if (err >= 0) break; if (err == -EAGAIN) { if (nonblock) { err = -EBUSY; break; } } else break; set_current_state(TASK_INTERRUPTIBLE); up(&pcm->open_mutex); schedule(); down(&pcm->open_mutex); if (signal_pending(current)) { err = -ERESTARTSYS; break; } } remove_wait_queue(&pcm->open_wait, &wait); up(&pcm->open_mutex); if (err < 0) goto __error; return err; __error: module_put(pcm->card->module); __error2: snd_card_file_remove(pcm->card, file); __error1: return err;}static int snd_pcm_oss_release(struct inode *inode, struct file *file){ snd_pcm_t *pcm; snd_pcm_substream_t *substream; snd_pcm_oss_file_t *pcm_oss_file; pcm_oss_file = file->private_data; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; snd_assert(substream != NULL, return -ENXIO); pcm = substream->pcm; snd_pcm_oss_sync(pcm_oss_file); down(&pcm->open_mutex); snd_pcm_oss_release_file(pcm_oss_file); up(&pcm->open_mutex); wake_up(&pcm->open_wait); module_put(pcm->card->module); snd_card_file_remove(pcm->card, file); return 0;}static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ snd_pcm_oss_file_t *pcm_oss_file; int __user *p = (int __user *)arg; int res; pcm_oss_file = file->private_data; if (cmd == OSS_GETVERSION) return put_user(SNDRV_OSS_VERSION, p); if (cmd == OSS_ALSAEMULVER) return put_user(1, p);#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE)) if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */ snd_pcm_substream_t *substream; int idx; for (idx = 0; idx < 2; ++idx) { substream = pcm_oss_file->streams[idx]; if (substream != NULL) break; } snd_assert(substream != NULL, return -ENXIO); return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg); }#endif if (((cmd >> 8) & 0xff) != 'P') return -EINVAL;#ifdef OSS_DEBUG printk("pcm_oss: ioctl = 0x%x\n", cmd);#endif switch (cmd) { case SNDCTL_DSP_RESET: return snd_pcm_oss_reset(pcm_oss_file); case SNDCTL_DSP_SYNC: return snd_pcm_oss_sync(pcm_oss_file); case SNDCTL_DSP_SPEED: if (get_user(res, p)) return -EFAULT; if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) return res; return put_user(res, p); case SOUND_PCM_READ_RATE: res = snd_pcm_oss_get_rate(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_STEREO: if (get_user(res, p)) return -EFAULT; res = res > 0 ? 2 : 1; if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0) return res; return put_user(--res, p); case SNDCTL_DSP_GETBLKSIZE: res = snd_pcm_oss_get_block_size(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_SETFMT: if (get_user(res, p)) return -EFAULT; res = snd_pcm_oss_set_format(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_READ_BITS: res = snd_pcm_oss_get_format(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_CHANNELS: if (get_user(res, p)) return -EFAULT; res = snd_pcm_oss_set_channels(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_READ_CHANNELS: res = snd_pcm_oss_get_channels(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -EIO; case SNDCTL_DSP_POST: return snd_pcm_oss_post(pcm_oss_file); case SNDCTL_DSP_SUBDIVIDE: if (get_user(res, p)) return -EFAULT; res = snd_pcm_oss_set_subdivide(pcm_oss_file, res); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_SETFRAGMENT: if (get_user(res, p)) return -EFAULT; return snd_pcm_oss_set_fragment(pcm_oss_file, res); case SNDCTL_DSP_GETFMTS: res = snd_pcm_oss_get_formats(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: return snd_pcm_oss_get_space(pcm_oss_file, cmd == SNDCTL_DSP_GETISPACE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, (struct audio_buf_info __user *) arg); case SNDCTL_DSP_NONBLOCK: return snd_pcm_oss_nonblock(file); case SNDCTL_DSP_GETCAPS: res = snd_pcm_oss_get_caps(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_GETTRIGGER: res = snd_pcm_oss_get_trigger(pcm_oss_file); if (res < 0) return res; return put_user(res, p); case SNDCTL_DSP_SETTRIGGER: if (get_user(res, p)) return -EFAULT; return snd_pcm_oss_set_trigger(pcm_oss_file, res); case SNDCTL_DSP_GETIPTR: case SNDCTL_DSP_GETOPTR: return snd_pcm_oss_get_ptr(pcm_oss_file, cmd == SNDCTL_DSP_GETIPTR ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, (struct count_info __user *) arg); case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: return snd_pcm_oss_get_mapbuf(pcm_oss_file, cmd == SNDCTL_DSP_MAPINBUF ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, (struct buffmem_desc __user *) arg); case SNDCTL_DSP_SETSYNCRO: /* stop DMA now.. */ return 0; case SNDCTL_DSP_SETDUPLEX: if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX) return 0; return -EIO; case SNDCTL_DSP_GETODELAY: res = snd_pcm_oss_get_odelay(pcm_oss_file); if (res < 0) { /* it's for sure, some broken apps don't check for error codes */ put_user(0, p); return res; } return put_user(res, p); case SNDCTL_DSP_PROFILE: return 0; /* silently ignore */ default: snd_printd("pcm_oss: unknown command = 0x%x\n", cmd); } return -EINVAL;}#ifdef CONFIG_COMPAT/* all compatible */#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl#else#define snd_pcm_oss_ioctl_compat NULL#endifstatic ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset){ snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream; pcm_oss_file = file->private_data; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream == NULL) return -ENXIO;#ifndef OSS_DEBUG return snd_pcm_oss_read1(substream, buf, count);#else { ssize_t res = snd_pcm_oss_read1(substream, buf, count); printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res); return res; }#endif}static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset){ snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream; long result; pcm_oss_file = file->private_data; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) return -ENXIO; up(&file->f_dentry->d_inode->i_sem); result = snd_pcm_oss_write1(substream, buf, count); down(&file->f_dentry->d_inode->i_sem);#ifdef OSS_DEBUG printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);#endif return result;}static int snd_pcm_oss_playback_ready(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; if (atomic_read(&runtime->mmap_count)) return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;}static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; if (atomic_read(&runtime->mmap_count)) return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;}static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait){ snd_pcm_oss_file_t *pcm_oss_file; unsigned int mask; snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL; pcm_oss_file = file->private_data; psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; mask = 0; if (psubstream != NULL) { snd_pcm_runtime_t *runtime = psubstream->runtime; poll_wait(file, &runtime->sleep, wait); snd_pcm_stream_lock_irq(psubstream); if (runtime->status->state != SNDRV_PCM_STATE_DRAINING && (runtime->status->state != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_playback_ready(psubstream))) mask |= POLLOUT | POLLWRNORM; snd_pcm_stream_unlock_irq(psubstream); } if (csubstream != NULL) { snd_pcm_runtime_t *runtime = csubstream->runtime; enum sndrv_pcm_state ostate; poll_wait(file, &runtime->sleep, wait); snd_pcm_stream_lock_irq(csubstream); if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_capture_ready(csubstream)) mask |= POLLIN | POLLRDNORM; snd_pcm_stream_unlock_irq(csubstream); if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) { snd_pcm_oss_file_t ofile; memset(&ofile, 0, sizeof(ofile)); ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; runtime->oss.trigger = 0; snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT); } } return mask;}static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area){ snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream = NULL; snd_pcm_runtime_t *runtime; int err;#ifdef OSS_DEBUG printk("pcm_oss: mmap begin\n");#endif pcm_oss_file = file->private_data; switch ((area->vm_flags
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -