📄 opti92x-ad1848.c
字号:
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, 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 = snd_magic_cast(opti93x_t, pcm->private_data, return); codec->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}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_isa_pages_for_all(pcm, 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(chip, OPTi93X_MIXOUT_LEFT, left); snd_opti93x_out(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 >> 16) & 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(chip, left_reg, val1); snd_opti93x_out(chip, right_reg, val1); spin_unlock_irqrestore(&chip->lock, flags); return change;}#define OPTi93X_CONTROLS (sizeof(snd_opti93x_controls)/sizeof(snd_kcontrol_new_t))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, 0, 0, 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, 0),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, 0, 0, 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, 0, 0, 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, 0, 0, 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, 0, 0, 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, 0, 0, 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,}}; int snd_opti93x_mixer(opti93x_t *chip){ snd_card_t *card; snd_kcontrol_new_t knew; int err, 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 < 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 __init snd_card_opti9xx_detect(snd_card_t *card, opti9xx_t *chip){ int i, err; static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};#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; chip->mc_base_size = opti9xx_mc_size[i]; if (check_region(chip->mc_base, chip->mc_base_size)) 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; }#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; chip->mc_base_size = opti9xx_mc_size[i]; if (check_region(chip->mc_base, chip->mc_base_size)) 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; }#endif /* OPTi93X */ return -ENODEV;}#ifdef __ISAPNP__static int __init snd_card_opti9xx_isapnp(opti9xx_t *chip){ struct isapnp_dev *pdev = NULL; const struct isapnp_card_id *pid = snd_card_opti9xx_pnpids-1; static struct isapnp_card *card = NULL; __again: while (1) { pid++; if (pid->card_vendor == 0) return -ENODEV; if ((card = isapnp_find_card(pid->card_vendor, pid->card_device, card))) break; } if (card == NULL) return -ENODEV; chip->dev = isapnp_find_dev(card, pid->devs[0].vendor, pid->devs[0].function, NULL); if (chip->dev == NULL) goto __again; chip->devmpu = isapnp_find_dev(card, pid->devs[1].vendor, pid->devs[1].function, NULL); pdev = chip->dev; if (pdev->prepare(pdev) < 0) return -EAGAIN;#ifdef OPTi93X if (snd_port != SNDRV_AUTO_PORT) isapnp_resource_change(&pdev->resource[0], snd_port + 4, 4);#else if ((pid->card_device != ISAPNP_DEVICE(0x0924)) && (snd_port != SNDRV_AUTO_PORT)) isapnp_resource_change(&pdev->resource[1], snd_port, 4);#endif /* OPTi93X */ if (snd_irq != SNDRV_AUTO_IRQ) isapnp_resource_change(&pdev->irq_resource[0], snd_irq, 1); if (snd_dma1 != SNDRV_AUTO_DMA) isapnp_resource_change(&pdev->dma_resource[0], snd_dma1, 1);#if defined(CS4231) || defined(OPTi93X) if (snd_dma2 != SNDRV_AUTO_DMA) isapnp_resource_change(&pdev->dma_resource[1], snd_dma2, 1);#endif /* CS4231 || OPTi93X */ if (snd_fm_port != SNDRV_AUTO_PORT) isapnp_resource_change(&pdev->resource[1], snd_fm_port, 4); if (pdev->activate(pdev) < 0) { snd_printk("AUDIO isapnp configure failure\n"); return -EBUSY; }#ifdef OPTi93X snd_port = pdev->resource[0].start - 4; snd_fm_port = pdev->resource[1].start;#else if (pid->card_device != ISAPNP_DEVICE(0x0924)) snd_port = pdev->resource[1].start; snd_fm_port = pdev->resource[2].start;#endif /* OPTi93X */ snd_irq = pdev->irq_resource[0].start; snd_dma1 = pdev->dma_resource[0].start;#if defined(CS4231) || defined(OPTi93X) snd_dma2 = pdev->dma_resource[1].start;#endif /* CS4231 || OPTi93X */ pdev = chip->devmpu; if (pdev == NULL || pdev->prepare(pdev) < 0) { snd_mpu_port = -1; chip->devmpu = NULL; return pid->card_device; } if (snd_mpu_port != SNDRV_AUTO_PORT) isapnp_resource_change(&pdev->resource[0], snd_mpu_port, 2); if (snd_mpu_irq != SNDRV_AUTO_IRQ) isapnp_resource_change(&pdev->irq_resource[0], snd_mpu_irq, 1); if (pdev->activate(pdev) < 0) { snd_printk("MPU-401 isapnp configure failure\n"); snd_mpu_port = -1; chip->devmpu = NULL; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -