📄 opti92x-ad1848.c
字号:
.prepare = snd_opti93x_playback_prepare, .trigger = snd_opti93x_playback_trigger, .pointer = snd_opti93x_playback_pointer,};static snd_pcm_ops_t snd_opti93x_capture_ops = { .open = snd_opti93x_capture_open, .close = snd_opti93x_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_opti93x_hw_params, .hw_free = snd_opti93x_hw_free, .prepare = snd_opti93x_capture_prepare, .trigger = snd_opti93x_capture_trigger, .pointer = snd_opti93x_capture_pointer,};static void snd_opti93x_pcm_free(snd_pcm_t *pcm){ opti93x_t *codec = pcm->private_data; codec->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}static int snd_opti93x_pcm(opti93x_t *codec, int device, snd_pcm_t **rpcm){ int error; snd_pcm_t *pcm; if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm))) return error; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops); pcm->private_data = codec; pcm->private_free = snd_opti93x_pcm_free; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; strcpy(pcm->name, snd_opti93x_chip_id(codec)); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); codec->pcm = pcm; if (rpcm) *rpcm = pcm; return 0;}/* * MIXER part */static int snd_opti93x_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ static char *texts[4] = { "Line1", "Aux", "Mic", "Mix" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 2; uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_opti93x_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ opti93x_t *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6; ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6; spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_opti93x_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ opti93x_t *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned short left, right; int change; if (ucontrol->value.enumerated.item[0] > 3 || ucontrol->value.enumerated.item[1] > 3) return -EINVAL; left = ucontrol->value.enumerated.item[0] << 6; right = ucontrol->value.enumerated.item[1] << 6; spin_lock_irqsave(&chip->lock, flags); left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left; right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right; change = left != chip->image[OPTi93X_MIXOUT_LEFT] || right != chip->image[OPTi93X_MIXOUT_RIGHT]; snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left); snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right); spin_unlock_irqrestore(&chip->lock, flags); return change;}#if 0#define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_opti93x_info_single, \ .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_opti93x_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask = (kcontrol->private_value >> 16) & 0xff; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_opti93x_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ opti93x_t *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; spin_lock_irqsave(&chip->lock, flags); ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; spin_unlock_irqrestore(&chip->lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0;}static int snd_opti93x_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ opti93x_t *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; int change; unsigned short val; val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; val <<= shift; spin_lock_irqsave(&chip->lock, flags); val = (chip->image[reg] & ~(mask << shift)) | val; change = val != chip->image[reg]; snd_opti93x_out(chip, reg, val); spin_unlock_irqrestore(&chip->lock, flags); return change;}#endif /* single */#define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_opti93x_info_double, \ .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }#define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \ do { xctl.private_value ^= 22; } while (0)#define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \ do { xctl.private_value &= ~0x0000ffff; \ xctl.private_value |= left_reg | (right_reg << 8); } while (0)static int snd_opti93x_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask = (kcontrol->private_value >> 24) & 0xff; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_opti93x_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ opti93x_t *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; int shift_right = (kcontrol->private_value >> 19) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; spin_lock_irqsave(&chip->lock, flags); ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; spin_unlock_irqrestore(&chip->lock, flags); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; } return 0;}static int snd_opti93x_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ opti93x_t *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; int shift_right = (kcontrol->private_value >> 19) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; int change; unsigned short val1, val2; val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; if (invert) { val1 = mask - val1; val2 = mask - val2; } val1 <<= shift_left; val2 <<= shift_right; spin_lock_irqsave(&chip->lock, flags); val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; snd_opti93x_out_image(chip, left_reg, val1); snd_opti93x_out_image(chip, right_reg, val2); spin_unlock_irqrestore(&chip->lock, flags); return change;}static snd_kcontrol_new_t snd_opti93x_controls[] = {OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1),OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1),OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1),OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1),OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1),OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = snd_opti93x_info_mux, .get = snd_opti93x_get_mux, .put = snd_opti93x_put_mux,}}; static int snd_opti93x_mixer(opti93x_t *chip){ snd_card_t *card; snd_kcontrol_new_t knew; int err; unsigned int idx; snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); card = chip->card; strcpy(card->mixername, snd_opti93x_chip_id(chip)); for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { knew = snd_opti93x_controls[idx]; if (chip->hardware == OPTi9XX_HW_82C930) { if (strstr(knew.name, "FM")) /* skip FM controls */ continue; else if (strcmp(knew.name, "Mic Playback Volume")) OPTi93X_DOUBLE_INVERT_INVERT(knew); else if (strstr(knew.name, "Aux")) OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT); else if (strcmp(knew.name, "PCM Playback Volume")) OPTi93X_DOUBLE_INVERT_INVERT(knew); else if (strcmp(knew.name, "Master Playback Volume")) OPTi93X_DOUBLE_INVERT_INVERT(knew); } if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0) return err; } return 0;}#endif /* OPTi93X */static int __devinit snd_card_opti9xx_detect(snd_card_t *card, opti9xx_t *chip){ int i, err;#ifndef OPTi93X for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) { unsigned char value; if ((err = snd_opti9xx_init(chip, i)) < 0) return err; if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) continue; value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); if ((value != 0xff) && (value != inb(chip->mc_base + 1))) if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) return 1; release_and_free_resource(chip->res_mc_base); chip->res_mc_base = NULL; }#else /* OPTi93X */ for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { unsigned long flags; unsigned char value; if ((err = snd_opti9xx_init(chip, i)) < 0) return err; if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) continue; spin_lock_irqsave(&chip->lock, flags); outb(chip->password, chip->mc_base + chip->pwd_reg); outb(((chip->mc_indir_index & (1 << 8)) >> 4) | ((chip->mc_indir_index & 0xf0) >> 4), chip->mc_base); spin_unlock_irqrestore(&chip->lock, flags); value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) return 1; release_and_free_resource(chip->res_mc_base); chip->res_mc_base = NULL; }#endif /* OPTi93X */ return -ENODEV;}#ifdef CONFIG_PNPstatic int __devinit snd_card_opti9xx_pnp(opti9xx_t *chip, struct pnp_card_link *card, const struct pnp_card_device_id *pid){ struct pnp_dev *pdev; struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); int err; chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); if (chip->dev == NULL) { kfree(cfg); return -EBUSY; } chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); pdev = chip->dev; pnp_init_resource_table(cfg);#ifdef OPTi93X if (port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], port + 4, 4);#else if (pid->driver_data != 0x0924 && port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], port, 4);#endif /* OPTi93X */ if (irq != SNDRV_AUTO_IRQ) pnp_resource_change(&cfg->irq_resource[0], irq, 1); if (dma1 != SNDRV_AUTO_DMA) pnp_resource_change(&cfg->dma_resource[0], dma1, 1);#if defined(CS4231) || defined(OPTi93X) if (dma2 != SNDRV_AUTO_DMA) pnp_resource_change(&cfg->dma_resource[1], dma2, 1);#else#ifdef snd_opti9xx_fixup_dma2 snd_opti9xx_fixup_dma2(pdev);#endif#endif /* CS4231 || OPTi93X */#ifdef OPTi93X if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], fm_port, 4);#else if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[2], fm_port, 4);#endif if (pnp_manual_config_dev(pdev, cfg, 0) < 0) snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); kfree(cfg); return err; }#ifdef OPTi93X port = pnp_port_start(pdev, 0) - 4; fm_port = pnp_port_start(pdev, 1);#else if (pid->driver_data != 0x0924) port = pnp_port_start(pdev, 1); fm_port = pnp_port_start(pdev, 2);#endif /* OPTi93X */ irq = pnp_irq(pdev, 0); dma1 = pnp_dma(pdev, 0);#if defined(CS4231) || defined(OPTi93X) dma2 = pnp_dma(pdev, 1);#endif /* CS4231 || OPTi93X */ pdev = chip->devmpu; if (pdev && mpu_port > 0) { pnp_init_resource_table(cfg); if (mpu_port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], mpu_port, 2); if (mpu_irq != SNDRV_AUTO_IRQ) pnp_resource_change(&cfg->irq_resource[0], mpu_irq, 1); if (pnp_manual_config_dev(pdev, cfg, 0) < 0) snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); mpu_port = -1; chip->devmpu = NULL; } else { mpu_port = pnp_port_start(pdev, 0); mpu_irq = pnp_irq(pdev, 0); } } kfree(cfg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -