diff --git a/alsactl/alsactl_lexer.l b/alsactl/alsactl_lexer.l index 3283b3e..a472852 100644 --- a/alsactl/alsactl_lexer.l +++ b/alsactl/alsactl_lexer.l @@ -57,6 +57,19 @@ playback return L_PLAYBACK; record return L_RECORD; output return L_OUTPUT; input return L_INPUT; +iec958ocs return L_IEC958OCS; +3d return L_3D; +reset return L_RESET; +user return L_USER; +valid return L_VALID; +data return L_DATA; +protected return L_PROTECTED; +pre2 return L_PRE2; +fslock return L_FSLOCK; +type return L_TYPE; +gstatus return L_GSTATUS; +enable return L_ENABLE; +disable return L_DISABLE; /* boolean */ diff --git a/alsactl/alsactl_parser.y b/alsactl/alsactl_parser.y index 79a41a3..63395bc 100644 --- a/alsactl/alsactl_parser.y +++ b/alsactl/alsactl_parser.y @@ -60,6 +60,8 @@ static void select_rawmidi_input_switch( char *name ); static void set_switch_boolean( int val ); static void set_switch_integer( int val ); +static void set_switch_iec958ocs_begin( void ); +static void set_switch_iec958ocs( int idx, unsigned short val, unsigned short mask ); /* local variables */ @@ -98,6 +100,8 @@ static void *Xswitch = NULL; /* other keywords */ %token L_SOUNDCARD L_MIXER L_CHANNEL L_STEREO L_MONO L_SWITCH L_RAWDATA %token L_CONTROL L_PCM L_RAWMIDI L_PLAYBACK L_RECORD L_OUTPUT L_INPUT +%token L_IEC958OCS L_3D L_RESET L_USER L_VALID L_DATA L_PROTECTED L_PRE2 +%token L_FSLOCK L_TYPE L_GSTATUS L_ENABLE L_DISABLE %type boolean %type integer @@ -208,9 +212,28 @@ switches : switch switch : L_TRUE { set_switch_boolean( 1 ); } | L_FALSE { set_switch_boolean( 0 ); } | L_INTEGER { set_switch_integer( $1 ); } + | L_IEC958OCS '(' { set_switch_iec958ocs_begin(); } iec958ocs ')' | error { yyerror( "unknown keyword in switch() data parameter" ); } ; +iec958ocs : iec958ocs1 + | iec958ocs iec958ocs1 + ; + +iec958ocs1 : L_ENABLE { set_switch_iec958ocs( 0, 1, 0 ); } + | L_DISABLE { set_switch_iec958ocs( 0, 0, 0 ); } + | L_3D { set_switch_iec958ocs( 4, 0x2000, ~0x2000 ); } + | L_RESET { set_switch_iec958ocs( 4, 0x0040, ~0x0040 ); } + | L_USER { set_switch_iec958ocs( 4, 0x0020, ~0x0020 ); } + | L_VALID { set_switch_iec958ocs( 4, 0x0010, ~0x0010 ); } + | L_DATA { set_switch_iec958ocs( 5, 0x0002, ~0x0002 ); } + | L_PRE2 { set_switch_iec958ocs( 5, 0x0008, ~0x0018 ); } + | L_FSLOCK { set_switch_iec958ocs( 5, 0x0020, ~0x0020 ); } + | L_TYPE '(' integer ')' { set_switch_iec958ocs( 5, ($3 & 0x7f) << 6, ~(0x7f<<6) ); } + | L_GSTATUS { set_switch_iec958ocs( 5, 0x2000, ~0x2000 ); } + | error { yyerror( "unknown keyword in iec958ocs1() arguments" ); } + ; + boolean : L_TRUE { $$ = 1; } | L_FALSE { $$ = 0; } | error { yyerror( "unknown boolean value" ); } @@ -434,3 +457,31 @@ static void set_switch_integer( int val ) if ( memcmp( &sw -> value, &xx, sizeof(xx) ) ) *Xswitchchange = 1; memcpy( &sw -> value, &xx, sizeof(xx) ); } + +static void set_switch_iec958ocs_begin( void ) +{ + /* ok.. this is a little bit wrong, but at these times are all switches same */ + snd_ctl_switch_t *sw = (snd_ctl_switch_t *)Xswitch; + + if ( Xswitchtype != SWITCH_MIXER || sw -> type != SND_MIXER_SW_TYPE_BOOLEAN || + !strcmp( sw -> name, SND_MIXER_SW_IEC958OUT ) ) + yyerror( "Switch '%s' cannot store IEC958 information for Cirrus Logic chips...", sw -> name ); + if ( sw -> value.data32[1] != (('C'<<8)|'S') ) + yyerror( "Switch '%s' doesn't have Cirrus Logic signature!!!", sw -> name ); + sw -> value.enable = 0; + sw -> value.data16[4] = 0x0000; + sw -> value.data16[5] = 0x0000; +} + +static void set_switch_iec958ocs( int idx, unsigned short val, unsigned short mask ) +{ + /* ok.. this is a little bit wrong, but at these times are all switches same */ + snd_ctl_switch_t *sw = (snd_ctl_switch_t *)Xswitch; + + if ( idx == 0 ) { + sw -> value.enable = val ? 1 : 0; + return; + } + sw -> value.data16[ idx ] &= ~mask; + sw -> value.data16[ idx ] |= val; +} diff --git a/alsactl/setup.c b/alsactl/setup.c index abebdb4..df0e6e3 100644 --- a/alsactl/setup.c +++ b/alsactl/setup.c @@ -528,7 +528,8 @@ static void soundcard_setup_write_switch( FILE *out, int interface, const unsign }; char *s, v[16]; struct data *pdata = (struct data *)data; - int idx; + int idx, first, switchok = 0; + const char *space = " "; v[0] = '\0'; switch ( type ) { @@ -540,17 +541,55 @@ static void soundcard_setup_write_switch( FILE *out, int interface, const unsign default: s = "unknown"; } - fprintf( out, " ; Type is '%s'.\n", s ); + fprintf( out, "%s; Type is '%s'.\n", space, s ); if ( low != 0 || high != 0 ) - fprintf( out, " ; Accepted switch range is from %ui to %ui.\n", low, high ); - fprintf( out, " switch( \"%s\", %s", name, v ); - if ( type < 0 || type > SND_CTL_SW_TYPE_DWORD ) { - /* TODO: some well known types should be verbose */ - fprintf( out, " rawdata( " ); - for ( idx = 0; idx < 31; idx++ ) { - fprintf( out, "@%02x:", pdata -> data8[idx] ); + fprintf( out, "%s; Accepted switch range is from %ui to %ui.\n", space, low, high ); + if ( interface == SND_INTERFACE_CONTROL && type == SND_CTL_SW_TYPE_WORD && + !strcmp( name, SND_CTL_SW_JOYSTICK_ADDRESS ) ) { + for ( idx = 1, first = 1; idx < 16; idx++ ) { + if ( pdata -> data16[idx] ) { + if ( first ) { + fprintf( out, "%s; Available addresses - 0x%x", space, pdata -> data16[idx] ); + first = 0; + } else { + fprintf( out, ", 0x%x", pdata -> data16[idx] ); + } + } + } + if ( !first ) fprintf( out, "\n" ); + } + fprintf( out, "%sswitch( \"%s\", ", space, name ); + if ( interface == SND_INTERFACE_MIXER && type == SND_MIXER_SW_TYPE_BOOLEAN && + !strcmp( name, SND_MIXER_SW_IEC958OUT ) ) { + if ( pdata -> data16[0] == (('C'<<8)|'S') ) { /* Cirrus Crystal */ + switchok = 0; + fprintf( out, "iec958ocs( %s", pdata -> enable ? "enable" : "disable" ); + if ( pdata -> data16[4] & 0x2000 ) fprintf( out, " 3d" ); + if ( pdata -> data16[4] & 0x0040 ) fprintf( out, " reset" ); + if ( pdata -> data16[4] & 0x0020 ) fprintf( out, " user" ); + if ( pdata -> data16[4] & 0x0010 ) fprintf( out, " valid" ); + if ( pdata -> data16[5] & 0x0002 ) fprintf( out, " data" ); + if ( !(pdata -> data16[5] & 0x0004) ) fprintf( out, " protected" ); + switch ( pdata -> data16[5] & 0x0018 ) { + case 0x0008: fprintf( out, " pre2" ); break; + default: break; + } + if ( pdata -> data16[5] & 0x0020 ) fprintf( out, " fslock" ); + fprintf( out, " type( 0x%x )", (pdata -> data16[5] >> 6) & 0x7f ); + if ( pdata -> data16[5] & 0x2000 ) fprintf( out, " gstatus" ); + fprintf( out, ")" ); + } + } + if ( !switchok ) { + fprintf( out, v ); + if ( type < 0 || type > SND_CTL_SW_TYPE_DWORD ) { + /* TODO: some well known types should be verbose */ + fprintf( out, " rawdata( " ); + for ( idx = 0; idx < 31; idx++ ) { + fprintf( out, "@%02x:", pdata -> data8[idx] ); + } + fprintf( out, "%02x@ )\n", pdata -> data8[31] ); } - fprintf( out, "%02x@ )\n", pdata -> data8[31] ); } fprintf( out, " )\n" ); }