⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rme9652.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	spin_unlock_irq(&rme9652->lock);	return err ? err : change;}/* Read-only switches */#define RME9652_SPDIF_RATE(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \  .info = snd_rme9652_info_spdif_rate, \  .get = snd_rme9652_get_spdif_rate }static int snd_rme9652_info_spdif_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 96000;	return 0;}static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol);		spin_lock_irq(&rme9652->lock);	ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652);	spin_unlock_irq(&rme9652->lock);	return 0;}#define RME9652_ADAT_SYNC(xname, xindex, xidx) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \  .info = snd_rme9652_info_adat_sync, \  .get = snd_rme9652_get_adat_sync, .private_value = xidx }static int snd_rme9652_info_adat_sync(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	static char *texts[4] = {"No Lock", "Lock", "No Lock Sync", "Lock Sync"};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 4;	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol);	unsigned int mask1, mask2, val;		switch (kcontrol->private_value) {	case 0: mask1 = RME9652_lock_0; mask2 = RME9652_sync_0; break;		case 1: mask1 = RME9652_lock_1; mask2 = RME9652_sync_1; break;		case 2: mask1 = RME9652_lock_2; mask2 = RME9652_sync_2; break;		default: return -EINVAL;	}	val = rme9652_read(rme9652, RME9652_status_register);	ucontrol->value.enumerated.item[0] = (val & mask1) ? 1 : 0;	ucontrol->value.enumerated.item[0] |= (val & mask2) ? 2 : 0;	return 0;}#define RME9652_TC_VALID(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \  .info = snd_rme9652_info_tc_valid, \  .get = snd_rme9652_get_tc_valid }static int snd_rme9652_info_tc_valid(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_rme9652_get_tc_valid(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol);		ucontrol->value.integer.value[0] = 		(rme9652_read(rme9652, RME9652_status_register) & RME9652_tc_valid) ? 1 : 0;	return 0;}#ifdef ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE/* FIXME: this routine needs a port to the new control API --jk */static int snd_rme9652_get_tc_value(void *private_data,				    snd_kswitch_t *kswitch,				    snd_switch_t *uswitch){	rme9652_t *s = (rme9652_t *) private_data;	u32 value;	int i;	uswitch->type = SNDRV_SW_TYPE_DWORD;	if ((rme9652_read(s, RME9652_status_register) &	     RME9652_tc_valid) == 0) {		uswitch->value.data32[0] = 0;		return 0;	}	/* timecode request */	rme9652_write(s, RME9652_time_code, 0);	/* XXX bug alert: loop-based timing !!!! */	for (i = 0; i < 50; i++) {		if (!(rme9652_read(s, i * 4) & RME9652_tc_busy))			break;	}	if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) {		return -EIO;	}	value = 0;	for (i = 0; i < 32; i++) {		value >>= 1;		if (rme9652_read(s, i * 4) & RME9652_tc_out)			value |= 0x80000000;	}	if (value > 2 * 60 * 48000) {		value -= 2 * 60 * 48000;	} else {		value = 0;	}	uswitch->value.data32[0] = value;	return 0;}#endif				/* ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE */static snd_kcontrol_new_t snd_rme9652_controls[] = {{	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),	.info =		snd_rme9652_control_spdif_info,	.get =		snd_rme9652_control_spdif_get,	.put =		snd_rme9652_control_spdif_put,},{	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),	.info =		snd_rme9652_control_spdif_stream_info,	.get =		snd_rme9652_control_spdif_stream_get,	.put =		snd_rme9652_control_spdif_stream_put,},{	.access =	SNDRV_CTL_ELEM_ACCESS_READ,	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),	.info =		snd_rme9652_control_spdif_mask_info,	.get =		snd_rme9652_control_spdif_mask_get,	.private_value = IEC958_AES0_NONAUDIO |			IEC958_AES0_PROFESSIONAL |			IEC958_AES0_CON_EMPHASIS,	                                                                                      },{	.access =	SNDRV_CTL_ELEM_ACCESS_READ,	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),	.info =		snd_rme9652_control_spdif_mask_info,	.get =		snd_rme9652_control_spdif_mask_get,	.private_value = IEC958_AES0_NONAUDIO |			IEC958_AES0_PROFESSIONAL |			IEC958_AES0_PRO_EMPHASIS,},RME9652_SPDIF_IN("IEC958 Input Connector", 0),RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),RME9652_SYNC_MODE("Sync Mode", 0),RME9652_SYNC_PREF("Preferred Sync Source", 0),{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Channels Thru",	.index = 0,	.info = snd_rme9652_info_thru,	.get = snd_rme9652_get_thru,	.put = snd_rme9652_put_thru,},RME9652_SPDIF_RATE("IEC958 Sample Rate", 0),RME9652_ADAT_SYNC("ADAT1 Sync Check", 0, 0),RME9652_ADAT_SYNC("ADAT2 Sync Check", 0, 1),RME9652_TC_VALID("Timecode Valid", 0),RME9652_PASSTHRU("Passthru", 0)};static snd_kcontrol_new_t snd_rme9652_adat3_check =RME9652_ADAT_SYNC("ADAT3 Sync Check", 0, 2);static snd_kcontrol_new_t snd_rme9652_adat1_input =RME9652_ADAT1_IN("ADAT1 Input Source", 0);static int snd_rme9652_create_controls(snd_card_t *card, rme9652_t *rme9652){	unsigned int idx;	int err;	snd_kcontrol_t *kctl;	for (idx = 0; idx < ARRAY_SIZE(snd_rme9652_controls); idx++) {		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652))) < 0)			return err;		if (idx == 1)	/* IEC958 (S/PDIF) Stream */			rme9652->spdif_ctl = kctl;	}	if (rme9652->ss_channels == RME9652_NCHANNELS)		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652))) < 0)			return err;	if (rme9652->hw_rev >= 15)		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652))) < 0)			return err;	return 0;}/*------------------------------------------------------------   /proc interface  ------------------------------------------------------------*/static voidsnd_rme9652_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer){	rme9652_t *rme9652 = (rme9652_t *) entry->private_data;	u32 thru_bits = rme9652->thru_bits;	int show_auto_sync_source = 0;	int i;	unsigned int status;	int x;	status = rme9652_read(rme9652, RME9652_status_register);	snd_iprintf(buffer, "%s (Card #%d)\n", rme9652->card_name, rme9652->card->number + 1);	snd_iprintf(buffer, "Buffers: capture %p playback %p\n",		    rme9652->capture_buffer, rme9652->playback_buffer);	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",		    rme9652->irq, rme9652->port, (unsigned long)rme9652->iobase);	snd_iprintf(buffer, "Control register: %x\n", rme9652->control_register);	snd_iprintf(buffer, "\n");	x = 1 << (6 + rme9652_decode_latency(rme9652->control_register & 					     RME9652_latency));	snd_iprintf(buffer, "Latency: %d samples (2 periods of %lu bytes)\n", 		    x, (unsigned long) rme9652->period_bytes);	snd_iprintf(buffer, "Hardware pointer (frames): %ld\n",		    rme9652_hw_pointer(rme9652));	snd_iprintf(buffer, "Passthru: %s\n",		    rme9652->passthru ? "yes" : "no");	if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) {		snd_iprintf(buffer, "Clock mode: autosync\n");		show_auto_sync_source = 1;	} else if (rme9652->control_register & RME9652_wsel) {		if (status & RME9652_wsel_rd) {			snd_iprintf(buffer, "Clock mode: word clock\n");		} else {			snd_iprintf(buffer, "Clock mode: word clock (no signal)\n");		}	} else {		snd_iprintf(buffer, "Clock mode: master\n");	}	if (show_auto_sync_source) {		switch (rme9652->control_register & RME9652_SyncPref_Mask) {		case RME9652_SyncPref_ADAT1:			snd_iprintf(buffer, "Pref. sync source: ADAT1\n");			break;		case RME9652_SyncPref_ADAT2:			snd_iprintf(buffer, "Pref. sync source: ADAT2\n");			break;		case RME9652_SyncPref_ADAT3:			snd_iprintf(buffer, "Pref. sync source: ADAT3\n");			break;		case RME9652_SyncPref_SPDIF:			snd_iprintf(buffer, "Pref. sync source: IEC958\n");			break;		default:			snd_iprintf(buffer, "Pref. sync source: ???\n");		}	}	if (rme9652->hw_rev >= 15)		snd_iprintf(buffer, "\nADAT1 Input source: %s\n",			    (rme9652->control_register & RME9652_ADAT1_INTERNAL) ?			    "Internal" : "ADAT1 optical");	snd_iprintf(buffer, "\n");	switch (rme9652_decode_spdif_in(rme9652->control_register & 					RME9652_inp)) {	case RME9652_SPDIFIN_OPTICAL:		snd_iprintf(buffer, "IEC958 input: ADAT1\n");		break;	case RME9652_SPDIFIN_COAXIAL:		snd_iprintf(buffer, "IEC958 input: Coaxial\n");		break;	case RME9652_SPDIFIN_INTERN:		snd_iprintf(buffer, "IEC958 input: Internal\n");		break;	default:		snd_iprintf(buffer, "IEC958 input: ???\n");		break;	}	if (rme9652->control_register & RME9652_opt_out) {		snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");	} else {		snd_iprintf(buffer, "IEC958 output: Coaxial only\n");	}	if (rme9652->control_register & RME9652_PRO) {		snd_iprintf(buffer, "IEC958 quality: Professional\n");	} else {		snd_iprintf(buffer, "IEC958 quality: Consumer\n");	}	if (rme9652->control_register & RME9652_EMP) {		snd_iprintf(buffer, "IEC958 emphasis: on\n");	} else {		snd_iprintf(buffer, "IEC958 emphasis: off\n");	}	if (rme9652->control_register & RME9652_Dolby) {		snd_iprintf(buffer, "IEC958 Dolby: on\n");	} else {		snd_iprintf(buffer, "IEC958 Dolby: off\n");	}	i = rme9652_spdif_sample_rate(rme9652);	if (i < 0) {		snd_iprintf(buffer,			    "IEC958 sample rate: error flag set\n");	} else if (i == 0) {		snd_iprintf(buffer, "IEC958 sample rate: undetermined\n");	} else {		snd_iprintf(buffer, "IEC958 sample rate: %d\n", i);	}	snd_iprintf(buffer, "\n");	snd_iprintf(buffer, "ADAT Sample rate: %dHz\n",		    rme9652_adat_sample_rate(rme9652));	/* Sync Check */	x = status & RME9652_sync_0;	if (status & RME9652_lock_0) {		snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock");	} else {		snd_iprintf(buffer, "ADAT1: No Lock\n");	}	x = status & RME9652_sync_1;	if (status & RME9652_lock_1) {		snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");	} else {		snd_iprintf(buffer, "ADAT2: No Lock\n");	}	x = status & RME9652_sync_2;	if (status & RME9652_lock_2) {		snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock");	} else {		snd_iprintf(buffer, "ADAT3: No Lock\n");	}	snd_iprintf(buffer, "\n");	snd_iprintf(buffer, "Timecode signal: %s\n",		    (status & RME9652_tc_valid) ? "yes" : "no");	/* thru modes */	snd_iprintf(buffer, "Punch Status:\n\n");	for (i = 0; i < rme9652->ss_channels; i++) {		if (thru_bits & (1 << i)) {			snd_iprintf(buffer, "%2d:  on ", i + 1);		} else {			snd_iprintf(buffer, "%2d: off ", i + 1);		}		if (((i + 1) % 8) == 0) {			snd_iprintf(buffer, "\n");		}	}	snd_iprintf(buffer, "\n");}static void __devinit snd_rme9652_proc_init(rme9652_t *rme9652){	snd_info_entry_t *entry;	if (! snd_card_proc_new(rme9652->card, "rme9652", &entry))		snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read);}static void snd_rme9652_free_buffers(rme9652_t *rme9652){	snd_hammerfall_free_buffer(&rme9652->capture_dma_buf, rme9652->pci);	snd_hammerfall_free_buffer(&rme9652->playback_dma_buf, rme9652->pci);}static int snd_rme9652_free(rme9652_t *rme9652){	if (rme9652->irq >= 0)		rme9652_stop(rme9652);	snd_rme9652_free_buffers(rme9652);	if (rme9652->irq >= 0)		free_irq(rme9652->irq, (void *)rme9652);	if (rme9652->iobase)		iounmap(rme9652->iobase);	if (rme9652->port)		pci_release_regions(rme9652->pci);	pci_disable_device(rme9652->pci);	return 0;}static int __devinit snd_rme9652_initialize_memory(rme9652_t *rme9652){	unsigned long pb_bus, cb_bus;	if (snd_hammerfall_get_buffer(rme9652->pci, &rme9652->capture_dma_buf, RME9652_DMA_AREA_BYTES) < 0 ||	    snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) {		if (rme9652->capture_dma_buf.area)			snd_dma_free_pages(&rme9652->capture_dma_buf);		printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name);		return -ENOMEM;	}	/* Align to bus-space 64K boundary */	cb_bus = (rme9652->capture_dma_buf.addr + 0xFFFF) & ~0xFFFFl;	pb_bus = (rme9652->playback_dma_buf.addr + 0xFFFF) & ~0xFFFFl;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -