if (ac97->scaps) { 
if (ac97->scaps && ac97_is_audio(ac97)) { 
int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97){	int err;	ac97_t *ac97;	snd_card_t *card;	char name[64];	unsigned long end_time;	unsigned int reg;	const ac97_codec_id_t *pid;	static snd_device_ops_t ops = {		.dev_free =	snd_ac97_dev_free,		.dev_register =	snd_ac97_dev_register,		.dev_unregister =	snd_ac97_dev_unregister,	};	snd_assert(rac97 != NULL, return -EINVAL);	*rac97 = NULL;	snd_assert(bus != NULL && template != NULL, return -EINVAL);	snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL);	snd_assert(bus->shared_type <= AC97_SHARED_TYPES, return -EINVAL);	if (bus->shared_type) {		/* already shared? */		down(&shared_codec_mutex);		ac97 = shared_codec[bus->shared_type-1][template->num];		if (ac97) {			if ((ac97_is_audio(ac97) && (template->scaps & AC97_SCAP_SKIP_AUDIO)) ||			    (ac97_is_modem(ac97) && (template->scaps & AC97_SCAP_SKIP_MODEM))) {				up(&shared_codec_mutex);				return -EACCES; /* skip this */			}		}		up(&shared_codec_mutex);	}	card = bus->card;	ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL);	if (ac97 == NULL)		return -ENOMEM;	ac97->private_data = template->private_data;	ac97->private_free = template->private_free;	ac97->bus = bus;	ac97->pci = template->pci;	ac97->num = template->num;	ac97->addr = template->addr;	ac97->scaps = template->scaps;	ac97->limited_regs = template->limited_regs;	memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed));	bus->codec[ac97->num] = ac97;	init_MUTEX(&ac97->reg_mutex);	init_MUTEX(&ac97->page_mutex);	if (ac97->pci) {		pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor);		pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device);	}	if (bus->ops->reset) {		bus->ops->reset(ac97);		goto __access_ok;	}	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);	if (ac97->id && ac97->id != (unsigned int)-1) {		pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id);		if (pid && (pid->flags & AC97_DEFAULT_POWER_OFF))			goto __access_ok;	}	/* reset to defaults */	if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO))		snd_ac97_write(ac97, AC97_RESET, 0);	if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM))		snd_ac97_write(ac97, AC97_EXTENDED_MID, 0);	if (bus->ops->wait)		bus->ops->wait(ac97);	else {		udelay(50);		if (ac97->scaps & AC97_SCAP_SKIP_AUDIO)			err = ac97_reset_wait(ac97, HZ/2, 1);		else {			err = ac97_reset_wait(ac97, HZ/2, 0);			if (err < 0)				err = ac97_reset_wait(ac97, HZ/2, 1);		}		if (err < 0) {			snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num);			/* proceed anyway - it's often non-critical */		}	}      __access_ok:	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);	if (! (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) &&	    (ac97->id == 0x00000000 || ac97->id == 0xffffffff)) {		snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id);		snd_ac97_free(ac97);		return -EIO;	}	pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id);	if (pid)		ac97->flags |= pid->flags;		/* test for AC'97 */	if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) {		/* test if we can write to the record gain volume register */		snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06);		if (((err = snd_ac97_read(ac97, AC97_REC_GAIN)) & 0x7fff) == 0x0a06)			ac97->scaps |= AC97_SCAP_AUDIO;	}	if (ac97->scaps & AC97_SCAP_AUDIO) {		ac97->caps = snd_ac97_read(ac97, AC97_RESET);		ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);		if (ac97->ext_id == 0xffff)	/* invalid combination */			ac97->ext_id = 0;	}	/* test for MC'97 */	if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM) && !(ac97->scaps & AC97_SCAP_MODEM)) {		ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);		if (ac97->ext_mid == 0xffff)	/* invalid combination */			ac97->ext_mid = 0;		if (ac97->ext_mid & 1)			ac97->scaps |= AC97_SCAP_MODEM;	}	if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) {		if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM)))			snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num);		snd_ac97_free(ac97);		return -EACCES;	}	if (bus->ops->reset) // FIXME: always skipping?		goto __ready_ok;	/* FIXME: add powerdown control */	if (ac97_is_audio(ac97)) {		/* nothing should be in powerdown mode */		snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);		if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) {			snd_ac97_write_cache(ac97, AC97_RESET, 0); /* reset to defaults */			udelay(100);			snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);		}		/* nothing should be in powerdown mode */		snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0);		end_time = jiffies + (HZ / 10);		do {			if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)				goto __ready_ok;			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout(1);		} while (time_after_eq(end_time, jiffies));		snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num);	}	/* FIXME: add powerdown control */	if (ac97_is_modem(ac97)) {		unsigned char tmp;		/* nothing should be in powerdown mode */		/* note: it's important to set the rate at first */		tmp = AC97_MEA_GPIO;		if (ac97->ext_mid & AC97_MEI_LINE1) {			snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000);			tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1;		}		if (ac97->ext_mid & AC97_MEI_LINE2) {			snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000);			tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2;		}		if (ac97->ext_mid & AC97_MEI_HANDSET) {			snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000);			tmp |= AC97_MEA_HADC | AC97_MEA_HDAC;		}		snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0);		udelay(100);		/* nothing should be in powerdown mode */		snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0);		end_time = jiffies + (HZ / 10);		do {			if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)				goto __ready_ok;			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout(1);		} while (time_after_eq(end_time, jiffies));		snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));	}	      __ready_ok:	if (ac97_is_audio(ac97))		ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;	else		ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT;	if (ac97->ext_id & 0x01c9) {	/* L/R, MIC, SDAC, LDAC VRA support */		reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);		reg |= ac97->ext_id & 0x01c0; /* LDAC/SDAC/CDAC */		if (! bus->no_vra)			reg |= ac97->ext_id & 0x0009; /* VRA/VRM */		snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg);	}	if ((ac97->ext_id & AC97_EI_DRA) && bus->dra) {		/* Intel controllers require double rate data to be put in		 * slots 7+8, so let's hope the codec supports it. */		snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, AC97_GP_DRSS_MASK, AC97_GP_DRSS_78);		if ((snd_ac97_read(ac97, AC97_GENERAL_PURPOSE) & AC97_GP_DRSS_MASK) == AC97_GP_DRSS_78)			ac97->flags |= AC97_DOUBLE_RATE;	}	if (ac97->ext_id & AC97_EI_VRA) {	/* VRA support */		snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]);		snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, 0, &ac97->rates[AC97_RATES_ADC]);	} else {		ac97->rates[AC97_RATES_FRONT_DAC] = SNDRV_PCM_RATE_48000;		if (ac97->flags & AC97_DOUBLE_RATE)			ac97->rates[AC97_RATES_FRONT_DAC] |= SNDRV_PCM_RATE_96000;		ac97->rates[AC97_RATES_ADC] = SNDRV_PCM_RATE_48000;	}	if (ac97->ext_id & AC97_EI_SPDIF) {		/* codec specific code (patch) should override these values */		ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000;	}	if (ac97->ext_id & AC97_EI_VRM) {	/* MIC VRA support */		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);	} else {		ac97->rates[AC97_RATES_MIC_ADC] = SNDRV_PCM_RATE_48000;	}	if (ac97->ext_id & AC97_EI_SDAC) {	/* SDAC support */		snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);		ac97->scaps |= AC97_SCAP_SURROUND_DAC;	}	if (ac97->ext_id & AC97_EI_LDAC) {	/* LDAC support */		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;	}	/* additional initializations */	if (bus->ops->init)		bus->ops->init(ac97);	snd_ac97_get_name(ac97, ac97->id, name, !ac97_is_audio(ac97));	snd_ac97_get_name(NULL, ac97->id, name, !ac97_is_audio(ac97));  // ac97->id might be changed in the special setup code	if (! ac97->build_ops)		ac97->build_ops = &null_build_ops;	if (ac97_is_audio(ac97)) {		char comp[16];		if (card->mixername[0] == '\0') {			strcpy(card->mixername, name);		} else {			if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {				strcat(card->mixername, ",");				strcat(card->mixername, name);			}		}		sprintf(comp, "AC97a:%08x", ac97->id);		if ((err = snd_component_add(card, comp)) < 0) {			snd_ac97_free(ac97);			return err;		}		if (snd_ac97_mixer_build(ac97) < 0) {			snd_ac97_free(ac97);			return -ENOMEM;		}	}	if (ac97_is_modem(ac97)) {		char comp[16];		if (card->mixername[0] == '\0') {			strcpy(card->mixername, name);		} else {			if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {				strcat(card->mixername, ",");				strcat(card->mixername, name);			}		}		sprintf(comp, "AC97m:%08x", ac97->id);		if ((err = snd_component_add(card, comp)) < 0) {			snd_ac97_free(ac97);			return err;		}		if (snd_ac97_modem_build(card, ac97) < 0) {			snd_ac97_free(ac97);			return -ENOMEM;		}	}	/* make sure the proper powerdown bits are cleared */	if (ac97->scaps) {		reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);		if (ac97->scaps & AC97_SCAP_SURROUND_DAC) 			reg &= ~AC97_EA_PRJ;		if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) 			reg &= ~(AC97_EA_PRI | AC97_EA_PRK);		snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg);	}	snd_ac97_proc_init(ac97);	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {		snd_ac97_free(ac97);		return err;	}	*rac97 = ac97;	if (bus->shared_type) {		down(&shared_codec_mutex);		shared_codec[bus->shared_type-1][ac97->num] = ac97;		up(&shared_codec_mutex);	}	return 0;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/2ba71978c04d4dba983b4fc658f82eae164c2bca/ac97_codec.c/buggy/sound/pci/ac97/ac97_codec.c