mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-22 21:56:31 +01:00
319 lines
7.5 KiB
Text
319 lines
7.5 KiB
Text
%{
|
|
|
|
/*
|
|
* Advanced Linux Sound Architecture Control Program
|
|
* Copyright (c) 1998 by Perex, APS, University of South Bohemia
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
#include "alsactl.h"
|
|
#include <stdarg.h>
|
|
|
|
/* insgus_lexer.c */
|
|
|
|
int yylex( void );
|
|
|
|
extern char cfgfile[];
|
|
extern int linecount;
|
|
extern FILE *yyin;
|
|
|
|
/* structure for byte arrays */
|
|
|
|
struct bytearray {
|
|
unsigned char *data;
|
|
size_t datalen;
|
|
};
|
|
|
|
/* local functions */
|
|
|
|
static void yyerror(char *, ...);
|
|
|
|
static void build_soundcard(char *name);
|
|
static void build_control_begin(void);
|
|
static void build_control_end(void);
|
|
static void set_control_iface(int iface);
|
|
static void set_control_device(int dev);
|
|
static void set_control_subdevice(int subdev);
|
|
static void set_control_name(char *name);
|
|
static void set_control_index(int idx);
|
|
static void set_control_type(snd_control_type_t type);
|
|
static void set_control_boolean(int val);
|
|
static void set_control_integer(long val);
|
|
|
|
/* local variables */
|
|
|
|
static struct soundcard *Xsoundcard = NULL;
|
|
static struct ctl_control *Xcontrol = NULL;
|
|
static int Xposition = 0;
|
|
static snd_control_type_t Xtype = SND_CONTROL_TYPE_NONE;
|
|
|
|
%}
|
|
|
|
%start lines
|
|
|
|
%union {
|
|
int b_value;
|
|
long i_value;
|
|
char *s_value;
|
|
struct bytearray a_value;
|
|
};
|
|
|
|
%token <b_value> L_TRUE L_FALSE
|
|
%token <i_value> L_INTEGER
|
|
%token <s_value> L_STRING
|
|
%token <a_value> L_BYTEARRAY
|
|
|
|
/* types */
|
|
%token L_INTEGER L_STRING
|
|
/* boolean */
|
|
%token L_FALSE L_TRUE
|
|
/* misc */
|
|
%token L_DOUBLE1
|
|
/* other keywords */
|
|
%token L_SOUNDCARD L_CONTROL L_RAWDATA
|
|
%token L_GLOBAL L_HWDEP L_MIXER L_PCM L_RAWMIDI L_TIMER L_SEQUENCER
|
|
%token L_IDENT L_IFACE L_NAME L_DEVICE L_SUBDEVICE L_INDEX
|
|
%token L_BOOL L_INT L_ENUM L_BYTE
|
|
|
|
%type <b_value> boolean
|
|
%type <i_value> integer iface
|
|
%type <s_value> string
|
|
%type <a_value> rawdata
|
|
|
|
%%
|
|
|
|
lines : line
|
|
| lines line
|
|
;
|
|
|
|
line : L_SOUNDCARD '(' string { build_soundcard($3); }
|
|
L_DOUBLE1 soundcards '}' { build_soundcard(NULL); }
|
|
| error { yyerror("unknown keyword in top level"); }
|
|
;
|
|
|
|
soundcards :
|
|
| soundcards soundcard
|
|
;
|
|
|
|
soundcard : L_CONTROL '(' L_IDENT '=' { build_control_begin(); }
|
|
'{' ctlids '}' ',' controls ')' { build_control_end(); }
|
|
| error { yyerror("an unknown keyword in the soundcard{} level"); }
|
|
;
|
|
|
|
ctlids : ctlid
|
|
| ctlids ',' ctlid
|
|
;
|
|
|
|
ctlid : L_IFACE '=' iface { set_control_iface($3); }
|
|
| L_DEVICE '=' integer { set_control_device($3); }
|
|
| L_SUBDEVICE '=' integer { set_control_subdevice($3); }
|
|
| L_NAME '=' string { set_control_name($3); }
|
|
| L_INDEX '=' integer { set_control_index($3); }
|
|
| error { yyerror("an unknown keyword in the control ID level"); }
|
|
;
|
|
|
|
controls : control
|
|
;
|
|
|
|
control : L_BOOL '=' { set_control_type(SND_CONTROL_TYPE_BOOLEAN); } '{' datas '}'
|
|
| L_INT '=' { set_control_type(SND_CONTROL_TYPE_INTEGER); } '{' datas '}'
|
|
| L_ENUM '=' { set_control_type(SND_CONTROL_TYPE_ENUMERATED); } '{' datas '}'
|
|
| L_BYTE '=' { set_control_type(SND_CONTROL_TYPE_BYTES); } '{' datas '}'
|
|
| error { yyerror( "an unknown keyword in the control() data parameter" ); }
|
|
;
|
|
|
|
datas : data
|
|
| datas ',' data
|
|
;
|
|
|
|
data : boolean { set_control_boolean($1); }
|
|
| integer { set_control_integer($1); }
|
|
| error { yyerror( "an unknown keyword in the control() data argument" ); }
|
|
;
|
|
|
|
iface : L_INTEGER { $$ = $1; }
|
|
| L_GLOBAL { $$ = SND_CONTROL_IFACE_CARD; }
|
|
| L_HWDEP { $$ = SND_CONTROL_IFACE_HWDEP; }
|
|
| L_MIXER { $$ = SND_CONTROL_IFACE_MIXER; }
|
|
| L_PCM { $$ = SND_CONTROL_IFACE_PCM; }
|
|
| L_RAWMIDI { $$ = SND_CONTROL_IFACE_RAWMIDI; }
|
|
| L_TIMER { $$ = SND_CONTROL_IFACE_TIMER; }
|
|
| L_SEQUENCER { $$ = SND_CONTROL_IFACE_SEQUENCER; }
|
|
| error { yyerror( "an unknown keyword in the interface field"); }
|
|
;
|
|
|
|
boolean : L_TRUE { $$ = 1; }
|
|
| L_FALSE { $$ = 0; }
|
|
;
|
|
|
|
integer : L_INTEGER { $$ = $1; }
|
|
;
|
|
|
|
string : L_STRING { $$ = $1; }
|
|
;
|
|
|
|
rawdata : L_RAWDATA '(' L_BYTEARRAY ')' { $$ = $3; }
|
|
| L_RAWDATA error { yyerror( "malformed rawdata value" ); }
|
|
;
|
|
|
|
%%
|
|
|
|
static void yyerror(char *string,...)
|
|
{
|
|
char errstr[1024];
|
|
|
|
va_list vars;
|
|
va_start(vars, string);
|
|
vsprintf(errstr, string, vars);
|
|
va_end(vars);
|
|
error("Error in configuration file '%s' (line %i): %s", cfgfile, linecount + 1, errstr);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
static void error_nomem(void)
|
|
{
|
|
yyerror("No enough memory...\n");
|
|
}
|
|
|
|
static void build_soundcard(char *name)
|
|
{
|
|
struct soundcard *soundcard;
|
|
|
|
if (!name) {
|
|
Xsoundcard = NULL;
|
|
return;
|
|
}
|
|
Xsoundcard = (struct soundcard *)malloc(sizeof(struct soundcard));
|
|
if (!Xsoundcard) {
|
|
free(name);
|
|
error_nomem();
|
|
return;
|
|
}
|
|
bzero(Xsoundcard, sizeof(*Xsoundcard));
|
|
for (soundcard = rsoundcards; soundcard && soundcard->next; soundcard = soundcard->next);
|
|
if (soundcard) {
|
|
soundcard->next = Xsoundcard;
|
|
} else {
|
|
rsoundcards = Xsoundcard;
|
|
}
|
|
strncpy(Xsoundcard->control.hwinfo.id, name, sizeof(Xsoundcard->control.hwinfo.id));
|
|
free(name);
|
|
}
|
|
|
|
static void build_control_begin(void)
|
|
{
|
|
struct ctl_control **first;
|
|
struct ctl_control *ctl;
|
|
|
|
first = &Xsoundcard->control.controls;
|
|
Xcontrol = (struct ctl_control *)malloc(sizeof(struct ctl_control));
|
|
if (!Xcontrol) {
|
|
error_nomem();
|
|
return;
|
|
}
|
|
Xposition = 0;
|
|
Xtype = SND_CONTROL_TYPE_NONE;
|
|
bzero(Xcontrol, sizeof(*Xcontrol));
|
|
for (ctl = *first; ctl && ctl->next; ctl = ctl->next);
|
|
if (ctl) {
|
|
ctl->next = Xcontrol;
|
|
} else {
|
|
*first = Xcontrol;
|
|
}
|
|
}
|
|
|
|
static void build_control_end(void)
|
|
{
|
|
Xcontrol = NULL;
|
|
}
|
|
|
|
static void set_control_iface(int iface)
|
|
{
|
|
Xcontrol->c.id.iface = iface;
|
|
}
|
|
|
|
static void set_control_device(int dev)
|
|
{
|
|
Xcontrol->c.id.device = dev;
|
|
}
|
|
|
|
static void set_control_subdevice(int subdev)
|
|
{
|
|
Xcontrol->c.id.subdevice = subdev;
|
|
}
|
|
|
|
static void set_control_name(char *name)
|
|
{
|
|
if (name == NULL)
|
|
return;
|
|
strncpy(Xcontrol->c.id.name, name, sizeof(Xcontrol->c.id.name));
|
|
free(name);
|
|
}
|
|
|
|
static void set_control_index(int idx)
|
|
{
|
|
Xcontrol->c.id.index = idx;
|
|
}
|
|
|
|
static void set_control_type(snd_control_type_t type)
|
|
{
|
|
Xcontrol->type = Xtype = type;
|
|
}
|
|
|
|
static void set_control_boolean(int val)
|
|
{
|
|
if (Xposition >= 512)
|
|
yyerror("Array overflow.");
|
|
switch (Xtype) {
|
|
case SND_CONTROL_TYPE_BOOLEAN:
|
|
Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
|
|
break;
|
|
case SND_CONTROL_TYPE_INTEGER:
|
|
Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
|
|
break;
|
|
case SND_CONTROL_TYPE_ENUMERATED:
|
|
Xcontrol->c.value.enumerated.item[Xposition++] = val ? 1 : 0;
|
|
break;
|
|
case SND_CONTROL_TYPE_BYTES:
|
|
Xcontrol->c.value.bytes.data[Xposition++] = val ? 1 : 0;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
static void set_control_integer(long val)
|
|
{
|
|
if (Xposition >= 512)
|
|
yyerror("Array overflow.");
|
|
switch (Xtype) {
|
|
case SND_CONTROL_TYPE_BOOLEAN:
|
|
Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
|
|
break;
|
|
case SND_CONTROL_TYPE_INTEGER:
|
|
Xcontrol->c.value.integer.value[Xposition++] = val;
|
|
break;
|
|
case SND_CONTROL_TYPE_ENUMERATED:
|
|
Xcontrol->c.value.enumerated.item[Xposition++] = (unsigned int)val;
|
|
break;
|
|
case SND_CONTROL_TYPE_BYTES:
|
|
Xcontrol->c.value.bytes.data[Xposition++] = (unsigned char)val;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|