📄 i810_audio.c
字号:
spin_lock_irqsave(&state->card->lock, flags); i810_set_adc_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } } return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */#ifdef DEBUG printk("SNDCTL_DSP_STEREO\n");#endif if (dmabuf->enable & DAC_RUNNING) { stop_dac(state); } if (dmabuf->enable & ADC_RUNNING) { stop_adc(state); } return put_user(1, (int *)arg); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) return val; } if (file->f_mode & FMODE_READ) { if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) return val; }#ifdef DEBUG printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);#endif return put_user(dmabuf->userfragsize, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/#ifdef DEBUG printk("SNDCTL_DSP_GETFMTS\n");#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */#ifdef DEBUG printk("SNDCTL_DSP_SETFMT\n");#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_CHANNELS:#ifdef DEBUG printk("SNDCTL_DSP_CHANNELS\n");#endif if (get_user(val, (int *)arg)) return -EFAULT; if (val > 0) { if (dmabuf->enable & DAC_RUNNING) { stop_dac(state); } if (dmabuf->enable & ADC_RUNNING) { stop_adc(state); } } else { return put_user(state->card->channels, (int *)arg); } /* ICH and ICH0 only support 2 channels */ if ( state->card->pci_id == 0x2415 || state->card->pci_id == 0x2425 ) return put_user(2, (int *)arg); /* Multi-channel support was added with ICH2. Bits in */ /* Global Status and Global Control register are now */ /* used to indicate this. */ i_glob_cnt = inl(state->card->iobase + GLOB_CNT); /* Current # of channels enabled */ if ( i_glob_cnt & 0x0100000 ) ret = 4; else if ( i_glob_cnt & 0x0200000 ) ret = 6; else ret = 2; switch ( val ) { case 2: /* 2 channels is always supported */ outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff)); /* Do we need to change mixer settings???? */ break; case 4: /* Supported on some chipsets, better check first */ if ( state->card->channels >= 4 ) { outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000)); /* Do we need to change mixer settings??? */ } else { val = ret; } break; case 6: /* Supported on some chipsets, better check first */ if ( state->card->channels >= 6 ) { outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000)); /* Do we need to change mixer settings??? */ } else { val = ret; } break; default: /* nothing else is ever supported by the chipset */ val = ret; break; } return put_user(val, (int *)arg); case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ /* we update the swptr to the end of the last sg segment then return */#ifdef DEBUG printk("SNDCTL_DSP_POST\n");#endif if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING)) return 0; if((dmabuf->swptr % dmabuf->fragsize) != 0) { val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize); dmabuf->swptr += val; dmabuf->count += val; } return 0; case SNDCTL_DSP_SUBDIVIDE: if (dmabuf->subdivision) return -EINVAL; if (get_user(val, (int *)arg)) return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL;#ifdef DEBUG printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);#endif dmabuf->subdivision = val; dmabuf->ready = 0; return 0; case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) return -EFAULT; dmabuf->ossfragsize = 1<<(val & 0xffff); dmabuf->ossmaxfrags = (val >> 16) & 0xffff; if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags) return -EINVAL; /* * Bound the frag size into our allowed range of 256 - 4096 */ if (dmabuf->ossfragsize < 256) dmabuf->ossfragsize = 256; else if (dmabuf->ossfragsize > 4096) dmabuf->ossfragsize = 4096; /* * The numfrags could be something reasonable, or it could * be 0xffff meaning "Give me as much as possible". So, * we check the numfrags * fragsize doesn't exceed our * 64k buffer limit, nor is it less than our 8k minimum. * If it fails either one of these checks, then adjust the * number of fragments, not the size of them. It's OK if * our number of fragments doesn't equal 32 or anything * like our hardware based number now since we are using * a different frag count for the hardware. Before we get * into this though, bound the maxfrags to avoid overflow * issues. A reasonable bound would be 64k / 256 since our * maximum buffer size is 64k and our minimum frag size is * 256. On the other end, our minimum buffer size is 8k and * our maximum frag size is 4k, so the lower bound should * be 2. */ if(dmabuf->ossmaxfrags > 256) dmabuf->ossmaxfrags = 256; else if (dmabuf->ossmaxfrags < 2) dmabuf->ossmaxfrags = 2; val = dmabuf->ossfragsize * dmabuf->ossmaxfrags; while (val < 8192) { val <<= 1; dmabuf->ossmaxfrags <<= 1; } while (val > 65536) { val >>= 1; dmabuf->ossmaxfrags >>= 1; } dmabuf->ready = 0;#ifdef DEBUG printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, dmabuf->ossfragsize, dmabuf->ossmaxfrags);#endif return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); abinfo.fragsize = dmabuf->userfragsize; abinfo.fragstotal = dmabuf->userfrags; if (dmabuf->mapped) abinfo.bytes = dmabuf->dmasize; else abinfo.bytes = i810_get_free_write_space(state); abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP) printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes, abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);#endif return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); val = i810_get_free_write_space(state); cinfo.bytes = dmabuf->total_bytes; cinfo.ptr = dmabuf->hwptr; cinfo.blocks = val/dmabuf->userfragsize; if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { dmabuf->count += val; dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; __i810_update_lvi(state, 0); } spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP) printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, cinfo.blocks, cinfo.ptr, dmabuf->count);#endif return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); abinfo.bytes = i810_get_available_read_data(state); abinfo.fragsize = dmabuf->userfragsize; abinfo.fragstotal = dmabuf->userfrags; abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP) printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes, abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);#endif return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); val = i810_get_available_read_data(state); cinfo.bytes = dmabuf->total_bytes; cinfo.blocks = val/dmabuf->userfragsize; cinfo.ptr = dmabuf->hwptr; if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) { dmabuf->count -= val; dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; __i810_update_lvi(state, 1); } spin_unlock_irqrestore(&state->card->lock, flags);#if defined(DEBUG) || defined(DEBUG_MMAP) printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, cinfo.blocks, cinfo.ptr, dmabuf->count);#endif return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_NONBLOCK:#ifdef DEBUG printk("SNDCTL_DSP_NONBLOCK\n");#endif file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETCAPS:#ifdef DEBUG printk("SNDCTL_DSP_GETCAPS\n");#endif return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, (int *)arg); case SNDCTL_DSP_GETTRIGGER: val = 0;#ifdef DEBUG printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);#endif return put_user(dmabuf->trigger, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) return -EFAULT;#if defined(DEBUG) || defined(DEBUG_MMAP) printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);#endif if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { stop_adc(state); } if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) { stop_dac(state); } dmabuf->trigger = val; if(val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) { if (!dmabuf->write_channel) { dmabuf->ready = 0; dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); if (!dmabuf->write_channel) return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; if (dmabuf->mapped) { spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); dmabuf->count = 0; dmabuf->swptr = dmabuf->hwptr; dmabuf->count = i810_get_free_write_space(state); dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; __i810_update_lvi(state, 0); spin_unlock_irqrestore(&state->card->lock, flags); } else start_dac(state); } if(val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) { if (!dmabuf->read_channel) { dmabuf->ready = 0; dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); if (!dmabuf->read_channel) return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; if (dmabuf->mapped) { spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); dmabuf->swptr = dmabuf->hwptr; dmabuf->count = 0; spin_unlock_irqrestore(&state->card->lock, flags); } i810_update_lvi(state, 1); start_adc(state); } return 0; case SNDCTL_DSP_SETDUPLEX:#ifdef DEBUG printk("SNDCTL_DSP_SETDUPLEX\n");#endif return -EINVAL; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags);#ifdef DEBUG printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);#endif return put_user(val, (int *)arg); case SOUND_PCM_READ_RATE:#ifdef DEBUG printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);#endif return put_user(dmabuf->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS:#ifdef DEBUG printk("SOUND_PCM_READ_CHANNELS\n");#endif return put_user(2, (int *)arg); case SOUND_PCM_READ_BITS:#ifdef DEBUG printk("SOUND_PCM_READ_BITS\n");#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */#ifdef DEBUG printk("SNDCTL_DSP_SETSPDIF\n");#endif if (get_user(val, (int *)arg)) return -EFAULT; /* Check to make sure the codec supports S/PDIF transmitter */ if((state->card->ac97_features & 4)) { /* mask out the transmitter speed bits so the user can't set them */ val &= ~0x3000; /* Add the current transmitter speed bits to the passed value */ ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL); val |= (ret & 0x3000); i810_ac97_set(codec, AC97_SPDIF_CONTROL, val); if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) { printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val); return -EFAULT; } }#ifdef DEBUG else printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");#endif return put_user(val, (int *)arg); case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */#ifdef DEBUG printk("SNDCTL_DSP_GETSPDIF\n");#endif if (get_user(val, (int *)arg)) return -EFAULT; /* Check to make sure the codec supports S/PDIF transmitter */ if(!(state->card->ac97_features & 4)) {#ifdef DEBUG printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");#endif val = 0; } else { val = i810_ac97_get(codec, AC97_SPDIF_CONTROL); } //return put_user((val & 0xcfff), (int *)arg); return put_user(val, (int *)arg); case SNDCTL_DSP_GETCHANNELMASK:#ifdef DEBUG printk("SNDCTL_DSP_GETCHANNELMASK\n");#endif if (get_user(val, (int *)arg)) return -EFAULT; /* Based on AC'97 DAC support, not ICH hardware */ val = DSP_BIND_FRONT; if ( state->card->ac97_features & 0x0004 ) v
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -