📄 cs4231_lib.c
字号:
if (chip->mode & CS4231_MODE_PLAY) snd_pcm_period_elapsed(chip->playback_substream); if (chip->mode & CS4231_MODE_RECORD) { snd_cs4231_overrange(chip); snd_pcm_period_elapsed(chip->capture_substream); } } } else { if (status & CS4231_PLAYBACK_IRQ) snd_pcm_period_elapsed(chip->playback_substream); if (status & CS4231_RECORD_IRQ) { snd_cs4231_overrange(chip); snd_pcm_period_elapsed(chip->capture_substream); } } spin_lock(&chip->reg_lock); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); spin_unlock(&chip->reg_lock);}static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) return 0; ptr = chip->p_dma_size - snd_dma_residue(chip->dma1); return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) return 0; ptr = chip->c_dma_size - snd_dma_residue(chip->dma2); return bytes_to_frames(substream->runtime, ptr);}/* */static int snd_cs4231_probe(cs4231_t *chip){ unsigned long flags; int i, id, rev; unsigned char *ptr; unsigned int hw;#if 0 snd_cs4231_debug(chip);#endif id = 0; for (i = 0; i < 50; i++) { mb(); if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) udelay(2000); else { spin_lock_irqsave(&chip->reg_lock, flags); snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f; spin_unlock_irqrestore(&chip->reg_lock, flags); if (id == 0x0a) break; /* this is valid value */ } } snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id); if (id != 0x0a) return -ENODEV; /* no valid device found */ if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) { rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7; snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev); if (rev == 0x80) { chip->hardware = CS4231_HW_CS4231; } else if (rev == 0xa0) { chip->hardware = CS4231_HW_CS4231A; } else if (rev == 0xa2) { chip->hardware = CS4231_HW_CS4232; } else if (rev == 0xb2) { chip->hardware = CS4231_HW_CS4232A; } else if (rev == 0x83) { chip->hardware = CS4231_HW_CS4236; } else if (rev == 0x03) { chip->hardware = CS4231_HW_CS4236B; } else { snd_printk("unknown CS chip with version 0x%x\n", rev); return -ENODEV; /* unknown CS4231 chip? */ } } spin_lock_irqsave(&chip->reg_lock, flags); inb(CS4231P(chip, STATUS)); /* clear any pendings IRQ */ outb(0, CS4231P(chip, STATUS)); mb(); spin_unlock_irqrestore(&chip->reg_lock, flags); chip->image[CS4231_MISC_INFO] = CS4231_MODE2; switch (chip->hardware) { case CS4231_HW_INTERWAVE: chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3; break; case CS4231_HW_CS4235: case CS4231_HW_CS4236B: case CS4231_HW_CS4237B: case CS4231_HW_CS4238B: case CS4231_HW_CS4239: if (hw == CS4231_HW_DETECT3) chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3; else chip->hardware = CS4231_HW_CS4236; break; } chip->image[CS4231_IFACE_CTRL] = (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | (chip->single_dma ? CS4231_SINGLE_DMA : 0); chip->image[CS4231_ALT_FEATURE_1] = 0x80; chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; ptr = (unsigned char *) &chip->image; snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->reg_lock, flags); for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */ snd_cs4231_out(chip, i, *ptr++); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_cs4231_mce_up(chip); snd_cs4231_mce_down(chip); mdelay(2); /* ok.. try check hardware version for CS4236+ chips */ if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) { if (chip->hardware == CS4231_HW_CS4236B) { rev = snd_cs4236_ext_in(chip, CS4236_VERSION); snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff); id = snd_cs4236_ext_in(chip, CS4236_VERSION); snd_cs4236_ext_out(chip, CS4236_VERSION, rev); snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id); if ((id & 0x1f) == 0x1d) { /* CS4235 */ chip->hardware = CS4231_HW_CS4235; switch (id >> 5) { case 4: case 5: case 6: break; default: snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id); } } else if ((id & 0x1f) == 0x0b) { /* CS4236/B */ switch (id >> 5) { case 4: case 5: case 6: case 7: chip->hardware = CS4231_HW_CS4236B; break; default: snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id); } } else if ((id & 0x1f) == 0x08) { /* CS4237B */ chip->hardware = CS4231_HW_CS4237B; switch (id >> 5) { case 4: case 5: case 6: case 7: break; default: snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id); } } else if ((id & 0x1f) == 0x09) { /* CS4238B */ chip->hardware = CS4231_HW_CS4238B; switch (id >> 5) { case 5: case 6: case 7: break; default: snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id); } } else if ((id & 0x1f) == 0x1e) { /* CS4239 */ chip->hardware = CS4231_HW_CS4239; switch (id >> 5) { case 4: case 5: case 6: break; default: snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id); } } else { snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id); } } } return 0; /* all things are ok.. */}/* */static snd_pcm_hardware_t snd_cs4231_playback ={ info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), formats: (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), rates: SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, rate_min: 5510, rate_max: 48000, channels_min: 1, channels_max: 2, buffer_bytes_max: (128*1024), period_bytes_min: 64, period_bytes_max: (128*1024), periods_min: 1, periods_max: 1024, fifo_size: 0,};static snd_pcm_hardware_t snd_cs4231_capture ={ info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), formats: (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), rates: SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, rate_min: 5510, rate_max: 48000, channels_min: 1, channels_max: 2, buffer_bytes_max: (128*1024), period_bytes_min: 64, period_bytes_max: (128*1024), periods_min: 1, periods_max: 1024, fifo_size: 0,};/* */static int snd_cs4231_playback_open(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; runtime->hw = snd_cs4231_playback; /* hardware bug in InterWave chipset */ if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3) runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW; /* hardware limitation of cheap chips */ if (chip->hardware == CS4231_HW_CS4235 || chip->hardware == CS4231_HW_CS4239) runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max); if (chip->claim_dma) { if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0) return err; } if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) { if (chip->release_dma) chip->release_dma(chip, chip->dma_private_data, chip->dma1); snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } chip->playback_substream = substream; snd_pcm_set_sync(substream); chip->rate_constraint(runtime); return 0;}static int snd_cs4231_capture_open(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; runtime->hw = snd_cs4231_capture; /* hardware limitation of cheap chips */ if (chip->hardware == CS4231_HW_CS4235 || chip->hardware == CS4231_HW_CS4239) runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; if (chip->claim_dma) { if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0) return err; } snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max); if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) { if (chip->release_dma) chip->release_dma(chip, chip->dma_private_data, chip->dma2); snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } chip->capture_substream = substream; snd_pcm_set_sync(substream); chip->rate_constraint(runtime); return 0;}static int snd_cs4231_playback_close(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); chip->playback_substream = NULL; snd_cs4231_close(chip, CS4231_MODE_PLAY); return 0;}static int snd_cs4231_capture_close(snd_pcm_substream_t * substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); chip->capture_substream = NULL; snd_cs4231_close(chip, CS4231_MODE_RECORD); return 0;}#ifdef CONFIG_PMstatic void snd_cs4231_suspend(cs4231_t *chip){ int reg; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) chip->image[reg] = snd_cs4231_in(chip, reg); spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_cs4231_resume(cs4231_t *chip){ int reg; unsigned long flags; int timeout; snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) { switch (reg) { case CS4231_VERSION: break; default: snd_cs4231_out(chip, reg, chip->image[reg]); break; } } spin_unlock_irqrestore(&chip->reg_lock, flags);#if 0 snd_cs4231_mce_down(chip);#else /* The following is a workaround to avoid freeze after resume on TP600E. This is the first half of copy of snd_cs4231_mce_down(), but doesn't include rescheduling. -- iwai */ spin_lock_irqsave(&chip->reg_lock, flags); snd_cs4231_busy_wait(chip); chip->mce_bit &= ~CS4231_MCE; timeout = inb(CS4231P(chip, REGSEL)); outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); if (timeout == 0x80) snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port); if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) { spin_unlock_irqrestore(&chip->reg_lock, flags); return; } snd_cs4231_busy_wait(chip); spin_unlock_irqrestore(&chip->reg_lock, flags);#endif}static int snd_cs4231_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data){ cs4231_t *chip = snd_magic_cast(cs4231_t, dev->data, return 0); switch (rqst) { case PM_SUSPEND: if (chip->suspend) (*chip->suspend)(chip); break; case PM_RESUME: if (chip->resume) (*chip->resume)(chip); break; } return 0;}#endif /* CONFIG_PM */static int snd_cs4231_free(cs4231_t *chip){ if (chip->res_port) { release_resource(chip->res_port); kfree_nocheck(chip->res_port); } if (chip->res_cport) { release_resource(chip->res_cport); kfree_nocheck(chip->res_cport); } if (chip->irq >= 0) { disable_irq(chip->irq); if (!(chip->hwshare & CS4231_HWSHARE_IRQ)) free_irq(chip->irq, (void *) chip); } if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) { snd_dma_disable(chip->dma1); free_dma(chip->dma1); } if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) { snd_dma_disable(chip->dma2); free_dma(chip->dma2); }#ifdef CONFIG_PM if (chip->pm_dev) pm_unregister(chip->pm_dev);#endif if (chip->timer) snd_device_free(chip->card, chip->timer); snd_magic_kfree(chip); return 0;}static int snd_cs4231_dev_free(snd_device_t *device){ cs4231_t *chip = snd_magic_cast(cs4231_t, device->device_data, return -ENXIO); return snd_cs4231_free(chip); }const char *snd_cs4231_chip_id(cs4231_t *chip){ switch (chip->hardware) { case CS4231_HW_CS4231: return "CS4231"; case CS4231_HW_CS4231A: return "CS4231A"; case CS4231_HW_CS4232: return "CS4232"; case CS4231_HW_CS4232A: return "CS4232A"; case CS4231_HW_CS4235: return "CS4235"; case CS4231_HW_CS4236B: return "CS4236B"; case CS4231_HW_CS4237B: return "CS4237B"; case CS4231_HW_CS4238B: return "CS4238B";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -