All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] asihpi driver, adds tuner controls, AESEBU controls, bus master support where available
@ 2005-07-28  5:17 Delio Brignoli
  2005-07-28  9:20 ` Takashi Iwai
  0 siblings, 1 reply; 4+ messages in thread
From: Delio Brignoli @ 2005-07-28  5:17 UTC (permalink / raw)
  To: tiwai; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1201 bytes --]


Hello,

> RETURN_IF_NEG() is a bit ugly.  In your code, it's not clear whether
> this is for a debug purpose or for checking a critical error.
> 
> If it's just a check, you can use snd_assert().  Otherwise, a plain
> if() would be easier to read.
> 
> Could you rewrite that stuff?

I've used snd_runtime_check ( thanks for pointing me at it )

I'm attaching a new patch with some extra features:

Thu Jul 28 17:03:28 NZST 2005  dbrignoli@audioscience.com
  * added_enable_bbm_module_param
Thu Jul 28 16:50:46 NZST 2005  dbrignoli@audioscience.com
  * use_alsa_debug_assertions_and_printd
Tue Jul 26 18:15:11 NZST 2005  dbrignoli@audioscience.com
  * fixed_bus_master_buffer_size_calculation
Tue Jul 26 18:13:50 NZST 2005  dbrignoli@audioscience.com
  * fixed_HPI_error_handling_macro_to_include_filename
Fri Jul 22 16:37:16 NZST 2005  dbrignoli@audioscience.com
  * add AESEBU controls to alsa mixer
Fri Jul 22 12:33:22 NZST 2005  dbrignoli@audioscience.com
  * enable_HPI_stream_host_buffers_if_supported
Thu Jul 21 16:03:58 NZST 2005  dbrignoli@audioscience.com
  * add_tuner_controls

--
Delio Brignoli
dbrignoli@audioscience.com

[-- Attachment #2: patch.txt --]
[-- Type: application/octet-stream, Size: 23528 bytes --]

Thu Jul 28 17:03:28 NZST 2005  dbrignoli@audioscience.com
  * added_enable_bbm_module_param
Thu Jul 28 16:50:46 NZST 2005  dbrignoli@audioscience.com
  * use_alsa_debug_assertions_and_printd
Tue Jul 26 18:15:11 NZST 2005  dbrignoli@audioscience.com
  * fixed_bus_master_buffer_size_calculation
Tue Jul 26 18:13:50 NZST 2005  dbrignoli@audioscience.com
  * fixed_HPI_error_handling_macro_to_include_filename
Fri Jul 22 16:37:16 NZST 2005  dbrignoli@audioscience.com
  * add AESEBU controls to alsa mixer
Fri Jul 22 12:33:22 NZST 2005  dbrignoli@audioscience.com
  * enable_HPI_stream_host_buffers_if_supported
Thu Jul 21 16:03:58 NZST 2005  dbrignoli@audioscience.com
  * add_tuner_controls
diff -rN -u old-alsa-driver-1.0.9b-rep/pci/asihpi.c new-alsa-driver-1.0.9b-rep/pci/asihpi.c
--- old-alsa-driver-1.0.9b-rep/pci/asihpi.c	2005-07-28 17:09:05.000000000 +1200
+++ new-alsa-driver-1.0.9b-rep/pci/asihpi.c	2005-07-28 16:57:18.000000000 +1200
@@ -57,6 +57,9 @@
 module_param(adapter_fs, int, 0444);
 MODULE_PARM_DESC(adapter_fs, "Adapter HW samplerate (if supported)");
 
+static int enable_bbm = 1;
+module_param(enable_bbm, int, 0444);
+MODULE_PARM_DESC(enable_bbm, "Enable background bus master, if available");
 
 MODULE_AUTHOR("Eliot Blennerhassett <EBlennerhassett@audioscience.com>");
 MODULE_DESCRIPTION("AudioScience soundcard (HPI)");
@@ -92,6 +95,8 @@
 	snd_card_asihpi_t *asihpi;
 	spinlock_t lock;
 	struct timer_list timer;
+	unsigned int hpi_in_buffer_allocated;
+	unsigned int hpi_out_buffer_allocated;
 	unsigned int pcm_size;
 	unsigned int pcm_count;
 	unsigned int pcm_jiffie_per_period;
@@ -107,17 +112,17 @@
 static HPI_HSUBSYS *phSubSys;	/* handle to HPI audio subsystem */
 static snd_card_t *snd_asihpi_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
-static void _HandleError(HW16 err, int line)
+static void _HandleError(HW16 err, int line, char *filename)
 {
 	char ErrorText[80];
 
 	if (err) {
 		HPI_GetErrorText(err, ErrorText);
-		printk(KERN_WARNING "line %d: %s\n", line, ErrorText);
+		printk(KERN_WARNING "in file %s, line %d: %s\n", filename, line, ErrorText);
 	}
 }
 
-#define HPI_HandleError(x)  _HandleError(x,__LINE__)
+#define HPI_HandleError(x)  _HandleError(x,__LINE__,__FILE__)
 /***************************** GENERAL PCM ****************/
 static int snd_card_asihpi_pcm_hw_params(snd_pcm_substream_t * substream,
 					 snd_pcm_hw_params_t * params)
@@ -305,6 +310,7 @@
 	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
 	int err;
 	HW16 wFormat;
+	HW32 minBufSize;
 
 	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params))) < 0)
 		return err;
@@ -323,6 +329,31 @@
 	dpcm->Data.dwpbData = (HW32) runtime->dma_area;
 	dpcm->Data.dwDataSize = MAX_BUFFER_SIZE;
 
+	if (enable_bbm) {
+		dpcm->hpi_out_buffer_allocated = 0;
+		minBufSize = 0;
+
+		err = HPI_StreamEstimateBufferSize( &dpcm->Data.Format, (HW32)( 1000 / HZ ), &minBufSize );
+		snd_printd(KERN_INFO "OutStreamHostBuffer estimated size: %d bytes\n", (int)minBufSize);
+
+		if ( minBufSize < MAX_BUFFER_SIZE )
+			minBufSize = MAX_BUFFER_SIZE;
+
+		if ( err == 0 ) {
+			err = HPI_OutStreamHostBufferAllocate( phSubSys, dpcm->hStream, minBufSize );
+			if ( err == 0 ) {
+				dpcm->hpi_out_buffer_allocated = minBufSize;
+				snd_printd(KERN_INFO "OutStreamHostBufferAllocate succeded\n");
+			} else if ( err != 0 && err != HPI_ERROR_INVALID_FUNC ) {
+				snd_printd(KERN_INFO "OutStreamHostBufferAllocate error(%d)\n", err);
+				return err;
+			}
+		} else {
+			snd_printd(KERN_INFO "Cannot estimate minimum bus master buffer size\n");
+		}
+		snd_printd(KERN_INFO "OutStreamHostBufferAllocate status(%d)\n", dpcm->hpi_out_buffer_allocated);
+	}
+
 	snd_printd(KERN_INFO "playback hwparams\n");
 
 	return snd_card_asihpi_pcm_hw_params(substream, params);
@@ -331,6 +362,12 @@
 static int
 snd_card_asihpi_playback_hw_free(snd_pcm_substream_t * substream)
 {
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
+	if ( dpcm->hpi_out_buffer_allocated ) {
+		HPI_OutStreamHostBufferFree( phSubSys, dpcm->hStream );
+	}
+
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
@@ -565,6 +602,7 @@
 	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
 	int err;
 	HW16 wFormat;
+	HW32 minBufSize;
 
 	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params))) < 0)
 		return err;
@@ -588,6 +626,31 @@
 	dpcm->Data.dwpbData = (HW32) runtime->dma_area;
 	dpcm->Data.dwDataSize = MAX_BUFFER_SIZE;
 
+	if (enable_bbm) {
+		dpcm->hpi_in_buffer_allocated = 0;
+		minBufSize = 0;
+
+		err = HPI_StreamEstimateBufferSize( &dpcm->Data.Format, (HW32)( 1000 / HZ ), &minBufSize );
+		snd_printd(KERN_INFO "OutStreamHostBuffer estimated size: %d bytes\n", (int)minBufSize);
+
+		if ( minBufSize < MAX_BUFFER_SIZE ) /* paranoia check */
+			minBufSize = MAX_BUFFER_SIZE;
+
+		if ( err == 0 ) {
+			err = HPI_InStreamHostBufferAllocate( phSubSys, dpcm->hStream, minBufSize );
+			if ( err == 0 ) {
+				dpcm->hpi_in_buffer_allocated = minBufSize;
+				snd_printd(KERN_INFO "InStreamHostBufferAllocate succeded");
+			} else if ( err != 0 && err != HPI_ERROR_INVALID_FUNC ) {
+				snd_printd(KERN_INFO "InStreamHostBufferAllocate error(%d)", err);
+				return err;
+			}
+		} else {
+			snd_printd(KERN_INFO "Cannot estimate minimum bus master buffer size\n");
+		}
+		snd_printd(KERN_INFO "InStreamHostBufferAllocate status(%d)", dpcm->hpi_in_buffer_allocated);
+	}
+
 	snd_printd(KERN_INFO "Capture hwparams\n");
 
 	return snd_card_asihpi_pcm_hw_params(substream, params);
@@ -595,6 +658,12 @@
 
 static int snd_card_asihpi_capture_hw_free(snd_pcm_substream_t * substream)
 {
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
+	if ( dpcm->hpi_in_buffer_allocated ) {
+		HPI_InStreamHostBufferFree( phSubSys, dpcm->hStream );
+	}
+
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
@@ -784,10 +853,21 @@
 	HW16 wSrcNodeIndex;
 	HW16 wDstNodeType;
 	HW16 wDstNodeIndex;
+	HW16 wBand;
 } hpi_control_t;
 
 #define TEXT(a) a
 
+#define ASIHPI_TUNER_BAND_STRINGS \
+{ \
+	TEXT("invalid"), \
+	TEXT("AM"), \
+	TEXT("FM (mono)"), \
+	TEXT("TV"), \
+	TEXT("FM (stereo)"), \
+	TEXT("AUX") \
+}
+
 #ifdef ASI_STYLE_NAMES
 #define ASIHPI_SOURCENODE_STRINGS \
 { \
@@ -845,17 +925,41 @@
 #endif
 #define NUM_DESTNODE_STRINGS 7
 
-#if ( (NUM_SOURCENODE_STRINGS < (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) ||
-(NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
+#if ( (NUM_SOURCENODE_STRINGS < (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) || (NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
 #error "Fewer node strings than #defines - new HPI?"
 #endif
-#if ( (NUM_SOURCENODE_STRINGS > (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) ||
-(NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
+#if ( (NUM_SOURCENODE_STRINGS > (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) || (NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
 #warning "More Node strings than HPI defines - old HPI?"
 #endif
 
 static char *asihpi_src_names[] = ASIHPI_SOURCENODE_STRINGS;
 static char *asihpi_dst_names[] = ASIHPI_DESTNODE_STRINGS;
+static char *asihpi_tuner_band_names[] = ASIHPI_TUNER_BAND_STRINGS;
+
+inline int ctl_add( snd_card_t * card, snd_kcontrol_new_t * ctl, snd_card_asihpi_t * asihpi ) {
+	int err;
+
+	if ((err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi))) < 0) {
+		return err;
+	} else if (mixer_dump)
+		snd_printk(KERN_INFO "Added %s(%d)\n", ctl->name, ctl->index);
+
+	return 0;
+}
+
+void asihpi_ctl_name_prefix( snd_kcontrol_new_t * snd_control, hpi_control_t * asihpi_control) {
+
+	if (asihpi_control->wDstNodeType)
+		sprintf(snd_control->name, "%s %s%d",
+			asihpi_src_names[asihpi_control->wSrcNodeType],
+			asihpi_dst_names[asihpi_control->wDstNodeType],
+			asihpi_control->wDstNodeIndex + 1);
+	else {
+		strcpy(snd_control->name,
+		       asihpi_src_names[asihpi_control->wSrcNodeType]);
+	}
+
+}
 
 /*------------------------------------------------------------
    Volume controls
@@ -1030,6 +1134,480 @@
 }
 
 /*------------------------------------------------------------
+   AESEBU controls
+ ------------------------------------------------------------*/
+
+/* AESEBU format */
+
+#define ASIHPI_AESEBU_FORMAT_STRINGS \
+{ \
+	TEXT("No signal"), \
+	TEXT("S/PDIF"), \
+	TEXT("AES/EBU"), \
+}
+
+static char *asihpi_aesebu_format_names[] = ASIHPI_AESEBU_FORMAT_STRINGS;
+
+static int snd_asihpi_aesebu_format_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+
+	strcpy( uinfo->value.enumerated.name, 
+		asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_format_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol,
+				 HW16 (*func)( HPI_HSUBSYS*, HPI_HCONTROL, HW16* ) )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 source;
+
+	snd_runtime_check( func(phSubSys, hControl, &source) != 0 , return -EINVAL );
+
+	/* default to S/PDIF */
+	ucontrol->value.enumerated.item[0] = 0;
+	if ( source == HPI_AESEBU_SOURCE_SPDIF )
+		ucontrol->value.enumerated.item[0] = 1;
+	if ( source == HPI_AESEBU_SOURCE_AESEBU )
+		ucontrol->value.enumerated.item[0] = 2;
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_format_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol,
+				 HW16 (*func)( HPI_HSUBSYS*, HPI_HCONTROL, HW16 ) )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	/* default to S/PDIF */
+	HW16 source = HPI_AESEBU_SOURCE_SPDIF;
+
+	if ( ucontrol->value.enumerated.item[0] == 1 )
+		source = HPI_AESEBU_SOURCE_SPDIF;
+	if ( ucontrol->value.enumerated.item[0] == 2 )
+		source = HPI_AESEBU_SOURCE_AESEBU;
+
+	snd_runtime_check( func(phSubSys, hControl, source) != 0, return -EINVAL );
+
+	return 1;
+}
+
+static int snd_asihpi_aesebu_rx_source_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_get( kcontrol, ucontrol, HPI_AESEBU_Receiver_GetSource );
+}
+
+static int snd_asihpi_aesebu_rx_source_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_put( kcontrol, ucontrol, HPI_AESEBU_Receiver_SetSource );
+}
+
+static int snd_asihpi_aesebu_tx_format_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_get( kcontrol, ucontrol, HPI_AESEBU_Transmitter_GetFormat );
+}
+
+static int snd_asihpi_aesebu_tx_format_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_put( kcontrol, ucontrol, HPI_AESEBU_Transmitter_SetFormat );
+}
+
+/* TX clock source */
+
+#define ASIHPI_AESEBU_CLOCKSOURCE_STRINGS \
+{ \
+	TEXT("Adapter"), \
+	TEXT("AES/EBU sync"), \
+}
+
+static char *asihpi_aesebu_clocksource_names[] = ASIHPI_AESEBU_CLOCKSOURCE_STRINGS;
+
+static int snd_asihpi_aesebu_tx_clocksource_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+
+	strcpy( uinfo->value.enumerated.name, 
+		asihpi_aesebu_clocksource_names[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_tx_clocksource_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 sync;
+
+	snd_runtime_check( HPI_AESEBU_Transmitter_GetClockSource(phSubSys, hControl, &sync) );
+
+	/* default to HPI_AESEBU_CLOCKSOURCE_ADAPTER */
+	ucontrol->value.enumerated.item[0] = 0;
+	if ( sync == HPI_AESEBU_CLOCKSOURCE_ADAPTER )
+		ucontrol->value.enumerated.item[0] = 0;
+	if ( sync == HPI_AESEBU_CLOCKSOURCE_AESEBU_SYNC )
+		ucontrol->value.enumerated.item[0] = 1;
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_tx_clocksource_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	/* default to AES/EBU sync */
+	HW16 sync = HPI_AESEBU_CLOCKSOURCE_AESEBU_SYNC;
+
+	if ( ucontrol->value.enumerated.item[0] == 0 )
+		sync = HPI_AESEBU_CLOCKSOURCE_ADAPTER;
+	if ( ucontrol->value.enumerated.item[0] == 1 )
+		sync = HPI_AESEBU_CLOCKSOURCE_AESEBU_SYNC;
+
+	snd_runtime_check( HPI_AESEBU_Transmitter_SetClockSource(phSubSys, hControl, sync) != 0, return -EINVAL );
+
+	return 1;
+}
+
+
+/* AESEBU control group initializers  */
+
+static int __init snd_asihpi_aesebu_rx_new(snd_card_asihpi_t * asihpi, hpi_control_t * asihpi_control,
+					snd_kcontrol_new_t * snd_control)
+{
+
+	snd_card_t *card = asihpi->card;
+
+/* RX source */
+
+	snd_control->info = snd_asihpi_aesebu_format_info;
+	snd_control->get = snd_asihpi_aesebu_rx_source_get;
+	snd_control->put = snd_asihpi_aesebu_rx_source_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Source");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) >= 0, return -EINVAL );
+
+	return 0;
+}
+
+static int __init snd_asihpi_aesebu_tx_new(snd_card_asihpi_t * asihpi, hpi_control_t * asihpi_control,
+					snd_kcontrol_new_t * snd_control)
+{
+
+	snd_card_t *card = asihpi->card;
+
+/* TX Format */
+
+	snd_control->info = snd_asihpi_aesebu_format_info;
+	snd_control->get = snd_asihpi_aesebu_tx_format_get;
+	snd_control->put = snd_asihpi_aesebu_tx_format_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Format");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) >= 0, return -EINVAL );
+
+/* TX Sample rate source*/
+
+	snd_control->info = snd_asihpi_aesebu_tx_clocksource_info;
+	snd_control->get = snd_asihpi_aesebu_tx_clocksource_get;
+	snd_control->put = snd_asihpi_aesebu_tx_clocksource_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Clock Source");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) >= 0, return -EINVAL );
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+   Tuner controls
+ ------------------------------------------------------------*/
+
+/* Gain */
+
+static int snd_asihpi_tuner_gain_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 err;
+	short idx;
+        HW32 gainRange[3];
+
+	for (idx = 0; idx < 3; idx++) {
+        	err = HPI_ControlQuery( phSubSys, hControl, HPI_TUNER_GAIN, idx, 0, &gainRange[idx] );
+		if (err != 0) return err;
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = ( (int)gainRange[0] ) / HPI_UNITS_PER_dB;
+	uinfo->value.integer.max = ( (int)gainRange[1] ) / HPI_UNITS_PER_dB;
+	uinfo->value.integer.step = ( (int) gainRange[2] ) / HPI_UNITS_PER_dB;
+	return 0;
+}
+
+static int snd_asihpi_tuner_gain_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	short gain;
+
+	HPI_Tuner_GetGain(phSubSys, hControl, &gain);
+	ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_gain_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	short gain;
+
+	gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
+	HPI_Tuner_SetGain(phSubSys, hControl, gain);
+
+	return 1;
+}
+
+/* Band  */
+
+static int asihpi_tuner_band_query( snd_kcontrol_t * kcontrol, HW32 * bandList, HW32 len ) {
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 err;
+	HW32 idx;
+
+	for (idx=0; idx < len; idx++) {
+		err = HPI_ControlQuery( phSubSys, hControl , HPI_TUNER_BAND, idx, 0 , &bandList[idx]);
+		if (err !=0) break;
+	}
+
+	return idx;
+}
+
+static int snd_asihpi_tuner_band_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0;
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = numBands;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+
+	strcpy( uinfo->value.enumerated.name, 
+		asihpi_tuner_band_names[tunerBands[uinfo->value.enumerated.item]]);
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_band_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HW16 band, idx;
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0;
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	HPI_Tuner_GetBand(phSubSys, hControl, &band);
+
+	ucontrol->value.enumerated.item[0] = -1;
+	for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
+		if ( tunerBands[ idx ] == band ) {
+			ucontrol->value.enumerated.item[0] = idx;
+			break;
+		}
+
+	snd_runtime_check( ucontrol->value.enumerated.item[0] >= 0, return -EINVAL );
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_band_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 band;
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0;
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	band = tunerBands[ucontrol->value.enumerated.item[0]];
+	HPI_Tuner_SetBand(phSubSys, hControl, band);
+
+	return 1;
+}
+
+/* Freq */
+
+static int snd_asihpi_tuner_freq_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 err;
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0, band_iter, idx;
+	HW32 freqRange[3], tempFreqRange[3];
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	freqRange[0] = INT_MAX;
+	freqRange[1] = 0;
+	freqRange[2] = INT_MAX;
+
+	for ( band_iter = 0; band_iter < numBands; band_iter++ ) {
+		for (idx = 0; idx < 3; idx++) {
+        		err = HPI_ControlQuery( phSubSys, hControl, HPI_TUNER_FREQ, idx, tunerBands[band_iter], &tempFreqRange[idx] );
+			if (err != 0) return err;
+		}
+
+		/* skip band with bogus stepping */
+		if ( tempFreqRange[2] <= 0 )
+			continue;
+
+		if ( tempFreqRange[0] < freqRange[0] )
+			freqRange[0] = tempFreqRange[0];
+		if ( tempFreqRange[1] > freqRange[1] )
+			freqRange[1] = tempFreqRange[1];
+		if ( tempFreqRange[2] < freqRange[2] )
+			freqRange[2] = tempFreqRange[2];
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = ( (int)freqRange[0] );
+	uinfo->value.integer.max = ( (int)freqRange[1] );
+	uinfo->value.integer.step = ( (int)freqRange[2] );
+	return 0;
+}
+
+static int snd_asihpi_tuner_freq_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW32 freq;
+
+	spin_lock_irqsave(&asihpi->mixer_lock, flags);
+	HPI_Tuner_GetFrequency(phSubSys, hControl, &freq);
+	ucontrol->value.integer.value[0] = freq;
+	spin_unlock_irqrestore(&asihpi->mixer_lock, flags);
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_freq_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW32 freq;
+
+	freq = ucontrol->value.integer.value[0];
+	spin_lock_irqsave(&asihpi->mixer_lock, flags);
+	HPI_Tuner_SetFrequency(phSubSys, hControl, freq);
+	spin_unlock_irqrestore(&asihpi->mixer_lock, flags);
+
+	return 1;
+}
+
+/* Tuner control group initializer  */
+
+static int __init snd_asihpi_tuner_new(snd_card_asihpi_t * asihpi, hpi_control_t * asihpi_control,
+					snd_kcontrol_new_t * snd_control)
+{
+
+	snd_card_t *card = asihpi->card;
+
+/* Gain ctl */
+
+	snd_control->info = snd_asihpi_tuner_gain_info;
+	snd_control->get = snd_asihpi_tuner_gain_get;
+	snd_control->put = snd_asihpi_tuner_gain_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Gain");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) != 0, return -EINVAL );
+
+/* Band ctl */
+
+	snd_control->info = snd_asihpi_tuner_band_info;
+	snd_control->get = snd_asihpi_tuner_band_get;
+	snd_control->put = snd_asihpi_tuner_band_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Band");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) != 0, return -EINVAL );
+
+/* Freq ctl */
+
+	snd_control->info = snd_asihpi_tuner_freq_info;
+	snd_control->get = snd_asihpi_tuner_freq_get;
+	snd_control->put = snd_asihpi_tuner_freq_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Freq");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) != 0, return -EINVAL );
+
+/* Level meter */
+
+	return 0;
+}
+
+
+/*------------------------------------------------------------
    Meter controls
  ------------------------------------------------------------*/
 static int snd_asihpi_meter_info(snd_kcontrol_t * kcontrol,
@@ -1437,6 +2015,7 @@
 /*------------------------------------------------------------
    Mixer
  ------------------------------------------------------------*/
+
 static int __init snd_card_asihpi_new_mixer(snd_card_asihpi_t * asihpi)
 {
 	snd_card_t *card = asihpi->card;
@@ -1525,10 +2104,19 @@
 			break;
 		case HPI_CONTROL_CONNECTION:	// ignore these
 			continue;
-		case HPI_CONTROL_MUTE:
+		case HPI_CONTROL_TUNER:
+			snd_runtime_check( snd_asihpi_tuner_new(asihpi, &asihpi_control,
+					     &snd_control) >= 0, return -EINVAL );
+			continue;
 		case HPI_CONTROL_AESEBU_TRANSMITTER:
+			snd_runtime_check( snd_asihpi_aesebu_tx_new(asihpi, &asihpi_control,
+					     &snd_control) >= 0, return -EINVAL );
+			continue;
 		case HPI_CONTROL_AESEBU_RECEIVER:
-		case HPI_CONTROL_TUNER:
+			snd_runtime_check( snd_asihpi_aesebu_rx_new(asihpi, &asihpi_control,
+					     &snd_control) >= 0, return -EINVAL );
+			continue;
+		case HPI_CONTROL_MUTE:
 		case HPI_CONTROL_ONOFFSWITCH:
 		case HPI_CONTROL_VOX:
 		case HPI_CONTROL_BITSTREAM:


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] asihpi driver, adds tuner controls, AESEBU controls, bus master support where available
  2005-07-28  5:17 [PATCH] asihpi driver, adds tuner controls, AESEBU controls, bus master support where available Delio Brignoli
@ 2005-07-28  9:20 ` Takashi Iwai
  0 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2005-07-28  9:20 UTC (permalink / raw)
  To: dbrignoli; +Cc: alsa-devel

At Wed, 27 Jul 2005 22:17:54 -0700,
Delio Brignoli wrote:
> 
> Hello,
> 
> > RETURN_IF_NEG() is a bit ugly.  In your code, it's not clear whether
> > this is for a debug purpose or for checking a critical error.
> > 
> > If it's just a check, you can use snd_assert().  Otherwise, a plain
> > if() would be easier to read.
> > 
> > Could you rewrite that stuff?
> 
> I've used snd_runtime_check ( thanks for pointing me at it )

Thanks.

I found other subtle things in the new patch.

  inline int ctl_add( snd_card_t * card, snd_kcontrol_new_t * ctl, snd_card_asihpi_t * asihpi ) {

should be static inline.

  void asihpi_ctl_name_prefix( snd_kcontrol_new_t * snd_control, hpi_control_t * asihpi_control) {

should be static, too.


> I'm attaching a new patch with some extra features:
> 
> Thu Jul 28 17:03:28 NZST 2005  dbrignoli@audioscience.com
>   * added_enable_bbm_module_param
> Thu Jul 28 16:50:46 NZST 2005  dbrignoli@audioscience.com
>   * use_alsa_debug_assertions_and_printd
> Tue Jul 26 18:15:11 NZST 2005  dbrignoli@audioscience.com
>   * fixed_bus_master_buffer_size_calculation
> Tue Jul 26 18:13:50 NZST 2005  dbrignoli@audioscience.com
>   * fixed_HPI_error_handling_macro_to_include_filename
> Fri Jul 22 16:37:16 NZST 2005  dbrignoli@audioscience.com
>   * add AESEBU controls to alsa mixer
> Fri Jul 22 12:33:22 NZST 2005  dbrignoli@audioscience.com
>   * enable_HPI_stream_host_buffers_if_supported
> Thu Jul 21 16:03:58 NZST 2005  dbrignoli@audioscience.com
>   * add_tuner_controls

Please put a full changelog to commit, and add signed-off-by line?


thanks,

Takashi


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO September
19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] asihpi driver, adds tuner controls, AESEBU controls, bus master support where available
@ 2005-07-28 21:59 Delio Brignoli
  2005-07-29 10:37 ` Takashi Iwai
  0 siblings, 1 reply; 4+ messages in thread
From: Delio Brignoli @ 2005-07-28 21:59 UTC (permalink / raw)
  To: tiwai; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 518 bytes --]

> I found other subtle things in the new patch.
[...]

I've made them both static.

> Please put a full changelog to commit, and add signed-off-by line?

Changelog:
*added Gain, Frequency, band tuner mixer controls.
*added AESEBU, S/P DIF format and clocksource mixer controls.
*use bus master, if available, for pcm playback and capture.
*added enable_bbm module param (defaults to true).

signed-off-by: Delio Brignoli dbrignoli@audioscience.com

grazie, ciao
--
Delio Brignoli


[-- Attachment #2: patch.txt --]
[-- Type: application/octet-stream, Size: 22852 bytes --]

diff -rN -u old-alsa-driver-1.0.9b-rep/pci/asihpi.c new-alsa-driver-1.0.9b-rep/pci/asihpi.c
--- old-alsa-driver-1.0.9b-rep/pci/asihpi.c	2005-07-29 09:32:34.000000000 +1200
+++ new-alsa-driver-1.0.9b-rep/pci/asihpi.c	2005-07-29 09:05:04.000000000 +1200
@@ -57,6 +57,9 @@
 module_param(adapter_fs, int, 0444);
 MODULE_PARM_DESC(adapter_fs, "Adapter HW samplerate (if supported)");
 
+static int enable_bbm = 1;
+module_param(enable_bbm, int, 0444);
+MODULE_PARM_DESC(enable_bbm, "Enable background bus master, if available");
 
 MODULE_AUTHOR("Eliot Blennerhassett <EBlennerhassett@audioscience.com>");
 MODULE_DESCRIPTION("AudioScience soundcard (HPI)");
@@ -92,6 +95,8 @@
 	snd_card_asihpi_t *asihpi;
 	spinlock_t lock;
 	struct timer_list timer;
+	unsigned int hpi_in_buffer_allocated;
+	unsigned int hpi_out_buffer_allocated;
 	unsigned int pcm_size;
 	unsigned int pcm_count;
 	unsigned int pcm_jiffie_per_period;
@@ -107,17 +112,17 @@
 static HPI_HSUBSYS *phSubSys;	/* handle to HPI audio subsystem */
 static snd_card_t *snd_asihpi_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
-static void _HandleError(HW16 err, int line)
+static void _HandleError(HW16 err, int line, char *filename)
 {
 	char ErrorText[80];
 
 	if (err) {
 		HPI_GetErrorText(err, ErrorText);
-		printk(KERN_WARNING "line %d: %s\n", line, ErrorText);
+		printk(KERN_WARNING "in file %s, line %d: %s\n", filename, line, ErrorText);
 	}
 }
 
-#define HPI_HandleError(x)  _HandleError(x,__LINE__)
+#define HPI_HandleError(x)  _HandleError(x,__LINE__,__FILE__)
 /***************************** GENERAL PCM ****************/
 static int snd_card_asihpi_pcm_hw_params(snd_pcm_substream_t * substream,
 					 snd_pcm_hw_params_t * params)
@@ -305,6 +310,7 @@
 	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
 	int err;
 	HW16 wFormat;
+	HW32 minBufSize;
 
 	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params))) < 0)
 		return err;
@@ -323,6 +329,31 @@
 	dpcm->Data.dwpbData = (HW32) runtime->dma_area;
 	dpcm->Data.dwDataSize = MAX_BUFFER_SIZE;
 
+	if (enable_bbm) {
+		dpcm->hpi_out_buffer_allocated = 0;
+		minBufSize = 0;
+
+		err = HPI_StreamEstimateBufferSize( &dpcm->Data.Format, (HW32)( 1000 / HZ ), &minBufSize );
+		snd_printd(KERN_INFO "OutStreamHostBuffer estimated size: %d bytes\n", (int)minBufSize);
+
+		if ( minBufSize < MAX_BUFFER_SIZE )
+			minBufSize = MAX_BUFFER_SIZE;
+
+		if ( err == 0 ) {
+			err = HPI_OutStreamHostBufferAllocate( phSubSys, dpcm->hStream, minBufSize );
+			if ( err == 0 ) {
+				dpcm->hpi_out_buffer_allocated = minBufSize;
+				snd_printd(KERN_INFO "OutStreamHostBufferAllocate succeded\n");
+			} else if ( err != 0 && err != HPI_ERROR_INVALID_FUNC ) {
+				snd_printd(KERN_INFO "OutStreamHostBufferAllocate error(%d)\n", err);
+				return err;
+			}
+		} else {
+			snd_printd(KERN_INFO "Cannot estimate minimum bus master buffer size\n");
+		}
+		snd_printd(KERN_INFO "OutStreamHostBufferAllocate status(%d)\n", dpcm->hpi_out_buffer_allocated);
+	}
+
 	snd_printd(KERN_INFO "playback hwparams\n");
 
 	return snd_card_asihpi_pcm_hw_params(substream, params);
@@ -331,6 +362,12 @@
 static int
 snd_card_asihpi_playback_hw_free(snd_pcm_substream_t * substream)
 {
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
+	if ( dpcm->hpi_out_buffer_allocated ) {
+		HPI_OutStreamHostBufferFree( phSubSys, dpcm->hStream );
+	}
+
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
@@ -565,6 +602,7 @@
 	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
 	int err;
 	HW16 wFormat;
+	HW32 minBufSize;
 
 	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params))) < 0)
 		return err;
@@ -588,6 +626,31 @@
 	dpcm->Data.dwpbData = (HW32) runtime->dma_area;
 	dpcm->Data.dwDataSize = MAX_BUFFER_SIZE;
 
+	if (enable_bbm) {
+		dpcm->hpi_in_buffer_allocated = 0;
+		minBufSize = 0;
+
+		err = HPI_StreamEstimateBufferSize( &dpcm->Data.Format, (HW32)( 1000 / HZ ), &minBufSize );
+		snd_printd(KERN_INFO "OutStreamHostBuffer estimated size: %d bytes\n", (int)minBufSize);
+
+		if ( minBufSize < MAX_BUFFER_SIZE ) /* paranoia check */
+			minBufSize = MAX_BUFFER_SIZE;
+
+		if ( err == 0 ) {
+			err = HPI_InStreamHostBufferAllocate( phSubSys, dpcm->hStream, minBufSize );
+			if ( err == 0 ) {
+				dpcm->hpi_in_buffer_allocated = minBufSize;
+				snd_printd(KERN_INFO "InStreamHostBufferAllocate succeded");
+			} else if ( err != 0 && err != HPI_ERROR_INVALID_FUNC ) {
+				snd_printd(KERN_INFO "InStreamHostBufferAllocate error(%d)", err);
+				return err;
+			}
+		} else {
+			snd_printd(KERN_INFO "Cannot estimate minimum bus master buffer size\n");
+		}
+		snd_printd(KERN_INFO "InStreamHostBufferAllocate status(%d)", dpcm->hpi_in_buffer_allocated);
+	}
+
 	snd_printd(KERN_INFO "Capture hwparams\n");
 
 	return snd_card_asihpi_pcm_hw_params(substream, params);
@@ -595,6 +658,12 @@
 
 static int snd_card_asihpi_capture_hw_free(snd_pcm_substream_t * substream)
 {
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_asihpi_pcm_t *dpcm = runtime->private_data;
+	if ( dpcm->hpi_in_buffer_allocated ) {
+		HPI_InStreamHostBufferFree( phSubSys, dpcm->hStream );
+	}
+
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
@@ -784,10 +853,21 @@
 	HW16 wSrcNodeIndex;
 	HW16 wDstNodeType;
 	HW16 wDstNodeIndex;
+	HW16 wBand;
 } hpi_control_t;
 
 #define TEXT(a) a
 
+#define ASIHPI_TUNER_BAND_STRINGS \
+{ \
+	TEXT("invalid"), \
+	TEXT("AM"), \
+	TEXT("FM (mono)"), \
+	TEXT("TV"), \
+	TEXT("FM (stereo)"), \
+	TEXT("AUX") \
+}
+
 #ifdef ASI_STYLE_NAMES
 #define ASIHPI_SOURCENODE_STRINGS \
 { \
@@ -845,17 +925,41 @@
 #endif
 #define NUM_DESTNODE_STRINGS 7
 
-#if ( (NUM_SOURCENODE_STRINGS < (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) ||
-(NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
+#if ( (NUM_SOURCENODE_STRINGS < (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) || (NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
 #error "Fewer node strings than #defines - new HPI?"
 #endif
-#if ( (NUM_SOURCENODE_STRINGS > (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) ||
-(NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
+#if ( (NUM_SOURCENODE_STRINGS > (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)) || (NUM_DESTNODE_STRINGS < (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)))
 #warning "More Node strings than HPI defines - old HPI?"
 #endif
 
 static char *asihpi_src_names[] = ASIHPI_SOURCENODE_STRINGS;
 static char *asihpi_dst_names[] = ASIHPI_DESTNODE_STRINGS;
+static char *asihpi_tuner_band_names[] = ASIHPI_TUNER_BAND_STRINGS;
+
+static inline int ctl_add( snd_card_t * card, snd_kcontrol_new_t * ctl, snd_card_asihpi_t * asihpi ) {
+	int err;
+
+	if ((err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi))) < 0) {
+		return err;
+	} else if (mixer_dump)
+		snd_printk(KERN_INFO "Added %s(%d)\n", ctl->name, ctl->index);
+
+	return 0;
+}
+
+static void asihpi_ctl_name_prefix( snd_kcontrol_new_t * snd_control, hpi_control_t * asihpi_control) {
+
+	if (asihpi_control->wDstNodeType)
+		sprintf(snd_control->name, "%s %s%d",
+			asihpi_src_names[asihpi_control->wSrcNodeType],
+			asihpi_dst_names[asihpi_control->wDstNodeType],
+			asihpi_control->wDstNodeIndex + 1);
+	else {
+		strcpy(snd_control->name,
+		       asihpi_src_names[asihpi_control->wSrcNodeType]);
+	}
+
+}
 
 /*------------------------------------------------------------
    Volume controls
@@ -1030,6 +1134,480 @@
 }
 
 /*------------------------------------------------------------
+   AESEBU controls
+ ------------------------------------------------------------*/
+
+/* AESEBU format */
+
+#define ASIHPI_AESEBU_FORMAT_STRINGS \
+{ \
+	TEXT("No signal"), \
+	TEXT("S/PDIF"), \
+	TEXT("AES/EBU"), \
+}
+
+static char *asihpi_aesebu_format_names[] = ASIHPI_AESEBU_FORMAT_STRINGS;
+
+static int snd_asihpi_aesebu_format_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+
+	strcpy( uinfo->value.enumerated.name, 
+		asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_format_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol,
+				 HW16 (*func)( HPI_HSUBSYS*, HPI_HCONTROL, HW16* ) )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 source;
+
+	snd_runtime_check( func(phSubSys, hControl, &source) != 0 , return -EINVAL );
+
+	/* default to S/PDIF */
+	ucontrol->value.enumerated.item[0] = 0;
+	if ( source == HPI_AESEBU_SOURCE_SPDIF )
+		ucontrol->value.enumerated.item[0] = 1;
+	if ( source == HPI_AESEBU_SOURCE_AESEBU )
+		ucontrol->value.enumerated.item[0] = 2;
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_format_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol,
+				 HW16 (*func)( HPI_HSUBSYS*, HPI_HCONTROL, HW16 ) )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	/* default to S/PDIF */
+	HW16 source = HPI_AESEBU_SOURCE_SPDIF;
+
+	if ( ucontrol->value.enumerated.item[0] == 1 )
+		source = HPI_AESEBU_SOURCE_SPDIF;
+	if ( ucontrol->value.enumerated.item[0] == 2 )
+		source = HPI_AESEBU_SOURCE_AESEBU;
+
+	snd_runtime_check( func(phSubSys, hControl, source) != 0, return -EINVAL );
+
+	return 1;
+}
+
+static int snd_asihpi_aesebu_rx_source_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_get( kcontrol, ucontrol, HPI_AESEBU_Receiver_GetSource );
+}
+
+static int snd_asihpi_aesebu_rx_source_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_put( kcontrol, ucontrol, HPI_AESEBU_Receiver_SetSource );
+}
+
+static int snd_asihpi_aesebu_tx_format_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_get( kcontrol, ucontrol, HPI_AESEBU_Transmitter_GetFormat );
+}
+
+static int snd_asihpi_aesebu_tx_format_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol) {
+	return snd_asihpi_aesebu_format_put( kcontrol, ucontrol, HPI_AESEBU_Transmitter_SetFormat );
+}
+
+/* TX clock source */
+
+#define ASIHPI_AESEBU_CLOCKSOURCE_STRINGS \
+{ \
+	TEXT("Adapter"), \
+	TEXT("AES/EBU sync"), \
+}
+
+static char *asihpi_aesebu_clocksource_names[] = ASIHPI_AESEBU_CLOCKSOURCE_STRINGS;
+
+static int snd_asihpi_aesebu_tx_clocksource_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+
+	strcpy( uinfo->value.enumerated.name, 
+		asihpi_aesebu_clocksource_names[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_tx_clocksource_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 sync;
+
+	snd_runtime_check( HPI_AESEBU_Transmitter_GetClockSource(phSubSys, hControl, &sync) );
+
+	/* default to HPI_AESEBU_CLOCKSOURCE_ADAPTER */
+	ucontrol->value.enumerated.item[0] = 0;
+	if ( sync == HPI_AESEBU_CLOCKSOURCE_ADAPTER )
+		ucontrol->value.enumerated.item[0] = 0;
+	if ( sync == HPI_AESEBU_CLOCKSOURCE_AESEBU_SYNC )
+		ucontrol->value.enumerated.item[0] = 1;
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_tx_clocksource_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol )
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	/* default to AES/EBU sync */
+	HW16 sync = HPI_AESEBU_CLOCKSOURCE_AESEBU_SYNC;
+
+	if ( ucontrol->value.enumerated.item[0] == 0 )
+		sync = HPI_AESEBU_CLOCKSOURCE_ADAPTER;
+	if ( ucontrol->value.enumerated.item[0] == 1 )
+		sync = HPI_AESEBU_CLOCKSOURCE_AESEBU_SYNC;
+
+	snd_runtime_check( HPI_AESEBU_Transmitter_SetClockSource(phSubSys, hControl, sync) != 0, return -EINVAL );
+
+	return 1;
+}
+
+
+/* AESEBU control group initializers  */
+
+static int __init snd_asihpi_aesebu_rx_new(snd_card_asihpi_t * asihpi, hpi_control_t * asihpi_control,
+					snd_kcontrol_new_t * snd_control)
+{
+
+	snd_card_t *card = asihpi->card;
+
+/* RX source */
+
+	snd_control->info = snd_asihpi_aesebu_format_info;
+	snd_control->get = snd_asihpi_aesebu_rx_source_get;
+	snd_control->put = snd_asihpi_aesebu_rx_source_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Source");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) >= 0, return -EINVAL );
+
+	return 0;
+}
+
+static int __init snd_asihpi_aesebu_tx_new(snd_card_asihpi_t * asihpi, hpi_control_t * asihpi_control,
+					snd_kcontrol_new_t * snd_control)
+{
+
+	snd_card_t *card = asihpi->card;
+
+/* TX Format */
+
+	snd_control->info = snd_asihpi_aesebu_format_info;
+	snd_control->get = snd_asihpi_aesebu_tx_format_get;
+	snd_control->put = snd_asihpi_aesebu_tx_format_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Format");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) >= 0, return -EINVAL );
+
+/* TX Sample rate source*/
+
+	snd_control->info = snd_asihpi_aesebu_tx_clocksource_info;
+	snd_control->get = snd_asihpi_aesebu_tx_clocksource_get;
+	snd_control->put = snd_asihpi_aesebu_tx_clocksource_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Clock Source");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) >= 0, return -EINVAL );
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+   Tuner controls
+ ------------------------------------------------------------*/
+
+/* Gain */
+
+static int snd_asihpi_tuner_gain_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 err;
+	short idx;
+        HW32 gainRange[3];
+
+	for (idx = 0; idx < 3; idx++) {
+        	err = HPI_ControlQuery( phSubSys, hControl, HPI_TUNER_GAIN, idx, 0, &gainRange[idx] );
+		if (err != 0) return err;
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = ( (int)gainRange[0] ) / HPI_UNITS_PER_dB;
+	uinfo->value.integer.max = ( (int)gainRange[1] ) / HPI_UNITS_PER_dB;
+	uinfo->value.integer.step = ( (int) gainRange[2] ) / HPI_UNITS_PER_dB;
+	return 0;
+}
+
+static int snd_asihpi_tuner_gain_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	short gain;
+
+	HPI_Tuner_GetGain(phSubSys, hControl, &gain);
+	ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_gain_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	short gain;
+
+	gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
+	HPI_Tuner_SetGain(phSubSys, hControl, gain);
+
+	return 1;
+}
+
+/* Band  */
+
+static int asihpi_tuner_band_query( snd_kcontrol_t * kcontrol, HW32 * bandList, HW32 len ) {
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 err;
+	HW32 idx;
+
+	for (idx=0; idx < len; idx++) {
+		err = HPI_ControlQuery( phSubSys, hControl , HPI_TUNER_BAND, idx, 0 , &bandList[idx]);
+		if (err !=0) break;
+	}
+
+	return idx;
+}
+
+static int snd_asihpi_tuner_band_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0;
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = numBands;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+
+	strcpy( uinfo->value.enumerated.name, 
+		asihpi_tuner_band_names[tunerBands[uinfo->value.enumerated.item]]);
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_band_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HW16 band, idx;
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0;
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	HPI_Tuner_GetBand(phSubSys, hControl, &band);
+
+	ucontrol->value.enumerated.item[0] = -1;
+	for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
+		if ( tunerBands[ idx ] == band ) {
+			ucontrol->value.enumerated.item[0] = idx;
+			break;
+		}
+
+	snd_runtime_check( ucontrol->value.enumerated.item[0] >= 0, return -EINVAL );
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_band_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	/*
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	*/
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 band;
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0;
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	band = tunerBands[ucontrol->value.enumerated.item[0]];
+	HPI_Tuner_SetBand(phSubSys, hControl, band);
+
+	return 1;
+}
+
+/* Freq */
+
+static int snd_asihpi_tuner_freq_info(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW16 err;
+        HW32 tunerBands[HPI_TUNER_BAND_LAST];
+	HW32 numBands = 0, band_iter, idx;
+	HW32 freqRange[3], tempFreqRange[3];
+
+        numBands = asihpi_tuner_band_query( kcontrol, tunerBands, HPI_TUNER_BAND_LAST );
+
+	freqRange[0] = INT_MAX;
+	freqRange[1] = 0;
+	freqRange[2] = INT_MAX;
+
+	for ( band_iter = 0; band_iter < numBands; band_iter++ ) {
+		for (idx = 0; idx < 3; idx++) {
+        		err = HPI_ControlQuery( phSubSys, hControl, HPI_TUNER_FREQ, idx, tunerBands[band_iter], &tempFreqRange[idx] );
+			if (err != 0) return err;
+		}
+
+		/* skip band with bogus stepping */
+		if ( tempFreqRange[2] <= 0 )
+			continue;
+
+		if ( tempFreqRange[0] < freqRange[0] )
+			freqRange[0] = tempFreqRange[0];
+		if ( tempFreqRange[1] > freqRange[1] )
+			freqRange[1] = tempFreqRange[1];
+		if ( tempFreqRange[2] < freqRange[2] )
+			freqRange[2] = tempFreqRange[2];
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = ( (int)freqRange[0] );
+	uinfo->value.integer.max = ( (int)freqRange[1] );
+	uinfo->value.integer.step = ( (int)freqRange[2] );
+	return 0;
+}
+
+static int snd_asihpi_tuner_freq_get(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW32 freq;
+
+	spin_lock_irqsave(&asihpi->mixer_lock, flags);
+	HPI_Tuner_GetFrequency(phSubSys, hControl, &freq);
+	ucontrol->value.integer.value[0] = freq;
+	spin_unlock_irqrestore(&asihpi->mixer_lock, flags);
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_freq_put(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_asihpi_t *asihpi = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	HPI_HCONTROL hControl = kcontrol->private_value;
+	HW32 freq;
+
+	freq = ucontrol->value.integer.value[0];
+	spin_lock_irqsave(&asihpi->mixer_lock, flags);
+	HPI_Tuner_SetFrequency(phSubSys, hControl, freq);
+	spin_unlock_irqrestore(&asihpi->mixer_lock, flags);
+
+	return 1;
+}
+
+/* Tuner control group initializer  */
+
+static int __init snd_asihpi_tuner_new(snd_card_asihpi_t * asihpi, hpi_control_t * asihpi_control,
+					snd_kcontrol_new_t * snd_control)
+{
+
+	snd_card_t *card = asihpi->card;
+
+/* Gain ctl */
+
+	snd_control->info = snd_asihpi_tuner_gain_info;
+	snd_control->get = snd_asihpi_tuner_gain_get;
+	snd_control->put = snd_asihpi_tuner_gain_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Gain");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) != 0, return -EINVAL );
+
+/* Band ctl */
+
+	snd_control->info = snd_asihpi_tuner_band_info;
+	snd_control->get = snd_asihpi_tuner_band_get;
+	snd_control->put = snd_asihpi_tuner_band_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Band");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) != 0, return -EINVAL );
+
+/* Freq ctl */
+
+	snd_control->info = snd_asihpi_tuner_freq_info;
+	snd_control->get = snd_asihpi_tuner_freq_get;
+	snd_control->put = snd_asihpi_tuner_freq_put;
+	snd_control->index = asihpi_control->wSrcNodeIndex + 1;
+
+	asihpi_ctl_name_prefix( snd_control, asihpi_control );
+	strcat(snd_control->name, " Freq");
+
+	snd_runtime_check( ctl_add( card, snd_control, asihpi ) != 0, return -EINVAL );
+
+/* Level meter */
+
+	return 0;
+}
+
+
+/*------------------------------------------------------------
    Meter controls
  ------------------------------------------------------------*/
 static int snd_asihpi_meter_info(snd_kcontrol_t * kcontrol,
@@ -1437,6 +2015,7 @@
 /*------------------------------------------------------------
    Mixer
  ------------------------------------------------------------*/
+
 static int __init snd_card_asihpi_new_mixer(snd_card_asihpi_t * asihpi)
 {
 	snd_card_t *card = asihpi->card;
@@ -1525,10 +2104,19 @@
 			break;
 		case HPI_CONTROL_CONNECTION:	// ignore these
 			continue;
-		case HPI_CONTROL_MUTE:
+		case HPI_CONTROL_TUNER:
+			snd_runtime_check( snd_asihpi_tuner_new(asihpi, &asihpi_control,
+					     &snd_control) >= 0, return -EINVAL );
+			continue;
 		case HPI_CONTROL_AESEBU_TRANSMITTER:
+			snd_runtime_check( snd_asihpi_aesebu_tx_new(asihpi, &asihpi_control,
+					     &snd_control) >= 0, return -EINVAL );
+			continue;
 		case HPI_CONTROL_AESEBU_RECEIVER:
-		case HPI_CONTROL_TUNER:
+			snd_runtime_check( snd_asihpi_aesebu_rx_new(asihpi, &asihpi_control,
+					     &snd_control) >= 0, return -EINVAL );
+			continue;
+		case HPI_CONTROL_MUTE:
 		case HPI_CONTROL_ONOFFSWITCH:
 		case HPI_CONTROL_VOX:
 		case HPI_CONTROL_BITSTREAM:


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] asihpi driver, adds tuner controls, AESEBU controls, bus master support where available
  2005-07-28 21:59 Delio Brignoli
@ 2005-07-29 10:37 ` Takashi Iwai
  0 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2005-07-29 10:37 UTC (permalink / raw)
  To: dbrignoli; +Cc: alsa-devel

At Thu, 28 Jul 2005 14:59:45 -0700,
Delio Brignoli wrote:
> 
> > I found other subtle things in the new patch.
> [...]
> 
> I've made them both static.
> 
> > Please put a full changelog to commit, and add signed-off-by line?
> 
> Changelog:
> *added Gain, Frequency, band tuner mixer controls.
> *added AESEBU, S/P DIF format and clocksource mixer controls.
> *use bus master, if available, for pcm playback and capture.
> *added enable_bbm module param (defaults to true).
> 
> signed-off-by: Delio Brignoli dbrignoli@audioscience.com

Thanks, applied to CVS now.


Takashi


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO September
19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-07-29 10:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-07-28  5:17 [PATCH] asihpi driver, adds tuner controls, AESEBU controls, bus master support where available Delio Brignoli
2005-07-28  9:20 ` Takashi Iwai
  -- strict thread matches above, loose matches on Subject: below --
2005-07-28 21:59 Delio Brignoli
2005-07-29 10:37 ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.