📄 pcm_oss.c
字号:
runtime->oss.subdivision = 1; /* disable SUBDIVIDE */#endif // printk("space: bytes = %i, periods = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.periods, info.fragstotal, info.fragsize); if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; return 0;}static int snd_pcm_oss_get_mapbuf(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct buffmem_desc * _info){ // it won't be probably implemented // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n"); return -EINVAL;}static snd_pcm_oss_setup_t *snd_pcm_oss_look_for_setup(snd_pcm_t *pcm, int stream, const char *task_name){ const char *ptr, *ptrl; snd_pcm_oss_setup_t *setup; down(&pcm->streams[stream].oss.setup_mutex); for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) { if (!strcmp(setup->task_name, task_name)) { up(&pcm->streams[stream].oss.setup_mutex); return setup; } } ptr = ptrl = task_name; while (*ptr) { if (*ptr == '/') ptrl = ptr + 1; ptr++; } if (ptrl == task_name) { goto __not_found; return NULL; } for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) { if (!strcmp(setup->task_name, ptrl)) { up(&pcm->streams[stream].oss.setup_mutex); return setup; } } __not_found: up(&pcm->streams[stream].oss.setup_mutex); return NULL;}static void snd_pcm_oss_init_substream(snd_pcm_substream_t *substream, snd_pcm_oss_setup_t *setup, int minor){ snd_pcm_runtime_t *runtime; substream->oss.oss = 1; substream->oss.setup = setup; runtime = substream->runtime; runtime->oss.params = 1; runtime->oss.trigger = 1; runtime->oss.rate = 8000; switch (SNDRV_MINOR_OSS_DEVICE(minor)) { case SNDRV_MINOR_OSS_PCM_8: runtime->oss.format = AFMT_U8; break; case SNDRV_MINOR_OSS_PCM_16: runtime->oss.format = AFMT_S16_LE; break; default: runtime->oss.format = AFMT_MU_LAW; } runtime->oss.channels = 1; runtime->oss.fragshift = 0; runtime->oss.maxfrags = 0; runtime->oss.subdivision = 0;}static void snd_pcm_oss_release_substream(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime; runtime = substream->runtime; if (runtime->oss.buffer) vfree(runtime->oss.buffer); snd_pcm_oss_plugin_clear(substream); substream->oss.file = NULL; substream->oss.oss = 0;}static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file){ int cidx; snd_assert(pcm_oss_file != NULL, return -ENXIO); for (cidx = 0; cidx < 2; ++cidx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[cidx]; snd_pcm_runtime_t *runtime; if (substream == NULL) continue; runtime = substream->runtime; spin_lock_irq(&runtime->lock); if (snd_pcm_running(substream)) snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); spin_unlock_irq(&runtime->lock); if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); substream->ops->close(substream); substream->ffile = NULL; snd_pcm_oss_release_substream(substream); snd_pcm_release_substream(substream); } snd_magic_kfree(pcm_oss_file); return 0;}static int snd_pcm_oss_open_file(struct file *file, snd_pcm_t *pcm, snd_pcm_oss_file_t **rpcm_oss_file, int minor, snd_pcm_oss_setup_t *psetup, snd_pcm_oss_setup_t *csetup){ int err = 0; snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL; unsigned int f_mode = file->f_mode; snd_assert(rpcm_oss_file != NULL, return -EINVAL); *rpcm_oss_file = NULL; pcm_oss_file = snd_magic_kcalloc(snd_pcm_oss_file_t, 0, GFP_KERNEL); if (pcm_oss_file == NULL) return -ENOMEM; if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) && (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) f_mode = FMODE_WRITE; if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) { if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK, &psubstream)) < 0) { snd_pcm_oss_release_file(pcm_oss_file); return err; } pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream; } if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) { if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE, &csubstream)) < 0) { snd_pcm_oss_release_file(pcm_oss_file); return err; } pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream; } if (psubstream == NULL && csubstream == NULL) { snd_pcm_oss_release_file(pcm_oss_file); return -EINVAL; } if (psubstream != NULL) { psubstream->oss.file = pcm_oss_file; err = snd_pcm_hw_constraints_init(psubstream); if (err < 0) { snd_printd("snd_pcm_hw_constraint_init failed\n"); snd_pcm_oss_release_file(pcm_oss_file); return err; } if ((err = psubstream->ops->open(psubstream)) < 0) { snd_pcm_oss_release_file(pcm_oss_file); return err; } 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; } psubstream->ffile = file; 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; } 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; } csubstream->ffile = file; 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_pcm_oss_open(struct inode *inode, struct file *file){ int minor = minor(inode->i_rdev); 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 ? snd_adsp_map[cardnum] : snd_dsp_map[cardnum];#ifdef LINUX_2_2 MOD_INC_USE_COUNT;#endif pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + device]; if (pcm == NULL) { err = -ENODEV; goto __error1; } if (!try_inc_mod_count(pcm->card->module)) { err = -EFAULT; goto __error1; } if (snd_task_name(current, task_name, sizeof(task_name)) < 0) { err = -EFAULT; goto __error1; } 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 (!nonblock) nonblock = snd_nonblock_open; } else if (csetup && !csetup->disable) { if (csetup->nonblock) nonblock = 1; else if (csetup->block) nonblock = 0; else if (!nonblock) nonblock = snd_nonblock_open; } init_waitqueue_entry(&wait, current); add_wait_queue(&pcm->open_wait, &wait); while (1) { down(&pcm->open_mutex); err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file, minor, psetup, csetup); if (err >= 0) break; up(&pcm->open_mutex); if (err == -EAGAIN) { if (nonblock) { err = -EBUSY; break; } } else break; set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { err = -ERESTARTSYS; break; } } set_current_state(TASK_RUNNING); remove_wait_queue(&pcm->open_wait, &wait); if (err < 0) goto __error; up(&pcm->open_mutex); return err; __error: dec_mod_count(pcm->card->module); __error1:#ifdef LINUX_2_2 MOD_DEC_USE_COUNT;#endif 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 = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); 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); dec_mod_count(pcm->card->module);#ifdef LINUX_2_2 MOD_DEC_USE_COUNT;#endif return 0;}static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ snd_pcm_oss_file_t *pcm_oss_file; int res; pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); if (cmd == OSS_GETVERSION) return put_user(SNDRV_OSS_VERSION, (int *)arg) ? -EFAULT : 0;#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; 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, (int *)arg)) return -EFAULT; if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SOUND_PCM_READ_RATE: res = snd_pcm_oss_get_rate(pcm_oss_file); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_STEREO: if (get_user(res, (int *)arg)) 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, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_GETBLKSIZE: res = snd_pcm_oss_get_block_size(pcm_oss_file); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_SETFMT: if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_format(pcm_oss_file, res); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SOUND_PCM_READ_BITS: res = snd_pcm_oss_get_format(pcm_oss_file); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_CHANNELS: if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_channels(pcm_oss_file, res); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SOUND_PCM_READ_CHANNELS: res = snd_pcm_oss_get_channels(pcm_oss_file); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -EIO; case SNDCTL_DSP_POST: /* to do */ return 0; case SNDCTL_DSP_SUBDIVIDE: if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_subdivide(pcm_oss_file, res); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_SETFRAGMENT: if (get_user(res, (int *)arg)) 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, (int *)arg) ? -EFAULT : 0; 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 *) 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, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_GETTRIGGER: res = snd_pcm_oss_get_trigger(pcm_oss_file); if (res < 0) return res; return put_user(res, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_SETTRIGGER: if (get_user(res, (int *)arg))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -