📄 opti92x-ad1848.c
字号:
if (!(chip->mode & OPTi93X_MODE_OPEN)) { outb(0x00, OPTi93X_PORT(chip, STATUS)); snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE); chip->mode = mode; } else chip->mode |= mode; spin_unlock_irqrestore(&chip->lock, flags); return 0;}static void snd_opti93x_close(opti93x_t *chip, unsigned int mode){ unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->mode &= ~mode; if (chip->mode & OPTi93X_MODE_OPEN) { spin_unlock_irqrestore(&chip->lock, flags); return; } snd_opti93x_mute(chip, 1); outb(0, OPTi93X_PORT(chip, STATUS)); snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, ~OPTi93X_IRQ_ENABLE); snd_opti93x_mce_up(chip); snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00); snd_opti93x_mce_down(chip); chip->mode = 0; snd_opti93x_mute(chip, 0); spin_unlock_irqrestore(&chip->lock, flags);}static int snd_opti93x_trigger(snd_pcm_substream_t *substream, unsigned char what, int cmd){ opti93x_t *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; struct list_head *pos; snd_pcm_substream_t *s; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if (s == chip->playback_substream) { what |= OPTi93X_PLAYBACK_ENABLE; snd_pcm_trigger_done(s, substream); } else if (s == chip->capture_substream) { what |= OPTi93X_CAPTURE_ENABLE; snd_pcm_trigger_done(s, substream); } } spin_lock(&chip->lock); if (cmd == SNDRV_PCM_TRIGGER_START) { snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); if (what & OPTi93X_CAPTURE_ENABLE) udelay(50); } else snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00); spin_unlock(&chip->lock); break; } default: return -EINVAL; } return 0;}static int snd_opti93x_playback_trigger(snd_pcm_substream_t *substream, int cmd){ return snd_opti93x_trigger(substream, OPTi93X_PLAYBACK_ENABLE, cmd);}static int snd_opti93x_capture_trigger(snd_pcm_substream_t * substream, int cmd){ return snd_opti93x_trigger(substream, OPTi93X_CAPTURE_ENABLE, cmd);}static int snd_opti93x_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_opti93x_hw_free(snd_pcm_substream_t * substream){ snd_pcm_lib_free_pages(substream); return 0;}static int snd_opti93x_playback_prepare(snd_pcm_substream_t * substream){ opti93x_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; unsigned char format; unsigned int count = snd_pcm_lib_period_bytes(substream); unsigned int size = snd_pcm_lib_buffer_bytes(substream); spin_lock_irqsave(&chip->lock, flags); chip->p_dma_size = size; snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO, ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO)); snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); format = snd_opti93x_get_freq(runtime->rate); format |= snd_opti93x_get_format(chip, runtime->format, runtime->channels); snd_opti93x_playback_format(chip, format); format = chip->image[OPTi93X_PLAY_FORMAT]; count = snd_opti93x_get_count(format, count) - 1; snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count); snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_opti93x_capture_prepare(snd_pcm_substream_t *substream){ opti93x_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; unsigned char format; unsigned int count = snd_pcm_lib_period_bytes(substream); unsigned int size = snd_pcm_lib_buffer_bytes(substream); spin_lock_irqsave(&chip->lock, flags); chip->c_dma_size = size; snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); format = snd_opti93x_get_freq(runtime->rate); format |= snd_opti93x_get_format(chip, runtime->format, runtime->channels); snd_opti93x_capture_format(chip, format); format = chip->image[OPTi93X_CAPT_FORMAT]; count = snd_opti93x_get_count(format, count) - 1; snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count); snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static snd_pcm_uframes_t snd_opti93x_playback_pointer(snd_pcm_substream_t *substream){ opti93x_t *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE)) return 0; ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_opti93x_capture_pointer(snd_pcm_substream_t *substream){ opti93x_t *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE)) return 0; ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); return bytes_to_frames(substream->runtime, ptr);}static void snd_opti93x_overrange(opti93x_t *chip){ unsigned long flags; spin_lock_irqsave(&chip->lock, flags); if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02)) chip->capture_substream->runtime->overrange++; spin_unlock_irqrestore(&chip->lock, flags);}static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs){ opti93x_t *codec = dev_id; unsigned char status; status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11)); if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) snd_pcm_period_elapsed(codec->playback_substream); if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { snd_opti93x_overrange(codec); snd_pcm_period_elapsed(codec->capture_substream); } outb(0x00, OPTi93X_PORT(codec, STATUS)); return IRQ_HANDLED;}static snd_pcm_hardware_t snd_opti93x_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 = 5512, .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_opti93x_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_8000_48000, .rate_min = 5512, .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_opti93x_playback_open(snd_pcm_substream_t *substream){ int error; opti93x_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0) return error; snd_pcm_set_sync(substream); chip->playback_substream = substream; runtime->hw = snd_opti93x_playback; snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); return error;}static int snd_opti93x_capture_open(snd_pcm_substream_t *substream){ int error; opti93x_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0) return error; runtime->hw = snd_opti93x_capture; snd_pcm_set_sync(substream); chip->capture_substream = substream; snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); return error;}static int snd_opti93x_playback_close(snd_pcm_substream_t *substream){ opti93x_t *chip = snd_pcm_substream_chip(substream); chip->playback_substream = NULL; snd_opti93x_close(chip, OPTi93X_MODE_PLAY); return 0;}static int snd_opti93x_capture_close(snd_pcm_substream_t *substream){ opti93x_t *chip = snd_pcm_substream_chip(substream); chip->capture_substream = NULL; snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE); return 0;}static void snd_opti93x_init(opti93x_t *chip){ unsigned long flags; int i; spin_lock_irqsave(&chip->lock, flags); snd_opti93x_mce_up(chip); for (i = 0; i < 32; i++) snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]); snd_opti93x_mce_down(chip); spin_unlock_irqrestore(&chip->lock, flags);}static int snd_opti93x_probe(opti93x_t *chip){ unsigned long flags; unsigned char val; spin_lock_irqsave(&chip->lock, flags); val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f; spin_unlock_irqrestore(&chip->lock, flags); return (val == 0x0a) ? 0 : -ENODEV;}static int snd_opti93x_free(opti93x_t *chip){ release_and_free_resource(chip->res_port); if (chip->dma1 >= 0) { disable_dma(chip->dma1); free_dma(chip->dma1); } if (chip->dma2 >= 0) { disable_dma(chip->dma2); free_dma(chip->dma2); } if (chip->irq >= 0) { free_irq(chip->irq, chip); } kfree(chip); return 0;}static int snd_opti93x_dev_free(snd_device_t *device){ opti93x_t *chip = device->device_data; return snd_opti93x_free(chip);}static const char *snd_opti93x_chip_id(opti93x_t *codec){ switch (codec->hardware) { case OPTi9XX_HW_82C930: return "82C930"; case OPTi9XX_HW_82C931: return "82C931"; case OPTi9XX_HW_82C933: return "82C933"; default: return "???"; }}static int snd_opti93x_create(snd_card_t *card, opti9xx_t *chip, int dma1, int dma2, opti93x_t **rcodec){ static snd_device_ops_t ops = { .dev_free = snd_opti93x_dev_free, }; int error; opti93x_t *codec; *rcodec = NULL; codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; codec->irq = -1; codec->dma1 = -1; codec->dma2 = -1; if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) { snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4); snd_opti93x_free(codec); return -EBUSY; } if (request_dma(dma1, "OPTI93x - 1")) { snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1); snd_opti93x_free(codec); return -EBUSY; } codec->dma1 = chip->dma1; if (request_dma(dma2, "OPTI93x - 2")) { snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2); snd_opti93x_free(codec); return -EBUSY; } codec->dma2 = chip->dma2; if (request_irq(chip->irq, snd_opti93x_interrupt, SA_INTERRUPT, DRIVER_NAME" - WSS", codec)) { snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); snd_opti93x_free(codec); return -EBUSY; } codec->card = card; codec->port = chip->wss_base + 4; codec->irq = chip->irq; spin_lock_init(&codec->lock); codec->hardware = chip->hardware; codec->chip = chip; if ((error = snd_opti93x_probe(codec))) { snd_opti93x_free(codec); return error; } snd_opti93x_init(codec); /* Register device */ if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { snd_opti93x_free(codec); return error; } *rcodec = codec; return 0;}static snd_pcm_ops_t snd_opti93x_playback_ops = { .open = snd_opti93x_playback_open, .close = snd_opti93x_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_opti93x_hw_params, .hw_free = snd_opti93x_hw_free,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -