X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Fpci%2Fcs46xx%2Fcs46xx_lib.c;h=0dcfee8015978639f37f01727446d02675de88f4;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=9b18681418c820188e5aa374ba08c6b7925d58d0;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 9b1868141..0dcfee801 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -68,6 +68,20 @@ static void amp_voyetra(cs46xx_t *chip, int change); +#ifdef CONFIG_SND_CS46XX_NEW_DSP +static snd_pcm_ops_t snd_cs46xx_playback_rear_ops; +static snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops; +static snd_pcm_ops_t snd_cs46xx_playback_clfe_ops; +static snd_pcm_ops_t snd_cs46xx_playback_indirect_clfe_ops; +static snd_pcm_ops_t snd_cs46xx_playback_iec958_ops; +static snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops; +#endif + +static snd_pcm_ops_t snd_cs46xx_playback_ops; +static snd_pcm_ops_t snd_cs46xx_playback_indirect_ops; +static snd_pcm_ops_t snd_cs46xx_capture_ops; +static snd_pcm_ops_t snd_cs46xx_capture_indirect_ops; + static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip, unsigned short reg, int codec_index) @@ -99,7 +113,7 @@ static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip, if ((tmp & ACCTL_VFRM) == 0) { snd_printk(KERN_WARNING "cs46xx: ACCTL_VFRM not set 0x%x\n",tmp); snd_cs46xx_pokeBA0(chip, BA0_ACCTL, (tmp & (~ACCTL_ESYN)) | ACCTL_VFRM ); - mdelay(50); + msleep(50); tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL + offset); snd_cs46xx_pokeBA0(chip, BA0_ACCTL, tmp | ACCTL_ESYN | ACCTL_VFRM ); @@ -203,12 +217,6 @@ static unsigned short snd_cs46xx_ac97_read(ac97_t * ac97, val = snd_cs46xx_codec_read(chip, reg, codec_index); - /* HACK: voyetra uses EAPD bit in the reverse way. - * we flip the bit to show the mixer status correctly - */ - if (reg == AC97_POWERDOWN && chip->amplifier_ctrl == amp_voyetra) - val ^= 0x8000; - return val; } @@ -289,12 +297,6 @@ static void snd_cs46xx_ac97_write(ac97_t *ac97, codec_index == CS46XX_SECONDARY_CODEC_INDEX, return); - /* HACK: voyetra uses EAPD bit in the reverse way. - * we flip the bit to show the mixer status correctly - */ - if (reg == AC97_POWERDOWN && chip->amplifier_ctrl == amp_voyetra) - val ^= 0x8000; - snd_cs46xx_codec_write(chip, reg, val, codec_index); } @@ -308,7 +310,7 @@ int snd_cs46xx_download(cs46xx_t *chip, unsigned long offset, unsigned long len) { - unsigned long dst; + void __iomem *dst; unsigned int bank = offset >> 16; offset = offset & 0xffff; @@ -336,7 +338,7 @@ int snd_cs46xx_clear_BA1(cs46xx_t *chip, unsigned long offset, unsigned long len) { - unsigned long dst; + void __iomem *dst; unsigned int bank = offset >> 16; offset = offset & 0xffff; @@ -1458,7 +1460,7 @@ static int snd_cs46xx_capture_close(snd_pcm_substream_t * substream) } #ifdef CONFIG_SND_CS46XX_NEW_DSP -snd_pcm_ops_t snd_cs46xx_playback_rear_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_rear_ops = { .open = snd_cs46xx_playback_open_rear, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1469,7 +1471,7 @@ snd_pcm_ops_t snd_cs46xx_playback_rear_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = { .open = snd_cs46xx_playback_open_rear, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1481,7 +1483,7 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = { .ack = snd_cs46xx_playback_transfer, }; -snd_pcm_ops_t snd_cs46xx_playback_clfe_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_clfe_ops = { .open = snd_cs46xx_playback_open_clfe, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1492,7 +1494,7 @@ snd_pcm_ops_t snd_cs46xx_playback_clfe_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -snd_pcm_ops_t snd_cs46xx_playback_indirect_clfe_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_indirect_clfe_ops = { .open = snd_cs46xx_playback_open_clfe, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1504,7 +1506,7 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_clfe_ops = { .ack = snd_cs46xx_playback_transfer, }; -snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = { .open = snd_cs46xx_playback_open_iec958, .close = snd_cs46xx_playback_close_iec958, .ioctl = snd_pcm_lib_ioctl, @@ -1515,7 +1517,7 @@ snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = { .open = snd_cs46xx_playback_open_iec958, .close = snd_cs46xx_playback_close_iec958, .ioctl = snd_pcm_lib_ioctl, @@ -1529,7 +1531,7 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = { #endif -snd_pcm_ops_t snd_cs46xx_playback_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_ops = { .open = snd_cs46xx_playback_open, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1540,7 +1542,7 @@ snd_pcm_ops_t snd_cs46xx_playback_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = { +static snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = { .open = snd_cs46xx_playback_open, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1552,7 +1554,7 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = { .ack = snd_cs46xx_playback_transfer, }; -snd_pcm_ops_t snd_cs46xx_capture_ops = { +static snd_pcm_ops_t snd_cs46xx_capture_ops = { .open = snd_cs46xx_capture_open, .close = snd_cs46xx_capture_close, .ioctl = snd_pcm_lib_ioctl, @@ -1563,7 +1565,7 @@ snd_pcm_ops_t snd_cs46xx_capture_ops = { .pointer = snd_cs46xx_capture_direct_pointer, }; -snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = { +static snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = { .open = snd_cs46xx_capture_open, .close = snd_cs46xx_capture_close, .ioctl = snd_pcm_lib_ioctl, @@ -2316,6 +2318,36 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = { #endif }; +#ifdef CONFIG_SND_CS46XX_NEW_DSP +/* set primary cs4294 codec into Extended Audio Mode */ +static int snd_cs46xx_front_dup_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + unsigned short val; + val = snd_ac97_read(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX], AC97_CSR_ACMODE); + ucontrol->value.integer.value[0] = (val & 0x200) ? 0 : 1; + return 0; +} + +static int snd_cs46xx_front_dup_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cs46xx_t *chip = snd_kcontrol_chip(kcontrol); + return snd_ac97_update_bits(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX], + AC97_CSR_ACMODE, 0x200, + ucontrol->value.integer.value[0] ? 0 : 0x200); +} + +static snd_kcontrol_new_t snd_cs46xx_front_dup_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Duplicate Front", + .info = snd_mixer_boolean_info, + .get = snd_cs46xx_front_dup_get, + .put = snd_cs46xx_front_dup_put, +}; +#endif + #ifdef CONFIG_SND_CS46XX_NEW_DSP /* Only available on the Hercules Game Theater XP soundcard */ static snd_kcontrol_new_t snd_hercules_controls[] __devinitdata = { @@ -2333,16 +2365,15 @@ static void snd_cs46xx_codec_reset (ac97_t * ac97) { unsigned long end_time; int err; - cs46xx_t * chip = ac97->private_data; /* reset to defaults */ snd_ac97_write(ac97, AC97_RESET, 0); /* set the desired CODEC mode */ - if (chip->nr_ac97_codecs == 0) { + if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) { snd_printdd("cs46xx: CODOEC1 mode %04x\n",0x0); snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x0); - } else if (chip->nr_ac97_codecs == 1) { + } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) { snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3); snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3); } else { @@ -2380,10 +2411,43 @@ static void snd_cs46xx_codec_reset (ac97_t * ac97) } #endif +static int __devinit cs46xx_detect_codec(cs46xx_t *chip, int codec) +{ + int idx, err; + ac97_template_t ac97; + + memset(&ac97, 0, sizeof(ac97)); + ac97.private_data = chip; + ac97.private_free = snd_cs46xx_mixer_free_ac97; + ac97.num = codec; + if (chip->amplifier_ctrl == amp_voyetra) + ac97.scaps = AC97_SCAP_INV_EAPD; + + if (codec == CS46XX_SECONDARY_CODEC_INDEX) { + snd_cs46xx_codec_write(chip, AC97_RESET, 0, codec); + udelay(10); + if (snd_cs46xx_codec_read(chip, AC97_RESET, codec) & 0x8000) { + snd_printdd("snd_cs46xx: seconadry codec not present\n"); + return -ENXIO; + } + } + + snd_cs46xx_codec_write(chip, AC97_MASTER, 0x8000, codec); + for (idx = 0; idx < 100; ++idx) { + if (snd_cs46xx_codec_read(chip, AC97_MASTER, codec) == 0x8000) { + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[codec]); + return err; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/100); + } + snd_printdd("snd_cs46xx: codec %d detection timeout\n", codec); + return -ENXIO; +} + int __devinit snd_cs46xx_mixer(cs46xx_t *chip) { snd_card_t *card = chip->card; - ac97_template_t ac97; snd_ctl_elem_id_t id; int err; unsigned int idx; @@ -2402,70 +2466,15 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) return err; chip->ac97_bus->private_free = snd_cs46xx_mixer_free_ac97_bus; - memset(&ac97, 0, sizeof(ac97)); - ac97.private_data = chip; - ac97.private_free = snd_cs46xx_mixer_free_ac97; - - snd_cs46xx_codec_write(chip, AC97_MASTER, 0x8000, - CS46XX_PRIMARY_CODEC_INDEX); - for (idx = 0; idx < 100; ++idx) { - if (snd_cs46xx_codec_read(chip, AC97_MASTER, - CS46XX_PRIMARY_CODEC_INDEX) == 0x8000) - goto _ok; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/100); - } - return -ENXIO; - - _ok: - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[CS46XX_PRIMARY_CODEC_INDEX])) < 0) - return err; - snd_printdd("snd_cs46xx: primary codec phase one\n"); + if (cs46xx_detect_codec(chip, CS46XX_PRIMARY_CODEC_INDEX) < 0) + return -ENXIO; chip->nr_ac97_codecs = 1; #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_printdd("snd_cs46xx: detecting seconadry codec\n"); /* try detect a secondary codec */ - memset(&ac97, 0, sizeof(ac97)); - ac97.private_data = chip; - ac97.private_free = snd_cs46xx_mixer_free_ac97; - ac97.num = CS46XX_SECONDARY_CODEC_INDEX; - - snd_cs46xx_codec_write(chip, AC97_RESET, 0, - CS46XX_SECONDARY_CODEC_INDEX); - udelay(10); - - if (snd_cs46xx_codec_read(chip, AC97_RESET, - CS46XX_SECONDARY_CODEC_INDEX) & 0x8000) { - snd_printdd("snd_cs46xx: seconadry codec not present\n"); - goto _no_sec_codec; - } - - snd_cs46xx_codec_write(chip, AC97_MASTER, 0x8000, - CS46XX_SECONDARY_CODEC_INDEX); - for (idx = 0; idx < 100; ++idx) { - if (snd_cs46xx_codec_read(chip, AC97_MASTER, - CS46XX_SECONDARY_CODEC_INDEX) == 0x8000) { - goto _ok2; - } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/100); - } - - _no_sec_codec: - snd_printdd("snd_cs46xx: secondary codec did not respond ...\n"); - - chip->nr_ac97_codecs = 1; - - /* well, one codec only ... */ - goto _end; - _ok2: - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0) - return err; - chip->nr_ac97_codecs = 2; - - _end: - + if (! cs46xx_detect_codec(chip, CS46XX_SECONDARY_CODEC_INDEX)) + chip->nr_ac97_codecs = 2; #endif /* CONFIG_SND_CS46XX_NEW_DSP */ /* add cs4630 mixer controls */ @@ -2483,15 +2492,15 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) chip->eapd_switch = snd_ctl_find_id(chip->card, &id); #ifdef CONFIG_SND_CS46XX_NEW_DSP - if (chip->nr_ac97_codecs == 1 && - (snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, - CS46XX_PRIMARY_CODEC_INDEX) == 0x592b || - snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, - CS46XX_PRIMARY_CODEC_INDEX) == 0x592d)) { - /* set primary cs4294 codec into Extended Audio Mode */ - snd_printdd("setting EAM bit on cs4294 CODEC\n"); - snd_cs46xx_codec_write(chip, AC97_CSR_ACMODE, 0x200, - CS46XX_PRIMARY_CODEC_INDEX); + if (chip->nr_ac97_codecs == 1) { + unsigned int id2 = chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]->id & 0xffff; + if (id2 == 0x592b || id2 == 0x592d) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_cs46xx_front_dup_ctl, chip)); + if (err < 0) + return err; + snd_ac97_write_cache(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX], + AC97_CSR_ACMODE, 0x200); + } } /* do soundcard specific mixer setup */ if (chip->mixer_init) { @@ -2902,7 +2911,7 @@ static int snd_cs46xx_free(cs46xx_t *chip) for (idx = 0; idx < 5; idx++) { snd_cs46xx_region_t *region = &chip->region.idx[idx]; if (region->remap_addr) - iounmap((void *) region->remap_addr); + iounmap(region->remap_addr); if (region->resource) { release_resource(region->resource); kfree_nocheck(region->resource); @@ -2921,6 +2930,7 @@ static int snd_cs46xx_free(cs46xx_t *chip) } #endif + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -3714,7 +3724,7 @@ static int snd_cs46xx_suspend(snd_card_t *card, unsigned int state) /* disable CLKRUN */ chip->active_ctrl(chip, -chip->amplifier); chip->amplifier = amp_saved; /* restore the status */ - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + pci_disable_device(chip->pci); return 0; } @@ -3724,6 +3734,7 @@ static int snd_cs46xx_resume(snd_card_t *card, unsigned int state) int amp_saved; pci_enable_device(chip->pci); + pci_set_master(chip->pci); amp_saved = chip->amplifier; chip->amplifier = 0; chip->active_ctrl(chip, 1); /* force to on */ @@ -3750,7 +3761,6 @@ static int snd_cs46xx_resume(snd_card_t *card, unsigned int state) else chip->active_ctrl(chip, -1); /* disable CLKRUN */ chip->amplifier = amp_saved; - snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* CONFIG_PM */ @@ -3780,8 +3790,10 @@ int __devinit snd_cs46xx_create(snd_card_t * card, return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); #ifdef CONFIG_SND_CS46XX_NEW_DSP init_MUTEX(&chip->spos_mutex); @@ -3868,8 +3880,8 @@ int __devinit snd_cs46xx_create(snd_card_t * card, snd_cs46xx_free(chip); return -EBUSY; } - region->remap_addr = (unsigned long) ioremap_nocache(region->base, region->size); - if (region->remap_addr == 0) { + region->remap_addr = ioremap_nocache(region->base, region->size); + if (region->remap_addr == NULL) { snd_printk("%s ioremap problem\n", region->name); snd_cs46xx_free(chip); return -ENOMEM; @@ -3897,15 +3909,15 @@ int __devinit snd_cs46xx_create(snd_card_t * card, return err; } - snd_cs46xx_proc_init(card, chip); - - snd_card_set_pm_callback(card, snd_cs46xx_suspend, snd_cs46xx_resume, chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_cs46xx_free(chip); return err; } + snd_cs46xx_proc_init(card, chip); + + snd_card_set_pm_callback(card, snd_cs46xx_suspend, snd_cs46xx_resume, chip); + chip->active_ctrl(chip, -1); /* disable CLKRUN */ snd_card_set_dev(card, &pci->dev);