📄 pcm_oss.c
字号:
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 *) 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 *) 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, (int *)arg); return res; } return put_user(res, (int *)arg) ? -EFAULT : 0; case SNDCTL_DSP_PROFILE: return 0; /* silently ignore */ default: snd_printd("pcm_oss: unknown command = 0x%x\n", cmd); } return -EINVAL;}static ssize_t snd_pcm_oss_read(struct file *file, char *buf, size_t count, loff_t *offset){ snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream; pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream == NULL) return -ENXIO; return snd_pcm_oss_read1(substream, buf, count);}static ssize_t snd_pcm_oss_write(struct file *file, const char *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 = 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) 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); 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_ready(substream);}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_ready(substream);}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 = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return 0); 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; spin_lock_irq(&runtime->lock); poll_wait(file, &runtime->sleep, wait); if (runtime->status->state != SNDRV_PCM_STATE_DRAINING && (runtime->status->state != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_playback_ready(psubstream))) mask |= POLLOUT | POLLWRNORM; spin_unlock_irq(&runtime->lock); } if (csubstream != NULL) { snd_pcm_runtime_t *runtime = csubstream->runtime; spin_lock_irq(&runtime->lock); poll_wait(file, &runtime->sleep, wait); if (runtime->status->state != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_capture_ready(csubstream)) mask |= POLLIN | POLLRDNORM; spin_unlock_irq(&runtime->lock); } 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; pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); switch ((area->vm_flags & (VM_READ | VM_WRITE))) { case VM_READ | VM_WRITE: substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream) break; /* Fall through */ case VM_READ: substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; break; case VM_WRITE: substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; break; default: return -EINVAL; } /* set VM_READ access as well to fix memset() routines that do reads before writes (to improve performance) */ area->vm_flags |= VM_READ; if (substream == NULL) return -ENXIO; runtime = substream->runtime; if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID)) return -EIO; if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED) runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; else return -EIO; if (runtime->oss.params) { if ((err = snd_pcm_oss_change_params(substream)) < 0) return err; } if (runtime->oss.plugin_first != NULL) return -EIO;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) if (area->vm_pgoff != 0)#else if (area->vm_offset != 0)#endif return -EINVAL; err = snd_pcm_mmap_data(substream, file, area); if (err < 0) return err; runtime->oss.mmap_bytes = area->vm_end - area->vm_start; /* In mmap mode we never stop */ runtime->stop_threshold = runtime->boundary; return 0;}/* * /proc interface */static void snd_pcm_oss_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data; snd_pcm_oss_setup_t *setup = pstr->oss.setup_list; down(&pstr->oss.setup_mutex); while (setup) { snd_iprintf(buffer, "%s %u %u%s%s%s%s\n", setup->task_name, setup->periods, setup->period_size, setup->disable ? " disable" : "", setup->direct ? " direct" : "", setup->block ? " block" : "", setup->nonblock ? " non-block" : ""); setup = setup->next; } up(&pstr->oss.setup_mutex);}static void snd_pcm_oss_proc_free_setup_list(snd_pcm_str_t * pstr){ unsigned int idx; snd_pcm_substream_t *substream; snd_pcm_oss_setup_t *setup, *setupn; for (idx = 0, substream = pstr->substream; idx < pstr->substream_count; idx++, substream = substream->next) substream->oss.setup = NULL; for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL; setup; setup = setupn) { setupn = setup->next; kfree(setup->task_name); kfree(setup); } pstr->oss.setup_list = NULL;}static void snd_pcm_oss_proc_write(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data; char line[512], str[32], task_name[32], *ptr; int idx1; snd_pcm_oss_setup_t *setup, *setup1, template; while (!snd_info_get_line(buffer, line, sizeof(line))) { down(&pstr->oss.setup_mutex); memset(&template, 0, sizeof(template)); ptr = snd_info_get_str(task_name, line, sizeof(task_name)); if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) { snd_pcm_oss_proc_free_setup_list(pstr); up(&pstr->oss.setup_mutex); continue; } for (setup = pstr->oss.setup_list; setup; setup = setup->next) { if (!strcmp(setup->task_name, task_name)) { template = *setup; break; } } ptr = snd_info_get_str(str, ptr, sizeof(str)); template.periods = simple_strtoul(str, NULL, 10); ptr = snd_info_get_str(str, ptr, sizeof(str)); template.period_size = simple_strtoul(str, NULL, 10); for (idx1 = 31; idx1 >= 0; idx1--) if (template.period_size & (1 << idx1)) break; for (idx1--; idx1 >= 0; idx1--) template.period_size &= ~(1 << idx1); do { ptr = snd_info_get_str(str, ptr, sizeof(str)); if (!strcmp(str, "disable")) { template.disable = 1; } else if (!strcmp(str, "direct")) { template.direct = 1; } else if (!strcmp(str, "block")) { template.block = 1; } else if (!strcmp(str, "non-block")) { template.nonblock = 1; } } while (*str); if (setup == NULL) { setup = (snd_pcm_oss_setup_t *) kmalloc(sizeof(snd_pcm_oss_setup_t), GFP_KERNEL); if (setup) { if (pstr->oss.setup_list == NULL) { pstr->oss.setup_list = setup; } else { for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next); setup1->next = setup; } template.task_name = snd_kmalloc_strdup(task_name, GFP_KERNEL); } else { buffer->error = -ENOMEM; } } if (setup) *setup = template; up(&pstr->oss.setup_mutex); }}static void snd_pcm_oss_proc_init(snd_pcm_t *pcm){ int stream; for (stream = 0; stream < 2; ++stream) { snd_info_entry_t *entry; snd_pcm_str_t *pstr = &pcm->streams[stream]; if (pstr->substream_count == 0) continue; if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; entry->c.text.read_size = 8192; entry->c.text.read = snd_pcm_oss_proc_read; entry->c.text.write_size = 8192; entry->c.text.write = snd_pcm_oss_proc_write; entry->private_data = pstr; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } pstr->oss.proc_entry = entry; }}static void snd_pcm_oss_proc_done(snd_pcm_t *pcm){ int stream; for (stream = 0; stream < 2; ++stream) { snd_pcm_str_t *pstr = &pcm->streams[stream]; if (pstr->oss.proc_entry) { snd_info_unregister(pstr->oss.proc_entry); pstr->oss.proc_entry = NULL; snd_pcm_oss_proc_free_setup_list(pstr); } }}/* * ENTRY functions */static struct file_operations snd_pcm_oss_f_reg ={#ifndef LINUX_2_2 owner: THIS_MODULE,#endif read: snd_pcm_oss_read, write: snd_pcm_oss_write, open: snd_pcm_oss_open, release: snd_pcm_oss_release, poll: snd_pcm_oss_poll, ioctl: snd_pcm_oss_ioctl, mmap: snd_pcm_oss_mmap,};static snd_minor_t snd_pcm_oss_reg ={ comment: "digital audio", f_ops: &snd_pcm_oss_f_reg,};static void register_oss_dsp(unsigned short native_minor, snd_pcm_t *pcm, int index){ char name[128]; sprintf(name, "dsp%i%i", pcm->card->number, pcm->device); if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, pcm->card, index, &snd_pcm_oss_reg, name) < 0) { snd_printk("unable to register OSS PCM device %i:%i\n", pcm->card->number, pcm->device); }}static int snd_pcm_oss_register_minor(unsigned short native_minor, snd_pcm_t * pcm){ pcm->oss.reg = 0; if (snd_dsp_map[pcm->card->number] == pcm->device) { char name[128]; int duplex; register_oss_dsp(native_minor, pcm, 0); duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 && pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count && !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)); sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : ""); snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number, name); pcm->oss.reg++; } if (snd_adsp_map[pcm->card->number] == pcm->device) { register_oss_dsp(native_minor, pcm, 1); pcm->oss.reg++; } if (pcm->oss.reg) snd_pcm_oss_proc_init(pcm); return 0;}static int snd_pcm_oss_unregister_minor(unsigned short native_minor, snd_pcm_t * pcm){ if (pcm->oss.reg) { if (snd_dsp_map[pcm->card->number] == pcm->device) { snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, pcm->card, 0); snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); } if (snd_adsp_map[pcm->card->number] == pcm->device) snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, pcm->card, 1); pcm->oss.reg = 0; snd_pcm_oss_proc_done(pcm); } return 0;}static snd_pcm_notify_t snd_pcm_oss_notify ={ n_register: snd_pcm_oss_register_minor, n_unregister: snd_pcm_oss_unregister_minor,};static int __init alsa_pcm_oss_init(void){ int i; int err; if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0) return err; /* check device map table */ for (i = 0; i < SNDRV_CARDS; i++) { if (snd_dsp_map[i] < 0 || snd_dsp_map[i] >= SNDRV_PCM_DEVICES) { snd_printk("invalid dsp_map[%d] = %d\n", i, snd_dsp_map[i]); snd_dsp_map[i] = 0; } if (snd_adsp_map[i] < 0 || snd_adsp_map[i] >= SNDRV_PCM_DEVICES) { snd_printk("invalid adsp_map[%d] = %d\n", i, snd_adsp_map[i]); snd_adsp_map[i] = 1; } } return 0;}static void __exit alsa_pcm_oss_exit(void){ snd_pcm_notify(&snd_pcm_oss_notify, 1);}module_init(alsa_pcm_oss_init)module_exit(alsa_pcm_oss_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -