📄 ad1848_lib.c
字号:
/* ok. now enable and ack CODEC IRQ */ spin_lock_irqsave(&chip->reg_lock, flags); outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ chip->image[AD1848_PIN_CTRL] |= AD1848_IRQ_ENABLE; snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]); spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = mode; up(&chip->open_mutex); return 0;}static void snd_ad1848_close(ad1848_t *chip){ unsigned long flags; down(&chip->open_mutex); if (!chip->mode) { up(&chip->open_mutex); return; } /* disable IRQ */ spin_lock_irqsave(&chip->reg_lock, flags); outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ chip->image[AD1848_PIN_CTRL] &= ~AD1848_IRQ_ENABLE; snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]); spin_unlock_irqrestore(&chip->reg_lock, flags); /* now disable capture & playback */ snd_ad1848_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO | AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO); snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_ad1848_mce_down(chip); /* clear IRQ again */ spin_lock_irqsave(&chip->reg_lock, flags); outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = 0; up(&chip->open_mutex);}/* * ok.. exported functions.. */static int snd_ad1848_playback_trigger(snd_pcm_substream_t * substream, int cmd){ ad1848_t *chip = snd_pcm_substream_chip(substream); return snd_ad1848_trigger(chip, AD1848_PLAYBACK_ENABLE, SNDRV_PCM_STREAM_PLAYBACK, cmd);}static int snd_ad1848_capture_trigger(snd_pcm_substream_t * substream, int cmd){ ad1848_t *chip = snd_pcm_substream_chip(substream); return snd_ad1848_trigger(chip, AD1848_CAPTURE_ENABLE, SNDRV_PCM_STREAM_CAPTURE, cmd);}static int snd_ad1848_playback_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ad1848_t *chip = snd_pcm_substream_chip(substream); unsigned long flags; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; snd_ad1848_calibrate_mute(chip, 1); snd_ad1848_set_data_format(chip, hw_params); snd_ad1848_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_ad1848_mce_down(chip); snd_ad1848_calibrate_mute(chip, 0); return 0;}static int snd_ad1848_playback_hw_free(snd_pcm_substream_t * substream){ return snd_pcm_lib_free_pages(substream);}static int snd_ad1848_playback_prepare(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma_size = size; chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO); snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1; spin_lock_irqsave(&chip->reg_lock, flags); snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count); snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8)); spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static int snd_ad1848_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ad1848_t *chip = snd_pcm_substream_chip(substream); unsigned long flags; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; snd_ad1848_calibrate_mute(chip, 1); snd_ad1848_set_data_format(chip, hw_params); snd_ad1848_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_ad1848_mce_down(chip); snd_ad1848_calibrate_mute(chip, 0); return 0;}static int snd_ad1848_capture_hw_free(snd_pcm_substream_t * substream){ return snd_pcm_lib_free_pages(substream);}static int snd_ad1848_capture_prepare(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma_size = size; chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO); snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1; spin_lock_irqsave(&chip->reg_lock, flags); snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count); snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8)); spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs){ ad1848_t *chip = dev_id; if ((chip->mode & AD1848_MODE_PLAY) && chip->playback_substream && (chip->mode & AD1848_MODE_RUNNING)) snd_pcm_period_elapsed(chip->playback_substream); if ((chip->mode & AD1848_MODE_CAPTURE) && chip->capture_substream && (chip->mode & AD1848_MODE_RUNNING)) snd_pcm_period_elapsed(chip->capture_substream); outb(0, AD1848P(chip, STATUS)); /* clear global interrupt bit */ return IRQ_HANDLED;}static snd_pcm_uframes_t snd_ad1848_playback_pointer(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_PLAYBACK_ENABLE)) return 0; ptr = snd_dma_pointer(chip->dma, chip->dma_size); return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_ad1848_capture_pointer(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_CAPTURE_ENABLE)) return 0; ptr = snd_dma_pointer(chip->dma, chip->dma_size); return bytes_to_frames(substream->runtime, ptr);}/* */static void snd_ad1848_thinkpad_twiddle(ad1848_t *chip, int on) { int tmp; if (!chip->thinkpad_flag) return; outb(0x1c, AD1848_THINKPAD_CTL_PORT1); tmp = inb(AD1848_THINKPAD_CTL_PORT2); if (on) /* turn it on */ tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT; else /* turn it off */ tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT; outb(tmp, AD1848_THINKPAD_CTL_PORT2);}#ifdef CONFIG_PMstatic int snd_ad1848_suspend(snd_card_t *card, unsigned int state){ ad1848_t *chip = card->pm_private_data; snd_pcm_suspend_all(chip->pcm); /* FIXME: save registers? */ if (chip->thinkpad_flag) snd_ad1848_thinkpad_twiddle(chip, 0); return 0;}static int snd_ad1848_resume(snd_card_t *card, unsigned int state){ ad1848_t *chip = card->pm_private_data; if (chip->thinkpad_flag) snd_ad1848_thinkpad_twiddle(chip, 1); /* FIXME: restore registers? */ return 0;}#endif /* CONFIG_PM */static int snd_ad1848_probe(ad1848_t * chip){ unsigned long flags; int i, id, rev, ad1847; unsigned char *ptr;#if 0 snd_ad1848_debug(chip);#endif id = ad1847 = 0; for (i = 0; i < 1000; i++) { mb(); if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) udelay(500); else { spin_lock_irqsave(&chip->reg_lock, flags); snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa); snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45); rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT); if (rev == 0x65) { spin_unlock_irqrestore(&chip->reg_lock, flags); id = 1; ad1847 = 1; break; } if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) { spin_unlock_irqrestore(&chip->reg_lock, flags); id = 1; break; } spin_unlock_irqrestore(&chip->reg_lock, flags); } } if (id != 1) return -ENODEV; /* no valid device found */ if (chip->hardware == AD1848_HW_DETECT) { if (ad1847) { chip->hardware = AD1848_HW_AD1847; } else { chip->hardware = AD1848_HW_AD1848; rev = snd_ad1848_in(chip, AD1848_MISC_INFO); if (rev & 0x80) { chip->hardware = AD1848_HW_CS4248; } else if ((rev & 0x0f) == 0x0a) { snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40); for (i = 0; i < 16; ++i) { if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) { chip->hardware = AD1848_HW_CMI8330; break; } } snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); } } } spin_lock_irqsave(&chip->reg_lock, flags); inb(AD1848P(chip, STATUS)); /* clear any pendings IRQ */ outb(0, AD1848P(chip, STATUS)); mb(); spin_unlock_irqrestore(&chip->reg_lock, flags); chip->image[AD1848_MISC_INFO] = 0x00; chip->image[AD1848_IFACE_CTRL] = (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA; ptr = (unsigned char *) &chip->image; snd_ad1848_mce_down(chip); spin_lock_irqsave(&chip->reg_lock, flags); for (i = 0; i < 16; i++) /* ok.. fill all AD1848 registers */ snd_ad1848_out(chip, i, *ptr++); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_ad1848_mce_up(chip); snd_ad1848_mce_down(chip); return 0; /* all things are ok.. */}/* */static snd_pcm_hardware_t snd_ad1848_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE), .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_ad1848_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE), .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_ad1848_playback_open(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = snd_ad1848_open(chip, AD1848_MODE_PLAY)) < 0) return err; chip->playback_substream = substream; runtime->hw = snd_ad1848_playback; snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max); snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); return 0;}static int snd_ad1848_capture_open(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = snd_ad1848_open(chip, AD1848_MODE_CAPTURE)) < 0) return err; chip->capture_substream = substream; runtime->hw = snd_ad1848_capture; snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max); snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); return 0;}static int snd_ad1848_playback_close(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); chip->mode &= ~AD1848_MODE_PLAY; chip->playback_substream = NULL; snd_ad1848_close(chip); return 0;}static int snd_ad1848_capture_close(snd_pcm_substream_t * substream){ ad1848_t *chip = snd_pcm_substream_chip(substream); chip->mode &= ~AD1848_MODE_CAPTURE; chip->capture_substream = NULL; snd_ad1848_close(chip); return 0;}static int snd_ad1848_free(ad1848_t *chip){ if (chip->res_port) { release_resource(chip->res_port); kfree_nocheck(chip->res_port); } if (chip->irq >= 0) free_irq(chip->irq, (void *) chip);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -