📄 audio.c
字号:
return put_user(k, (int *)arg); case SOUND_MIXER_READ_RECSRC: if (drv->ops->get_input_port) i = drv->ops->get_input_port(drv); /* only one should ever be selected */ if (i & AUDIO_CD) j = SOUND_MASK_CD; if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE; if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC; return put_user(j, (int *)arg); case SOUND_MIXER_WRITE_RECSRC: if (!drv->ops->set_input_port) return -EINVAL; if (get_user(k, (int *)arg)) return -EFAULT; /* only one should ever be selected */ if (k & SOUND_MASK_CD) j = AUDIO_CD; if (k & SOUND_MASK_LINE) j = AUDIO_LINE_IN; if (k & SOUND_MASK_MIC) j = AUDIO_MICROPHONE; oprintk(("setting inport to %d\n", j)); i = drv->ops->set_input_port(drv, j); return put_user(i, (int *)arg); case SOUND_MIXER_READ_RECMASK: if (drv->ops->get_input_ports) i = drv->ops->get_input_ports(drv); /* what do we support? */ if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; if (i & AUDIO_CD) j |= SOUND_MASK_CD; return put_user(j, (int *)arg); case SOUND_MIXER_READ_CAPS: /* mixer capabilities */ i = SOUND_CAP_EXCL_INPUT; return put_user(i, (int *)arg); case SOUND_MIXER_READ_DEVMASK: /* all supported devices */ if (drv->ops->get_input_ports) i = drv->ops->get_input_ports(drv); /* what do we support? */ if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; if (i & AUDIO_CD) j |= SOUND_MASK_CD; if (drv->ops->get_output_ports) i = drv->ops->get_output_ports(drv); if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER; if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE1; if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE2; j |= SOUND_MASK_VOLUME; case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */ j |= SOUND_MASK_PCM|SOUND_MASK_RECLEV; if (cmd == SOUND_MIXER_READ_STEREODEVS) j &= ~(MONO_DEVICES); return put_user(j, (int *)arg); default: return -EINVAL; };}/* AUDIO_SETINFO uses these to set values if possible. */static __inline__ int __sparcaudio_if_set_do(struct sparcaudio_driver *drv, int (*set_function)(struct sparcaudio_driver *, int), int (*get_function)(struct sparcaudio_driver *), unsigned int value){ if (set_function && Modify(value)) return (int) set_function(drv, value); else if (get_function) return (int) get_function(drv); else return 0;}static __inline__ int __sparcaudio_if_setc_do(struct sparcaudio_driver *drv, int (*set_function)(struct sparcaudio_driver *, int), int (*get_function)(struct sparcaudio_driver *), unsigned char value){ if (set_function && Modifyc(value)) return (char) set_function(drv, (int)value); else if (get_function) return (char) get_function(drv); else return 0;}/* I_FLUSH, I_{G,S}ETSIG, I_NREAD provided for SunOS compatibility * * I must admit I'm quite ashamed of the state of the ioctl handling, * but I do have several optimizations which I'm planning. -- DJB */static int sparcaudio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ int retval = 0, i, j, k; int minor = MINOR(inode->i_rdev); struct audio_info ainfo; audio_buf_info binfo; count_info cinfo; struct sparcaudio_driver *drv = drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)]; switch (minor & 0xf) { case SPARCAUDIO_MIXER_MINOR: return sparcaudio_mixer_ioctl(inode, file, cmd, (unsigned int *)arg); case SPARCAUDIO_DSP16_MINOR: case SPARCAUDIO_DSP_MINOR: case SPARCAUDIO_AUDIO_MINOR: case SPARCAUDIO_AUDIOCTL_MINOR: /* According to the OSS prog int, you can mixer ioctl /dev/dsp */ if (_IOC_TYPE(cmd) == 'M') return sparcaudio_mixer_ioctl(inode, file, cmd, (unsigned int *)arg); switch (cmd) { case I_GETSIG: case I_GETSIG_SOLARIS: j = (int) lis_get_elist_ent(drv->sd_siglist,current->pid); put_user(j, (int *)arg); retval = drv->input_count; break; case I_SETSIG: case I_SETSIG_SOLARIS: if ((minor & 0xf) == SPARCAUDIO_AUDIOCTL_MINOR) { if (!arg) { if (lis_del_from_elist(&(drv->sd_siglist), current->pid,S_ALL)) { retval = -EINVAL; } else if (!drv->sd_siglist) { drv->sd_sigflags=0; } } else if (lis_add_to_elist(&(drv->sd_siglist), current->pid, (short)arg)) { retval = -EAGAIN; } else { ((drv->sd_sigflags) |= (arg)); } } break; case I_NREAD: case I_NREAD_SOLARIS: /* According to the Solaris man page, this copies out * the size of the first streams buffer and returns * the number of streams messages on the read queue as * as its retval. (streamio(7I)) This should work. */ j = (drv->input_count > 0) ? drv->input_buffer_size : 0; put_user(j, (int *)arg); retval = drv->input_count; break; /* A poor substitute until we do true resizable buffers. */ case SNDCTL_DSP_GETISPACE: binfo.fragstotal = drv->num_input_buffers; binfo.fragments = drv->num_input_buffers - (drv->input_count + drv->recording_count); binfo.fragsize = drv->input_buffer_size; binfo.bytes = binfo.fragments*binfo.fragsize; retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo)); if (retval) break; copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo)); break; case SNDCTL_DSP_GETOSPACE: binfo.fragstotal = drv->num_output_buffers; binfo.fragments = drv->num_output_buffers - (drv->output_count + drv->playing_count + (drv->output_offset ? 1 : 0)); binfo.fragsize = drv->output_buffer_size; binfo.bytes = binfo.fragments*binfo.fragsize + (drv->output_buffer_size - drv->output_offset); retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo)); if (retval) break; copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo)); break; case SNDCTL_DSP_GETIPTR: case SNDCTL_DSP_GETOPTR: /* int bytes (number of bytes read/written since last) * int blocks (number of frags read/wrote since last call) * int ptr (current position of dma in buffer) */ retval = 0; cinfo.bytes = 0; cinfo.ptr = 0; cinfo.blocks = 0; cinfo.bytes += cinfo.ptr; retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(cinfo)); if (retval) break; copy_to_user(&((char *)arg)[0], (char *)&cinfo, sizeof(cinfo)); break; case SNDCTL_DSP_SETFRAGMENT: /* XXX Small hack to get ESD/Enlightenment to work. --DaveM */ retval = 0; break; case SNDCTL_DSP_SUBDIVIDE: /* I don't understand what I need to do yet. */ retval = -EINVAL; break; case SNDCTL_DSP_SETTRIGGER: /* This may not be 100% correct */ if ((arg & PCM_ENABLE_INPUT) && drv->ops->get_input_pause && drv->ops->set_input_pause) { if (drv->ops->get_input_pause(drv)) drv->ops->set_input_pause(drv, 0); } else { if (!drv->ops->get_input_pause(drv)) drv->ops->set_input_pause(drv, 1); } if ((arg & PCM_ENABLE_OUTPUT) && drv->ops->get_output_pause && drv->ops->set_output_pause) { if (drv->ops->get_output_pause(drv)) drv->ops->set_output_pause(drv, 0); } else { if (!drv->ops->get_output_pause(drv)) drv->ops->set_output_pause(drv, 1); } break; case SNDCTL_DSP_GETTRIGGER: j = 0; if (drv->ops->get_input_pause) { if (drv->ops->get_input_pause(drv)) j = PCM_ENABLE_INPUT; } if (drv->ops->get_output_pause) { if (drv->ops->get_output_pause(drv)) j |= PCM_ENABLE_OUTPUT; } put_user(j, (int *)arg); break; case SNDCTL_DSP_GETBLKSIZE: j = drv->input_buffer_size; put_user(j, (int *)arg); break; case SNDCTL_DSP_SPEED: if ((!drv->ops->set_output_rate) && (!drv->ops->set_input_rate)) { retval = -EINVAL; break; } get_user(i, (int *)arg) tprintk(("setting speed to %d\n", i)); drv->ops->set_input_rate(drv, i); drv->ops->set_output_rate(drv, i); j = drv->ops->get_output_rate(drv); put_user(j, (int *)arg); break; case SNDCTL_DSP_GETCAPS: /* All Sparc audio hardware is full duplex. * 4231 supports DMA pointer reading, 7930 is byte at a time. * Pause functionality emulates trigger */ j = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER | DSP_CAP_REALTIME; put_user(j, (int *)arg); break; case SNDCTL_DSP_GETFMTS: if (drv->ops->get_formats) { j = drv->ops->get_formats(drv); put_user(j, (int *)arg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -