* 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.