mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 00:25:43 +01:00
Rewritten alsactl
This commit is contained in:
parent
6add1cdfb5
commit
8c4e1aa769
7 changed files with 929 additions and 1281 deletions
|
@ -1,10 +1,4 @@
|
||||||
sbin_PROGRAMS=alsactl
|
sbin_PROGRAMS=alsactl
|
||||||
noinst_HEADERS=alsactl.h
|
|
||||||
man_MANS=alsactl.1
|
man_MANS=alsactl.1
|
||||||
|
|
||||||
alsactl_SOURCES=alsactl.c alsactl_parser.y setup.c merge.c alsactl_lexer.l
|
alsactl_SOURCES=alsactl.c
|
||||||
YFLAGS=-d
|
|
||||||
|
|
||||||
# lexer / parser debug
|
|
||||||
#CFLAGS=-pipe -g -DYYDEBUG
|
|
||||||
#LFLAGS=-d
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* Advanced Linux Sound Architecture Control Program
|
|
||||||
* Copyright (c) 1997 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 <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/asoundlib.h>
|
|
||||||
|
|
||||||
#define ALSACTL_FILE "/etc/asound.conf"
|
|
||||||
|
|
||||||
#define LEFT 1
|
|
||||||
#define RIGHT 2
|
|
||||||
|
|
||||||
#define OUTPUT 0
|
|
||||||
#define INPUT 1
|
|
||||||
|
|
||||||
extern int debugflag;
|
|
||||||
|
|
||||||
extern void error(const char *fmt,...);
|
|
||||||
|
|
||||||
struct ctl_control {
|
|
||||||
int change;
|
|
||||||
snd_control_type_t type;
|
|
||||||
snd_control_info_t info;
|
|
||||||
snd_control_t c;
|
|
||||||
struct ctl_control *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ctl {
|
|
||||||
snd_ctl_hw_info_t hwinfo;
|
|
||||||
struct ctl_control *controls;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soundcard {
|
|
||||||
int no; /* card number */
|
|
||||||
struct ctl control;
|
|
||||||
struct soundcard *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct soundcard *soundcards;
|
|
||||||
extern struct soundcard *rsoundcards; /* read soundcards */
|
|
||||||
|
|
||||||
void soundcard_setup_init(void);
|
|
||||||
void soundcard_setup_done(void);
|
|
||||||
int soundcard_setup_load(const char *filename, int skip);
|
|
||||||
int soundcard_setup_write(const char *filename, int cardno);
|
|
||||||
int soundcard_setup_collect_controls(int cardno);
|
|
||||||
int soundcard_setup_merge_controls(int cardno);
|
|
||||||
int soundcard_setup_process_controls(int cardno);
|
|
||||||
|
|
||||||
char *control_id(snd_control_id_t *id);
|
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
struct bytearray {
|
|
||||||
unsigned char *data;
|
|
||||||
size_t datalen;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "alsactl_parser.h"
|
|
||||||
|
|
||||||
#define YY_NO_UNPUT
|
|
||||||
#undef YY_CDECL
|
|
||||||
#define YY_CDECL int YY_PROTO(yylex( void ));
|
|
||||||
|
|
||||||
int linecount;
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
/* special characters */
|
|
||||||
|
|
||||||
"{"|"}" return yytext[0];
|
|
||||||
"("|")" return yytext[0];
|
|
||||||
"["|"]" return yytext[0];
|
|
||||||
")"[ \t]*"{" return L_DOUBLE1;
|
|
||||||
"," return yytext[0];
|
|
||||||
"=" return yytext[0];
|
|
||||||
|
|
||||||
/* tokens */
|
|
||||||
|
|
||||||
soundcard return L_SOUNDCARD;
|
|
||||||
control return L_CONTROL;
|
|
||||||
|
|
||||||
global return L_GLOBAL;
|
|
||||||
hwdep return L_HWDEP;
|
|
||||||
mixer return L_MIXER;
|
|
||||||
pcm return L_PCM;
|
|
||||||
rawmidi return L_RAWMIDI;
|
|
||||||
timer return L_TIMER;
|
|
||||||
sequencer return L_SEQUENCER;
|
|
||||||
|
|
||||||
ident return L_IDENT;
|
|
||||||
iface return L_IFACE;
|
|
||||||
name return L_NAME;
|
|
||||||
device return L_DEVICE;
|
|
||||||
subdevice return L_SUBDEVICE;
|
|
||||||
index return L_INDEX;
|
|
||||||
|
|
||||||
bool return L_BOOL;
|
|
||||||
int return L_INT;
|
|
||||||
enum return L_ENUM;
|
|
||||||
byte return L_BYTE;
|
|
||||||
|
|
||||||
/* boolean */
|
|
||||||
|
|
||||||
false|off|no return L_FALSE;
|
|
||||||
true|on|yes return L_TRUE;
|
|
||||||
|
|
||||||
/* integers */
|
|
||||||
|
|
||||||
[0-9]+ { yylval.i_value = strtol(yytext, (char **)NULL, 10); return L_INTEGER; }
|
|
||||||
0x[0-9a-f]+ { yylval.i_value = strtol(yytext, (char **)NULL, 0); return L_INTEGER; }
|
|
||||||
|
|
||||||
/* strings */
|
|
||||||
|
|
||||||
\"[^\"]*\" { yytext[strlen(yytext) - 1] = 0;
|
|
||||||
yylval.s_value = strdup(&yytext[1]);
|
|
||||||
return L_STRING; }
|
|
||||||
\'[^\']*\' { yytext[strlen(yytext) - 1] = 0;
|
|
||||||
yylval.s_value = strdup(&yytext[1]);
|
|
||||||
return L_STRING; }
|
|
||||||
[a-z0-9/\~@-Za-z_]+ { yylval.s_value = strdup(yytext);
|
|
||||||
return L_STRING; }
|
|
||||||
$[a-z0-9/\~@-Za-z_]+ { yylval.s_value = strdup(getenv(&yytext[1]));
|
|
||||||
return L_STRING; }
|
|
||||||
|
|
||||||
/* comments & whitespaces */
|
|
||||||
|
|
||||||
[#\;][^\n]*\n { linecount++; }
|
|
||||||
[ \t]+ ;
|
|
||||||
\n { linecount++; }
|
|
||||||
. fprintf( stderr, "alsactl: discarding char '%c' - line %i\n", yytext[0], linecount + 1 );
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
#ifndef yywrap
|
|
||||||
int yywrap(void) /* do this avoid to do -lfl */
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,319 +0,0 @@
|
||||||
%{
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
170
alsactl/merge.c
170
alsactl/merge.c
|
@ -1,170 +0,0 @@
|
||||||
/*
|
|
||||||
* Advanced Linux Sound Architecture Control Program
|
|
||||||
* Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
static int merge_one_control(struct ctl_control *cctl, struct ctl_control *uctl, int cardno)
|
|
||||||
{
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
if (!(cctl->info.access & SND_CONTROL_ACCESS_WRITE))
|
|
||||||
return 0;
|
|
||||||
switch (cctl->info.type) {
|
|
||||||
case SND_CONTROL_TYPE_BOOLEAN:
|
|
||||||
if (uctl->type != SND_CONTROL_TYPE_BOOLEAN) {
|
|
||||||
error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for (idx = 0; idx < cctl->info.values_count; idx++) {
|
|
||||||
if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
|
|
||||||
cctl->change = 1;
|
|
||||||
cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_INTEGER:
|
|
||||||
if (uctl->type != SND_CONTROL_TYPE_INTEGER) {
|
|
||||||
error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for (idx = 0; idx < cctl->info.values_count; idx++) {
|
|
||||||
if (cctl->info.value.integer.min > uctl->c.value.integer.value[idx] ||
|
|
||||||
cctl->info.value.integer.max < uctl->c.value.integer.value[idx]) {
|
|
||||||
error("The value %li for the control '%s' is out of range %i-%i.", uctl->c.value.integer.value[idx], control_id(&uctl->c.id), cctl->info.value.integer.min, cctl->info.value.integer.max);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
|
|
||||||
cctl->change = 1;
|
|
||||||
cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_ENUMERATED:
|
|
||||||
if (uctl->type != SND_CONTROL_TYPE_ENUMERATED) {
|
|
||||||
error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for (idx = 0; idx < cctl->info.values_count; idx++) {
|
|
||||||
if (cctl->info.value.enumerated.items <= uctl->c.value.enumerated.item[idx]) {
|
|
||||||
error("The value %u for the control '%s' is out of range 0-%i.", uctl->c.value.integer.value[idx], control_id(&uctl->c.id), cctl->info.value.enumerated.items-1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (cctl->c.value.enumerated.item[idx] != uctl->c.value.enumerated.item[idx]) {
|
|
||||||
cctl->change = 1;
|
|
||||||
cctl->c.value.enumerated.item[idx] = uctl->c.value.enumerated.item[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_BYTES:
|
|
||||||
if (uctl->type != SND_CONTROL_TYPE_BYTES) {
|
|
||||||
error("A wrong type %i for the control %s. The type 'bytes' is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (memcmp(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count)) {
|
|
||||||
cctl->change = 1;
|
|
||||||
memcpy(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error("The control type %i is not known.", cctl->type);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int soundcard_setup_merge_control(struct ctl_control *cctl, struct ctl_control *uctl, int cardno)
|
|
||||||
{
|
|
||||||
struct ctl_control *cctl1;
|
|
||||||
|
|
||||||
for ( ; uctl; uctl = uctl->next) {
|
|
||||||
for (cctl1 = cctl; cctl1; cctl1 = cctl1->next) {
|
|
||||||
if (cctl1->c.id.iface == uctl->c.id.iface &&
|
|
||||||
cctl1->c.id.device == uctl->c.id.device &&
|
|
||||||
cctl1->c.id.subdevice == uctl->c.id.subdevice &&
|
|
||||||
!strncmp(cctl1->c.id.name, uctl->c.id.name, sizeof(cctl1->c.id.name)) &&
|
|
||||||
cctl1->c.id.index == uctl->c.id.index) {
|
|
||||||
merge_one_control(cctl1, uctl, cardno);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!cctl1) {
|
|
||||||
error("Cannot find the control %s...", control_id(&uctl->c.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundcard_setup_merge_controls(int cardno)
|
|
||||||
{
|
|
||||||
struct soundcard *soundcard, *rsoundcard;
|
|
||||||
|
|
||||||
for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) {
|
|
||||||
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
|
|
||||||
if (!strncmp(soundcard->control.hwinfo.id, rsoundcard->control.hwinfo.id, sizeof(soundcard->control.hwinfo.id)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!soundcard) {
|
|
||||||
error("The soundcard '%s' was not found...\n", rsoundcard->control.hwinfo.id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (cardno >= 0 && soundcard->no != cardno)
|
|
||||||
continue;
|
|
||||||
soundcard_setup_merge_control(soundcard->control.controls, rsoundcard->control.controls, soundcard->no);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int soundcard_open_ctl(snd_ctl_t **ctlhandle, struct soundcard *soundcard)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (*ctlhandle)
|
|
||||||
return 0;
|
|
||||||
if ((err = snd_ctl_open(ctlhandle, soundcard->no)) < 0) {
|
|
||||||
error("Cannot open control interface for soundcard #%i.", soundcard->no + 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundcard_setup_process_controls(int cardno)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
snd_ctl_t *ctlhandle = NULL;
|
|
||||||
struct soundcard *soundcard;
|
|
||||||
struct ctl_control *ctl;
|
|
||||||
|
|
||||||
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
|
|
||||||
if (cardno >= 0 && soundcard->no != cardno)
|
|
||||||
continue;
|
|
||||||
for (ctl = soundcard->control.controls; ctl; ctl = ctl->next) {
|
|
||||||
if (ctl->change)
|
|
||||||
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
|
||||||
if ((err = snd_ctl_cwrite(ctlhandle, &ctl->c)) < 0)
|
|
||||||
error("Control '%s' write error: %s", control_id(&ctl->c.id), snd_strerror(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ctlhandle) {
|
|
||||||
snd_ctl_close(ctlhandle);
|
|
||||||
ctlhandle = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
530
alsactl/setup.c
530
alsactl/setup.c
|
@ -1,530 +0,0 @@
|
||||||
/*
|
|
||||||
* Advanced Linux Sound Architecture Control Program
|
|
||||||
* Copyright (c) 1997 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"
|
|
||||||
|
|
||||||
#define SND_INTERFACE_CONTROL 0
|
|
||||||
#define SND_INTERFACE_MIXER 1
|
|
||||||
#define SND_INTERFACE_PCM 2
|
|
||||||
#define SND_INTERFACE_RAWMIDI 3
|
|
||||||
|
|
||||||
extern int yyparse(void);
|
|
||||||
extern int linecount;
|
|
||||||
extern FILE *yyin;
|
|
||||||
extern int yydebug;
|
|
||||||
struct soundcard *soundcards = NULL;
|
|
||||||
struct soundcard *rsoundcards = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* misc functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
char *control_id(snd_control_id_t *id)
|
|
||||||
{
|
|
||||||
static char str[128];
|
|
||||||
|
|
||||||
if (!id)
|
|
||||||
return "???";
|
|
||||||
sprintf(str, "%i,%i,%i,%s,%i", id->iface, id->device, id->subdevice, id->name, id->index);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* free functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void soundcard_ctl_control_free(struct ctl_control *first)
|
|
||||||
{
|
|
||||||
struct ctl_control *next;
|
|
||||||
|
|
||||||
while (first) {
|
|
||||||
next = first->next;
|
|
||||||
free(first);
|
|
||||||
first = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void soundcard_free1(struct soundcard *soundcard)
|
|
||||||
{
|
|
||||||
if (!soundcard)
|
|
||||||
return;
|
|
||||||
soundcard_ctl_control_free(soundcard->control.controls);
|
|
||||||
free(soundcard);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void soundcard_free(struct soundcard *first)
|
|
||||||
{
|
|
||||||
struct soundcard *next;
|
|
||||||
|
|
||||||
while (first) {
|
|
||||||
next = first->next;
|
|
||||||
soundcard_free1(first);
|
|
||||||
first = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int soundcard_remove(int cardno)
|
|
||||||
{
|
|
||||||
struct soundcard *first, *prev = NULL, *next;
|
|
||||||
|
|
||||||
first = soundcards;
|
|
||||||
while (first) {
|
|
||||||
next = first->next;
|
|
||||||
if (first->no == cardno) {
|
|
||||||
soundcard_free1(first);
|
|
||||||
if (!prev)
|
|
||||||
soundcards = next;
|
|
||||||
else
|
|
||||||
prev->next = next;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
prev = first;
|
|
||||||
first = first->next;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* exported functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
void soundcard_setup_init(void)
|
|
||||||
{
|
|
||||||
soundcards = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void soundcard_setup_done(void)
|
|
||||||
{
|
|
||||||
soundcard_free(soundcards);
|
|
||||||
soundcard_free(rsoundcards);
|
|
||||||
soundcards = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int determine_controls(void *handle, struct ctl_control **cctl)
|
|
||||||
{
|
|
||||||
int err, idx;
|
|
||||||
snd_control_list_t list;
|
|
||||||
snd_control_id_t *item;
|
|
||||||
snd_control_t ctl;
|
|
||||||
struct ctl_control *prev_control;
|
|
||||||
struct ctl_control *new_control;
|
|
||||||
|
|
||||||
*cctl = NULL;
|
|
||||||
bzero(&list, sizeof(list));
|
|
||||||
if ((err = snd_ctl_clist(handle, &list)) < 0) {
|
|
||||||
error("Cannot determine controls: %s", snd_strerror(err));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (list.controls <= 0)
|
|
||||||
return 0;
|
|
||||||
list.controls_request = list.controls + 16;
|
|
||||||
list.controls_offset = list.controls_count = 0;
|
|
||||||
list.pids = malloc(sizeof(snd_control_id_t) * list.controls_request);
|
|
||||||
if (!list.pids) {
|
|
||||||
error("No enough memory...");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if ((err = snd_ctl_clist(handle, &list)) < 0) {
|
|
||||||
error("Cannot determine controls (2): %s", snd_strerror(err));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for (idx = 0, prev_control = NULL; idx < list.controls_count; idx++) {
|
|
||||||
item = &list.pids[idx];
|
|
||||||
bzero(&ctl, sizeof(ctl));
|
|
||||||
ctl.id = *item;
|
|
||||||
if ((err = snd_ctl_cread(handle, &ctl)) < 0) {
|
|
||||||
error("Cannot read control '%s': %s", control_id(item), snd_strerror(err));
|
|
||||||
free(list.pids);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
new_control = malloc(sizeof(*new_control));
|
|
||||||
if (!new_control) {
|
|
||||||
error("No enough memory...");
|
|
||||||
free(list.pids);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
bzero(new_control, sizeof(*new_control));
|
|
||||||
memcpy(&new_control->c, &ctl, sizeof(new_control->c));
|
|
||||||
new_control->info.id = ctl.id;
|
|
||||||
if ((err = snd_ctl_cinfo(handle, &new_control->info)) < 0) {
|
|
||||||
error("Cannot read control info '%s': %s", control_id(item), snd_strerror(err));
|
|
||||||
free(new_control);
|
|
||||||
free(list.pids);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (*cctl) {
|
|
||||||
prev_control->next = new_control;
|
|
||||||
prev_control = new_control;
|
|
||||||
} else {
|
|
||||||
*cctl = prev_control = new_control;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(list.pids);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int soundcard_setup_collect_controls1(int cardno)
|
|
||||||
{
|
|
||||||
snd_ctl_t *handle;
|
|
||||||
struct soundcard *card, *first, *prev;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
soundcard_remove(cardno);
|
|
||||||
if ((err = snd_ctl_open(&handle, cardno)) < 0) {
|
|
||||||
error("SND CTL open error: %s", snd_strerror(err));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* --- */
|
|
||||||
card = (struct soundcard *) malloc(sizeof(struct soundcard));
|
|
||||||
if (!card) {
|
|
||||||
snd_ctl_close(handle);
|
|
||||||
error("malloc error");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
bzero(card, sizeof(struct soundcard));
|
|
||||||
card->no = cardno;
|
|
||||||
for (first = soundcards, prev = NULL; first; first = first->next) {
|
|
||||||
if (first->no > cardno) {
|
|
||||||
if (!prev) {
|
|
||||||
soundcards = card;
|
|
||||||
} else {
|
|
||||||
prev->next = card;
|
|
||||||
}
|
|
||||||
card->next = first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev = first;
|
|
||||||
}
|
|
||||||
if (!first) {
|
|
||||||
if (!soundcards) {
|
|
||||||
soundcards = card;
|
|
||||||
} else {
|
|
||||||
prev->next = card;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((err = snd_ctl_hw_info(handle, &card->control.hwinfo)) < 0) {
|
|
||||||
snd_ctl_close(handle);
|
|
||||||
error("SND CTL HW INFO error: %s", snd_strerror(err));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* --- */
|
|
||||||
if (determine_controls(handle, &card->control.controls)) {
|
|
||||||
snd_ctl_close(handle);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* --- */
|
|
||||||
snd_ctl_close(handle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundcard_setup_collect_controls(int cardno)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
unsigned int mask;
|
|
||||||
|
|
||||||
if (cardno >= 0) {
|
|
||||||
return soundcard_setup_collect_controls1(cardno);
|
|
||||||
} else {
|
|
||||||
mask = snd_cards_mask();
|
|
||||||
for (cardno = 0; cardno < SND_CARDS; cardno++) {
|
|
||||||
if (!(mask & (1 << cardno)))
|
|
||||||
continue;
|
|
||||||
err = soundcard_setup_collect_controls1(cardno);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundcard_setup_load(const char *cfgfile, int skip)
|
|
||||||
{
|
|
||||||
extern int yyparse(void);
|
|
||||||
extern int linecount;
|
|
||||||
extern FILE *yyin;
|
|
||||||
#ifdef YYDEBUG
|
|
||||||
extern int yydebug;
|
|
||||||
#endif
|
|
||||||
int xtry;
|
|
||||||
|
|
||||||
#ifdef YYDEBUG
|
|
||||||
yydebug = 1;
|
|
||||||
#endif
|
|
||||||
if (debugflag)
|
|
||||||
printf("cfgfile = '%s'\n", cfgfile);
|
|
||||||
if (skip && access(cfgfile, R_OK))
|
|
||||||
return 0;
|
|
||||||
if ((yyin = fopen(cfgfile, "r")) == NULL) {
|
|
||||||
error("Cannot open configuration file '%s'...", cfgfile);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
linecount = 0;
|
|
||||||
xtry = yyparse();
|
|
||||||
fclose(yyin);
|
|
||||||
if (debugflag)
|
|
||||||
printf("Config ok..\n");
|
|
||||||
if (xtry)
|
|
||||||
error("Ignored error in configuration file '%s'...", cfgfile);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void soundcard_setup_write_control(FILE * out, const char *space, int card, struct ctl_control *control)
|
|
||||||
{
|
|
||||||
char *s, v[16];
|
|
||||||
int err, idx;
|
|
||||||
snd_ctl_t *handle;
|
|
||||||
snd_control_info_t info;
|
|
||||||
|
|
||||||
memcpy(&info, &control->info, sizeof(info));
|
|
||||||
v[0] = '\0';
|
|
||||||
switch (info.type) {
|
|
||||||
case SND_CONTROL_TYPE_BOOLEAN: s = "bool"; break;
|
|
||||||
case SND_CONTROL_TYPE_INTEGER: s = "integer"; break;
|
|
||||||
case SND_CONTROL_TYPE_ENUMERATED: s = "enumerated"; break;
|
|
||||||
case SND_CONTROL_TYPE_BYTES: s = "bytes"; break;
|
|
||||||
default: s = "unknown";
|
|
||||||
}
|
|
||||||
fprintf(out, "\n%s; The type is '%s'. Access:", space, s);
|
|
||||||
if (info.access & SND_CONTROL_ACCESS_READ)
|
|
||||||
fprintf(out, " read");
|
|
||||||
if (info.access & SND_CONTROL_ACCESS_WRITE)
|
|
||||||
fprintf(out, " write");
|
|
||||||
if (info.access & SND_CONTROL_ACCESS_INACTIVE)
|
|
||||||
fprintf(out, " inactive");
|
|
||||||
fprintf(out, ". Count is %i.\n", info.values_count);
|
|
||||||
switch (info.type) {
|
|
||||||
case SND_CONTROL_TYPE_BOOLEAN:
|
|
||||||
if (info.value.integer.min != 0 || info.value.integer.max != 1 ||
|
|
||||||
info.value.integer.step != 0)
|
|
||||||
error("Wrong control '%s' (boolean)\n", control_id(&info.id));
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_INTEGER:
|
|
||||||
fprintf(out, "%s; The range is %li-%li (step %li)\n", space, info.value.integer.min, info.value.integer.max, info.value.integer.step);
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_ENUMERATED:
|
|
||||||
if ((err = snd_ctl_open(&handle, card)) >= 0) {
|
|
||||||
for (idx = 0; idx < info.value.enumerated.items; idx++) {
|
|
||||||
info.value.enumerated.item = idx;
|
|
||||||
if (snd_ctl_cinfo(handle, &info) >= 0)
|
|
||||||
fprintf(out, "%s; Item #%i - %s\n", space, idx, info.value.enumerated.name);
|
|
||||||
}
|
|
||||||
snd_ctl_close(handle);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (info.id.iface) {
|
|
||||||
case SND_CONTROL_IFACE_CARD: s = "global"; break;
|
|
||||||
case SND_CONTROL_IFACE_HWDEP: s = "hwdep"; break;
|
|
||||||
case SND_CONTROL_IFACE_MIXER: s = "mixer"; break;
|
|
||||||
case SND_CONTROL_IFACE_PCM: s = "pcm"; break;
|
|
||||||
case SND_CONTROL_IFACE_RAWMIDI: s = "rawmidi"; break;
|
|
||||||
case SND_CONTROL_IFACE_TIMER: s = "timer"; break;
|
|
||||||
case SND_CONTROL_IFACE_SEQUENCER: s = "sequencer"; break;
|
|
||||||
default: sprintf(v, "%i", info.id.iface); s = v; break;
|
|
||||||
}
|
|
||||||
fprintf(out, "%scontrol(ident={iface=%s", space, s);
|
|
||||||
if (info.id.device > 0)
|
|
||||||
fprintf(out, ", device=%i", info.id.device);
|
|
||||||
if (info.id.subdevice > 0)
|
|
||||||
fprintf(out, ", subdevice=%i", info.id.subdevice);
|
|
||||||
fprintf(out, ", name='%s'", info.id.name);
|
|
||||||
if (info.id.index > 0)
|
|
||||||
fprintf(out, ", index=%i", info.id.index);
|
|
||||||
fprintf(out, "}, ");
|
|
||||||
switch (info.type) {
|
|
||||||
case SND_CONTROL_TYPE_BOOLEAN: fprintf(out, "bool={"); break;
|
|
||||||
case SND_CONTROL_TYPE_INTEGER: fprintf(out, "int={"); break;
|
|
||||||
case SND_CONTROL_TYPE_ENUMERATED: fprintf(out, "enum={"); break;
|
|
||||||
case SND_CONTROL_TYPE_BYTES: fprintf(out, "byte={"); break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
for (idx = 0; idx < info.values_count; idx++) {
|
|
||||||
if (idx > 0)
|
|
||||||
fprintf(out, ",");
|
|
||||||
switch (info.type) {
|
|
||||||
case SND_CONTROL_TYPE_BOOLEAN:
|
|
||||||
fprintf(out, "%s", control->c.value.integer.value[idx] ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_INTEGER:
|
|
||||||
fprintf(out, "%li", control->c.value.integer.value[idx]);
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_ENUMERATED:
|
|
||||||
fprintf(out, "%u", control->c.value.enumerated.item[idx]);
|
|
||||||
break;
|
|
||||||
case SND_CONTROL_TYPE_BYTES:
|
|
||||||
fprintf(out, "%02x", control->c.value.bytes.data[idx]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(out, "})\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void soundcard_setup_write_controls(FILE *out, const char *space, int card, struct ctl_control **controls)
|
|
||||||
{
|
|
||||||
struct ctl_control *ctl;
|
|
||||||
|
|
||||||
if (!(*controls))
|
|
||||||
return;
|
|
||||||
for (ctl = *controls; ctl; ctl = ctl->next)
|
|
||||||
soundcard_setup_write_control(out, space, card, ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_LINE (32 * 1024)
|
|
||||||
|
|
||||||
int soundcard_setup_write(const char *cfgfile, int cardno)
|
|
||||||
{
|
|
||||||
FILE *out, *out1, *out2, *in;
|
|
||||||
char *tmpfile1, *tmpfile2;
|
|
||||||
struct soundcard *first, *sel = NULL;
|
|
||||||
char *line, cardname[sizeof(first->control.hwinfo.name)+16], *ptr1;
|
|
||||||
int mark, size, ok;
|
|
||||||
|
|
||||||
tmpfile1 = (char *)malloc(strlen(cfgfile) + 16);
|
|
||||||
tmpfile2 = (char *)malloc(strlen(cfgfile) + 16);
|
|
||||||
if (!tmpfile1 || !tmpfile2) {
|
|
||||||
error("No enough memory...\n");
|
|
||||||
if (tmpfile1)
|
|
||||||
free(tmpfile1);
|
|
||||||
if (tmpfile2)
|
|
||||||
free(tmpfile2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
strcpy(tmpfile1, cfgfile);
|
|
||||||
strcat(tmpfile1, ".new");
|
|
||||||
strcpy(tmpfile2, cfgfile);
|
|
||||||
strcat(tmpfile2, ".insert");
|
|
||||||
|
|
||||||
if (cardno >= 0) {
|
|
||||||
line = (char *)malloc(MAX_LINE);
|
|
||||||
if (!line) {
|
|
||||||
error("No enough memory...\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if ((in = fopen(cfgfile, "r")) == NULL)
|
|
||||||
cardno = -1;
|
|
||||||
} else {
|
|
||||||
line = NULL;
|
|
||||||
in = NULL;
|
|
||||||
}
|
|
||||||
if ((out = out1 = fopen(tmpfile1, "w+")) == NULL) {
|
|
||||||
error("Cannot open file '%s' for writing...\n", tmpfile1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
fprintf(out, "# ALSA driver configuration\n");
|
|
||||||
fprintf(out, "# This configuration is generated with the alsactl program.\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
if (cardno >= 0) {
|
|
||||||
if ((out = out2 = fopen(tmpfile2, "w+")) == NULL) {
|
|
||||||
error("Cannot open file '%s' for writing...\n", tmpfile2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out2 = NULL;
|
|
||||||
}
|
|
||||||
for (first = soundcards; first; first = first->next) {
|
|
||||||
if (cardno >= 0 && first->no != cardno)
|
|
||||||
continue;
|
|
||||||
sel = first;
|
|
||||||
fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id);
|
|
||||||
if (first->control.controls) {
|
|
||||||
soundcard_setup_write_controls(out, " ", first->no, &first->control.controls);
|
|
||||||
}
|
|
||||||
fprintf(out, "}\n%s", cardno < 0 && first->next ? "\n" : "");
|
|
||||||
}
|
|
||||||
/* merge the old and new text */
|
|
||||||
if (cardno >= 0) {
|
|
||||||
fseek(out2, 0, SEEK_SET);
|
|
||||||
mark = ok = 0;
|
|
||||||
__1:
|
|
||||||
while (fgets(line, MAX_LINE - 1, in)) {
|
|
||||||
line[MAX_LINE - 1] = '\0';
|
|
||||||
if (!strncmp(line, "soundcard(", 10))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (!feof(in)) {
|
|
||||||
ptr1 = line + 10;
|
|
||||||
while (*ptr1 && *ptr1 != '"')
|
|
||||||
ptr1++;
|
|
||||||
if (*ptr1)
|
|
||||||
ptr1++;
|
|
||||||
strncpy(cardname, sel->control.hwinfo.id, sizeof(sel->control.hwinfo.id));
|
|
||||||
cardname[sizeof(sel->control.hwinfo.id)] = '\0';
|
|
||||||
strcat(cardname, "\"");
|
|
||||||
if (!strncmp(ptr1, cardname, strlen(cardname))) {
|
|
||||||
if (mark)
|
|
||||||
fprintf(out1, "\n");
|
|
||||||
do {
|
|
||||||
size = fread(line, 1, MAX_LINE, out2);
|
|
||||||
if (size > 0)
|
|
||||||
fwrite(line, 1, size, out1);
|
|
||||||
} while (size > 0);
|
|
||||||
mark = ok = 1;
|
|
||||||
goto __1;
|
|
||||||
} else {
|
|
||||||
if (mark)
|
|
||||||
fprintf(out1, "\n");
|
|
||||||
fprintf(out1, line);
|
|
||||||
while (fgets(line, MAX_LINE - 1, in)) {
|
|
||||||
line[MAX_LINE - 1] = '\0';
|
|
||||||
fprintf(out1, line);
|
|
||||||
if (line[0] == '}') {
|
|
||||||
mark = 1;
|
|
||||||
goto __1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
if (mark)
|
|
||||||
fprintf(out1, "\n");
|
|
||||||
do {
|
|
||||||
size = fread(line, 1, MAX_LINE, out2);
|
|
||||||
printf("size = %i\n", size);
|
|
||||||
if (size > 0)
|
|
||||||
fwrite(line, 1, size, out1);
|
|
||||||
} while (size > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (in)
|
|
||||||
fclose(in);
|
|
||||||
if (out2)
|
|
||||||
fclose(out2);
|
|
||||||
if (!access(cfgfile, F_OK) && remove(cfgfile))
|
|
||||||
error("Cannot remove file '%s'...", cfgfile);
|
|
||||||
if (rename(tmpfile1, cfgfile) < 0)
|
|
||||||
error("Cannot rename file '%s' to '%s'...", tmpfile1, cfgfile);
|
|
||||||
fclose(out1);
|
|
||||||
if (line)
|
|
||||||
free(line);
|
|
||||||
if (tmpfile2) {
|
|
||||||
remove(tmpfile2);
|
|
||||||
free(tmpfile2);
|
|
||||||
}
|
|
||||||
if (tmpfile1) {
|
|
||||||
remove(tmpfile1);
|
|
||||||
free(tmpfile1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in a new issue