📄 azt3328.c
字号:
/* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */ /* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */ if (channels == 2) val |= SOUNDFORMAT_FLAG_2CHANNELS; if (format_width == 16) val |= SOUNDFORMAT_FLAG_16BIT; spin_lock_irqsave(&chip->reg_lock, flags); /* set bitrate/format */ snd_azf3328_codec_outw(chip, reg, val); /* changing the bitrate/format settings switches off the * audio output with an annoying click in case of 8/16bit format change * (maybe shutting down DAC/ADC?), thus immediately * do some tweaking to reenable it and get rid of the clicking * (FIXME: yes, it works, but what exactly am I doing here?? :) * FIXME: does this have some side effects for full-duplex * or other dramatic side effects? */ if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2 | SOMETHING_ALMOST_ALWAYS_SET | DMA_EPILOGUE_SOMETHING | DMA_SOMETHING_ELSE ); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave();}static voidsnd_azf3328_setdmaa(struct snd_azf3328 *chip, long unsigned int addr, unsigned int count, unsigned int size, int do_recording){ unsigned long flags, portbase; unsigned int is_running; snd_azf3328_dbgcallenter(); if (do_recording) { /* access capture registers, i.e. skip playback reg section */ portbase = chip->codec_port + 0x20; is_running = chip->is_recording; } else { /* access the playback register section */ portbase = chip->codec_port + 0x00; is_running = chip->is_playing; } /* AZF3328 uses a two buffer pointer DMA playback approach */ if (!is_running) { unsigned long addr_area2; unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ count_areas = size/2; addr_area2 = addr+count_areas; count_areas--; /* max. index */ snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); /* build combined I/O buffer length word */ count_tmp = count_areas; count_areas |= (count_tmp << 16); spin_lock_irqsave(&chip->reg_lock, flags); outl(addr, portbase + IDX_IO_PLAY_DMA_START_1); outl(addr_area2, portbase + IDX_IO_PLAY_DMA_START_2); outl(count_areas, portbase + IDX_IO_PLAY_DMA_LEN_1); spin_unlock_irqrestore(&chip->reg_lock, flags); } snd_azf3328_dbgcallleave();}static intsnd_azf3328_playback_prepare(struct snd_pcm_substream *substream){#if 0 struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream);#endif snd_azf3328_dbgcallenter();#if 0 snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0);#endif snd_azf3328_dbgcallleave(); return 0;}static intsnd_azf3328_capture_prepare(struct snd_pcm_substream *substream){#if 0 struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream);#endif snd_azf3328_dbgcallenter();#if 0 snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1);#endif snd_azf3328_dbgcallleave(); return 0;}static intsnd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd){ struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int result = 0; unsigned int status1; snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_azf3328_dbgplay("START PLAYBACK\n"); /* mute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); spin_lock(&chip->reg_lock); /* stop playback */ status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); /* FIXME: clear interrupts or what??? */ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), 0); spin_lock(&chip->reg_lock);#ifdef WIN9X /* FIXME: enable playback/recording??? */ status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); /* start playback again */ /* FIXME: what is this value (0x0010)??? */ status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);#else /* NT4 */ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, 0x0000); snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, DMA_PLAY_SOMETHING1); snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2); snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, DMA_RESUME | SOMETHING_ALMOST_ALWAYS_SET | DMA_EPILOGUE_SOMETHING | DMA_SOMETHING_ELSE);#endif spin_unlock(&chip->reg_lock); /* now unmute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); chip->is_playing = 1; snd_azf3328_dbgplay("STARTED PLAYBACK\n"); break; case SNDRV_PCM_TRIGGER_RESUME: snd_azf3328_dbgplay("RESUME PLAYBACK\n"); /* resume playback if we were active */ if (chip->is_playing) snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); break; case SNDRV_PCM_TRIGGER_STOP: snd_azf3328_dbgplay("STOP PLAYBACK\n"); /* mute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); spin_lock(&chip->reg_lock); /* stop playback */ status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); /* hmm, is this really required? we're resetting the same bit * immediately thereafter... */ status1 |= DMA_PLAY_SOMETHING1; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); status1 &= ~DMA_PLAY_SOMETHING1; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); spin_unlock(&chip->reg_lock); /* now unmute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); chip->is_playing = 0; snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); break; case SNDRV_PCM_TRIGGER_SUSPEND: snd_azf3328_dbgplay("SUSPEND PLAYBACK\n"); /* make sure playback is stopped */ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); break; default: printk(KERN_ERR "FIXME: unknown trigger mode!\n"); return -EINVAL; } snd_azf3328_dbgcallleave(); return result;}/* this is just analogous to playback; I'm not quite sure whether recording * should actually be triggered like that */static intsnd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd){ struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int result = 0; unsigned int status1; snd_azf3328_dbgcalls("snd_azf3328_capture_trigger cmd %d\n", cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_azf3328_dbgplay("START CAPTURE\n"); snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); spin_lock(&chip->reg_lock); /* stop recording */ status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); /* FIXME: clear interrupts or what??? */ snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), 1); spin_lock(&chip->reg_lock);#ifdef WIN9X /* FIXME: enable playback/recording??? */ status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); /* start capture again */ /* FIXME: what is this value (0x0010)??? */ status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);#else snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, 0x0000); snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, DMA_PLAY_SOMETHING1); snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2); snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, DMA_RESUME | SOMETHING_ALMOST_ALWAYS_SET | DMA_EPILOGUE_SOMETHING | DMA_SOMETHING_ELSE);#endif spin_unlock(&chip->reg_lock); chip->is_recording = 1; snd_azf3328_dbgplay("STARTED CAPTURE\n"); break; case SNDRV_PCM_TRIGGER_RESUME: snd_azf3328_dbgplay("RESUME CAPTURE\n"); /* resume recording if we were active */ if (chip->is_recording) snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); break; case SNDRV_PCM_TRIGGER_STOP: snd_azf3328_dbgplay("STOP CAPTURE\n"); spin_lock(&chip->reg_lock); /* stop recording */ status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); status1 |= DMA_PLAY_SOMETHING1; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); status1 &= ~DMA_PLAY_SOMETHING1; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); spin_unlock(&chip->reg_lock); chip->is_recording = 0; snd_azf3328_dbgplay("STOPPED CAPTURE\n"); break; case SNDRV_PCM_TRIGGER_SUSPEND: snd_azf3328_dbgplay("SUSPEND CAPTURE\n"); /* make sure recording is stopped */ snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); break; default: printk(KERN_ERR "FIXME: unknown trigger mode!\n"); return -EINVAL; } snd_azf3328_dbgcallleave(); return result;}static snd_pcm_uframes_tsnd_azf3328_playback_pointer(struct snd_pcm_substream *substream){ struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); unsigned long bufptr, result; snd_pcm_uframes_t frmres;#ifdef QUERY_HARDWARE bufptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_START_1);#else bufptr = substream->runtime->dma_addr;#endif result = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); /* calculate offset */ result -= bufptr; frmres = bytes_to_frames( substream->runtime, result); snd_azf3328_dbgplay("PLAY @ 0x%8lx, frames %8ld\n", result, frmres); return frmres;}static snd_pcm_uframes_tsnd_azf3328_capture_pointer(struct snd_pcm_substream *substream){ struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); unsigned long bufptr, result; snd_pcm_uframes_t frmres;#ifdef QUERY_HARDWARE bufptr = inl(chip->codec_port+IDX_IO_REC_DMA_START_1);#else bufptr = substream->runtime->dma_addr;#endif result = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); /* calculate offset */ result -= bufptr; frmres = bytes_to_frames( substream->runtime, result); snd_azf3328_dbgplay("REC @ 0x%8lx, frames %8ld\n", result, frmres); return frmres;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -