1998-10-29 23:45:59 +01:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
extern int yyparse(void);
|
1998-10-29 23:45:59 +01:00
|
|
|
extern int linecount;
|
|
|
|
extern FILE *yyin;
|
|
|
|
extern int yydebug;
|
|
|
|
struct soundcard *soundcards = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* free functions
|
|
|
|
*/
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_ctl_switch_free(struct ctl_switch *first)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
struct ctl_switch *next;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
while (first) {
|
|
|
|
next = first->next;
|
|
|
|
free(first);
|
|
|
|
first = next;
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_mixer_channel_free(struct mixer_channel *first)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
struct mixer_channel *next;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
while (first) {
|
|
|
|
next = first->next;
|
|
|
|
free(first);
|
|
|
|
first = next;
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_mixer_free1(struct mixer *mixer)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!mixer)
|
|
|
|
return;
|
|
|
|
soundcard_mixer_channel_free(mixer->channels);
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_ctl_switch_free(mixer->switches);
|
1998-11-27 16:13:57 +01:00
|
|
|
free(mixer);
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
|
|
|
|
static void soundcard_mixer_free(struct mixer *first)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
struct mixer *next;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
while (first) {
|
|
|
|
next = first->next;
|
|
|
|
soundcard_mixer_free1(first);
|
|
|
|
first = next;
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_pcm_free1(struct pcm *pcm)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!pcm)
|
|
|
|
return;
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_ctl_switch_free(pcm->pswitches);
|
|
|
|
soundcard_ctl_switch_free(pcm->rswitches);
|
1998-11-27 16:13:57 +01:00
|
|
|
free(pcm);
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
|
|
|
|
static void soundcard_pcm_free(struct pcm *first)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
struct pcm *next;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
while (first) {
|
|
|
|
next = first->next;
|
|
|
|
soundcard_pcm_free1(first);
|
|
|
|
first = next;
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_rawmidi_free1(struct rawmidi *rawmidi)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!rawmidi)
|
|
|
|
return;
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_ctl_switch_free(rawmidi->iswitches);
|
|
|
|
soundcard_ctl_switch_free(rawmidi->oswitches);
|
1998-11-27 16:13:57 +01:00
|
|
|
free(rawmidi);
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
|
|
|
|
static void soundcard_rawmidi_free(struct rawmidi *first)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
struct rawmidi *next;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
while (first) {
|
|
|
|
next = first->next;
|
|
|
|
soundcard_rawmidi_free1(first);
|
|
|
|
first = next;
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_free1(struct soundcard *soundcard)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!soundcard)
|
|
|
|
return;
|
|
|
|
soundcard_ctl_switch_free(soundcard->control.switches);
|
|
|
|
soundcard_mixer_free(soundcard->mixers);
|
|
|
|
soundcard_pcm_free(soundcard->pcms);
|
|
|
|
soundcard_rawmidi_free(soundcard->rawmidis);
|
|
|
|
free(soundcard);
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static void soundcard_free(struct soundcard *first)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
struct soundcard *next;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
while (first) {
|
|
|
|
next = first->next;
|
|
|
|
soundcard_free1(first);
|
|
|
|
first = next;
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static int soundcard_remove(int cardno)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
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;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* exported functions
|
|
|
|
*/
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
void soundcard_setup_init(void)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
soundcards = NULL;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
void soundcard_setup_done(void)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
soundcard_free(soundcards);
|
|
|
|
soundcards = NULL;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1999-03-27 20:45:01 +01:00
|
|
|
static int switch_list(void *handle, snd_switch_list_t *list, int interface, int device)
|
|
|
|
{
|
|
|
|
switch (interface) {
|
|
|
|
case 0:
|
|
|
|
return snd_ctl_switch_list(handle, list);
|
|
|
|
case 1:
|
|
|
|
return snd_ctl_mixer_switch_list(handle, device, list);
|
|
|
|
case 2:
|
|
|
|
return snd_ctl_pcm_playback_switch_list(handle, device, list);
|
|
|
|
case 3:
|
|
|
|
return snd_ctl_pcm_record_switch_list(handle, device, list);
|
|
|
|
case 4:
|
|
|
|
return snd_ctl_rawmidi_output_switch_list(handle, device, list);
|
|
|
|
case 5:
|
|
|
|
return snd_ctl_rawmidi_input_switch_list(handle, device, list);
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int switch_read(void *handle, snd_switch_t *sw, int interface, int device)
|
|
|
|
{
|
|
|
|
switch (interface) {
|
|
|
|
case 0:
|
|
|
|
return snd_ctl_switch_read(handle, sw);
|
|
|
|
case 1:
|
|
|
|
return snd_ctl_mixer_switch_read(handle, device, sw);
|
|
|
|
case 2:
|
|
|
|
return snd_ctl_pcm_playback_switch_read(handle, device, sw);
|
|
|
|
case 3:
|
|
|
|
return snd_ctl_pcm_record_switch_read(handle, device, sw);
|
|
|
|
case 4:
|
|
|
|
return snd_ctl_rawmidi_output_switch_read(handle, device, sw);
|
|
|
|
case 5:
|
|
|
|
return snd_ctl_rawmidi_input_switch_read(handle, device, sw);
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static int switch_write(void *handle, snd_switch_t *sw, int interface, int device)
|
|
|
|
{
|
|
|
|
switch (interface) {
|
|
|
|
case 0:
|
|
|
|
return snd_ctl_switch_write(handle, sw);
|
|
|
|
case 1:
|
|
|
|
return snd_ctl_mixer_switch_write(handle, device, sw);
|
|
|
|
case 2:
|
|
|
|
return snd_ctl_pcm_playback_switch_write(handle, device, sw);
|
|
|
|
case 3:
|
|
|
|
return snd_ctl_pcm_record_switch_write(handle, device, sw);
|
|
|
|
case 4:
|
|
|
|
return snd_ctl_rawmidi_output_switch_write(handle, device, sw);
|
|
|
|
case 5:
|
|
|
|
return snd_ctl_rawmidi_input_switch_write(handle, device, sw);
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int determine_switches(void *handle, struct ctl_switch **csw, int interface, int device)
|
|
|
|
{
|
|
|
|
int err, idx;
|
|
|
|
snd_switch_list_t list;
|
|
|
|
snd_switch_list_item_t *item;
|
|
|
|
snd_switch_t sw;
|
|
|
|
struct ctl_switch *prev_csw;
|
|
|
|
struct ctl_switch *new_csw;
|
|
|
|
|
|
|
|
*csw = NULL;
|
|
|
|
bzero(&list, sizeof(list));
|
|
|
|
if ((err = switch_list(handle, &list, interface, device)) < 0) {
|
|
|
|
error("Cannot determine switches for interface %i and device %i: %s", interface, device, snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (list.switches_over <= 0)
|
|
|
|
return 0;
|
|
|
|
list.switches_size = list.switches_over + 16;
|
|
|
|
list.switches = list.switches_over = 0;
|
|
|
|
list.pswitches = malloc(sizeof(snd_switch_list_item_t) * list.switches_size);
|
|
|
|
if (!list.pswitches) {
|
|
|
|
error("No enough memory...");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if ((err = switch_list(handle, &list, interface, device)) < 0) {
|
|
|
|
error("Cannot determine switches (2) for interface %i and device %i: %s", interface, device, snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
for (idx = 0, prev_csw = NULL; idx < list.switches; idx++) {
|
|
|
|
item = &list.pswitches[idx];
|
|
|
|
bzero(&sw, sizeof(sw));
|
|
|
|
strncpy(sw.name, item->name, sizeof(sw.name));
|
|
|
|
if ((err = switch_read(handle, &sw, interface, device)) < 0) {
|
|
|
|
error("Cannot read switch for interface %i and device %i: %s", interface, device, snd_strerror(err));
|
|
|
|
free(list.pswitches);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
new_csw = malloc(sizeof(*new_csw));
|
|
|
|
if (!new_csw) {
|
|
|
|
error("No enough memory...");
|
|
|
|
free(list.pswitches);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
bzero(new_csw, sizeof(*new_csw));
|
|
|
|
memcpy(&new_csw->s, &sw, sizeof(new_csw->s));
|
|
|
|
if (*csw) {
|
|
|
|
prev_csw->next = new_csw;
|
|
|
|
prev_csw = new_csw;
|
|
|
|
} else {
|
|
|
|
*csw = prev_csw = new_csw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(list.pswitches);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
int soundcard_setup_collect(int cardno)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
void *handle, *mhandle;
|
|
|
|
struct soundcard *card, *first, *prev;
|
|
|
|
int err, idx, count, device;
|
|
|
|
struct mixer *mixer, *mixerprev;
|
|
|
|
struct mixer_channel *mixerchannel, *mixerchannelprev;
|
|
|
|
struct pcm *pcm, *pcmprev;
|
|
|
|
struct rawmidi *rawmidi, *rawmidiprev;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
/* --- */
|
1999-03-27 20:45:01 +01:00
|
|
|
if (determine_switches(handle, &card->control.switches, 0, 0)) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 1;
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
/* --- */
|
|
|
|
for (device = 0, mixerprev = NULL; device < card->control.hwinfo.mixerdevs; device++) {
|
|
|
|
mixer = (struct mixer *) malloc(sizeof(struct mixer));
|
|
|
|
if (!mixer) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("malloc problem");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
bzero(mixer, sizeof(struct mixer));
|
|
|
|
mixer->no = device;
|
1999-03-27 20:45:01 +01:00
|
|
|
if (determine_switches(handle, &mixer->switches, 1, device)) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 1;
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
if (!mixerprev) {
|
|
|
|
card->mixers = mixer;
|
|
|
|
} else {
|
|
|
|
mixerprev->next = mixer;
|
|
|
|
}
|
|
|
|
mixerprev = mixer;
|
|
|
|
if ((err = snd_mixer_open(&mhandle, cardno, device)) < 0) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("MIXER open error: %s\n", snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if ((err = snd_mixer_exact_mode(mhandle, 1)) < 0) {
|
|
|
|
snd_mixer_close(mhandle);
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("MIXER exact mode error: %s\n", snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if ((err = snd_mixer_info(mhandle, &mixer->info)) < 0) {
|
|
|
|
snd_mixer_close(mhandle);
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("MIXER info error: %s\n", snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
count = snd_mixer_channels(mhandle);
|
|
|
|
for (idx = 0, mixerchannelprev = NULL; idx < count; idx++) {
|
|
|
|
mixerchannel = (struct mixer_channel *) malloc(sizeof(struct mixer_channel));
|
|
|
|
if (!mixerchannel) {
|
|
|
|
snd_mixer_close(mhandle);
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("malloc problem");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
bzero(mixerchannel, sizeof(struct mixer_channel));
|
|
|
|
mixerchannel->no = idx;
|
1999-03-08 17:51:53 +01:00
|
|
|
if ((err = snd_mixer_channel_info(mhandle, idx, &mixerchannel->info)) < 0) {
|
1998-11-27 16:13:57 +01:00
|
|
|
free(mixerchannel);
|
|
|
|
error("MIXER channel info error (%s) - skipping", snd_strerror(err));
|
|
|
|
break;
|
|
|
|
}
|
1999-03-08 17:51:53 +01:00
|
|
|
if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT) &&
|
|
|
|
(err = snd_mixer_channel_output_info(mhandle, idx, &mixerchannel->dinfo[OUTPUT])) < 0) {
|
|
|
|
free(mixerchannel);
|
|
|
|
error("MIXER channel output info error (%s) - skipping", snd_strerror(err));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_INPUT) &&
|
|
|
|
(err = snd_mixer_channel_input_info(mhandle, idx, &mixerchannel->dinfo[INPUT])) < 0) {
|
|
|
|
free(mixerchannel);
|
|
|
|
error("MIXER channel input info error (%s) - skipping", snd_strerror(err));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((err = snd_mixer_channel_read(mhandle, idx, &mixerchannel->data)) < 0) {
|
1998-11-27 16:13:57 +01:00
|
|
|
free(mixerchannel);
|
|
|
|
error("MIXER channel read error (%s) - skipping", snd_strerror(err));
|
|
|
|
break;
|
|
|
|
}
|
1999-03-08 17:51:53 +01:00
|
|
|
if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT) &&
|
|
|
|
(err = snd_mixer_channel_output_read(mhandle, idx, &mixerchannel->ddata[OUTPUT])) < 0) {
|
1999-02-15 16:42:34 +01:00
|
|
|
free(mixerchannel);
|
1999-03-08 17:51:53 +01:00
|
|
|
error("MIXER channel output read error (%s) - skipping", snd_strerror(err));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_INPUT) &&
|
|
|
|
(err = snd_mixer_channel_input_read(mhandle, idx, &mixerchannel->ddata[INPUT])) < 0) {
|
|
|
|
free(mixerchannel);
|
|
|
|
error("MIXER channel input read error (%s) - skipping", snd_strerror(err));
|
1999-02-15 16:42:34 +01:00
|
|
|
break;
|
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!mixerchannelprev) {
|
|
|
|
mixer->channels = mixerchannel;
|
|
|
|
} else {
|
|
|
|
mixerchannelprev->next = mixerchannel;
|
|
|
|
}
|
|
|
|
mixerchannelprev = mixerchannel;
|
|
|
|
}
|
|
|
|
snd_mixer_close(mhandle);
|
|
|
|
}
|
|
|
|
/* --- */
|
|
|
|
for (device = 0, pcmprev = NULL; device < card->control.hwinfo.pcmdevs; device++) {
|
|
|
|
pcm = (struct pcm *) malloc(sizeof(struct pcm));
|
|
|
|
if (!pcm) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("malloc problem");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
bzero(pcm, sizeof(struct pcm));
|
|
|
|
pcm->no = device;
|
|
|
|
if ((err = snd_ctl_pcm_info(handle, device, &pcm->info)) < 0) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("PCM info error: %s\n", snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
if (determine_switches(handle, &pcm->pswitches, 2, device)) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 1;
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
if (determine_switches(handle, &pcm->rswitches, 3, device)) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 1;
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
if (!pcmprev) {
|
|
|
|
card->pcms = pcm;
|
|
|
|
} else {
|
|
|
|
pcmprev->next = pcm;
|
|
|
|
}
|
|
|
|
pcmprev = pcm;
|
|
|
|
}
|
|
|
|
/* --- */
|
|
|
|
for (device = 0, rawmidiprev = NULL; device < card->control.hwinfo.mididevs; device++) {
|
|
|
|
rawmidi = (struct rawmidi *) malloc(sizeof(struct rawmidi));
|
|
|
|
if (!rawmidi) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("malloc problem");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
bzero(rawmidi, sizeof(struct rawmidi));
|
|
|
|
rawmidi->no = device;
|
|
|
|
if ((err = snd_ctl_rawmidi_info(handle, device, &rawmidi->info)) < 0) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
error("RAWMIDI info error: %s\n", snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
if (determine_switches(handle, &rawmidi->oswitches, 4, device)) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 1;
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
if (determine_switches(handle, &rawmidi->iswitches, 5, device)) {
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 1;
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
if (!rawmidiprev) {
|
|
|
|
card->rawmidis = rawmidi;
|
|
|
|
} else {
|
|
|
|
rawmidiprev->next = rawmidi;
|
|
|
|
}
|
|
|
|
rawmidiprev = rawmidi;
|
|
|
|
}
|
|
|
|
/* --- */
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
return 0;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-20 21:02:51 +01:00
|
|
|
int soundcard_setup_load(const char *cfgfile, int skip)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
extern int yyparse(void);
|
|
|
|
extern int linecount;
|
|
|
|
extern FILE *yyin;
|
|
|
|
extern int yydebug;
|
|
|
|
int xtry;
|
1998-10-29 23:45:59 +01:00
|
|
|
|
|
|
|
#ifdef YYDEBUG
|
1998-11-27 16:13:57 +01:00
|
|
|
yydebug = 1;
|
1998-10-29 23:45:59 +01:00
|
|
|
#endif
|
1998-11-27 16:13:57 +01:00
|
|
|
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;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1999-03-27 20:45:01 +01:00
|
|
|
static void soundcard_setup_write_switch(FILE * out, const char *space, int interface, snd_switch_t *sw)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
char *s, v[16];
|
|
|
|
int idx, first, switchok = 0;
|
|
|
|
|
|
|
|
v[0] = '\0';
|
1999-03-27 20:45:01 +01:00
|
|
|
switch (sw->type) {
|
|
|
|
case SND_SW_TYPE_BOOLEAN:
|
1998-11-27 16:13:57 +01:00
|
|
|
s = "bool";
|
1999-03-27 20:45:01 +01:00
|
|
|
strcpy(v, sw->value.enable ? "true" : "false");
|
1998-11-27 16:13:57 +01:00
|
|
|
break;
|
1999-03-27 20:45:01 +01:00
|
|
|
case SND_SW_TYPE_BYTE:
|
1998-11-27 16:13:57 +01:00
|
|
|
s = "byte";
|
1999-03-27 20:45:01 +01:00
|
|
|
sprintf(v, "%u", (unsigned int) sw->value.data8[0]);
|
1998-11-27 16:13:57 +01:00
|
|
|
break;
|
1999-03-27 20:45:01 +01:00
|
|
|
case SND_SW_TYPE_WORD:
|
1998-11-27 16:13:57 +01:00
|
|
|
s = "word";
|
1998-12-05 12:19:22 +01:00
|
|
|
if (interface == SND_INTERFACE_CONTROL &&
|
1999-03-27 20:45:01 +01:00
|
|
|
!strcmp(sw->name, SND_CTL_SW_JOYSTICK_ADDRESS)) {
|
|
|
|
sprintf(v, "0x%x", (unsigned int) sw->value.data16[0]);
|
1998-12-05 12:19:22 +01:00
|
|
|
} else {
|
1999-03-27 20:45:01 +01:00
|
|
|
sprintf(v, "%u", (unsigned int) sw->value.data16[0]);
|
1998-12-05 12:19:22 +01:00
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
break;
|
1999-03-27 20:45:01 +01:00
|
|
|
case SND_SW_TYPE_DWORD:
|
1998-11-27 16:13:57 +01:00
|
|
|
s = "dword";
|
1999-03-27 20:45:01 +01:00
|
|
|
sprintf(v, "%u", sw->value.data32[0]);
|
1998-11-27 16:13:57 +01:00
|
|
|
break;
|
1999-03-27 20:45:01 +01:00
|
|
|
case SND_SW_TYPE_USER:
|
1998-11-27 16:13:57 +01:00
|
|
|
s = "user";
|
|
|
|
break;
|
1999-03-27 20:45:01 +01:00
|
|
|
case SND_SW_TYPE_LIST:
|
|
|
|
s = "list";
|
|
|
|
sprintf(v, "%u", sw->value.item_number);
|
|
|
|
break;
|
1998-11-27 16:13:57 +01:00
|
|
|
default:
|
|
|
|
s = "unknown";
|
|
|
|
}
|
|
|
|
fprintf(out, "%s; Type is '%s'.\n", space, s);
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->low != 0 || sw->high != 0)
|
|
|
|
fprintf(out, "%s; Accepted switch range is from %u to %u.\n", space, sw->low, sw->high);
|
|
|
|
if (interface == SND_INTERFACE_CONTROL && sw->type == SND_SW_TYPE_WORD &&
|
|
|
|
!strcmp(sw->name, SND_CTL_SW_JOYSTICK_ADDRESS)) {
|
1998-11-27 16:13:57 +01:00
|
|
|
for (idx = 1, first = 1; idx < 16; idx++) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->value.data16[idx]) {
|
1998-11-27 16:13:57 +01:00
|
|
|
if (first) {
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "%s; Available addresses - 0x%x", space, sw->value.data16[idx]);
|
1998-11-27 16:13:57 +01:00
|
|
|
first = 0;
|
|
|
|
} else {
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, ", 0x%x", sw->value.data16[idx]);
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!first)
|
|
|
|
fprintf(out, "\n");
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
if (interface == SND_INTERFACE_MIXER && sw->type == SND_SW_TYPE_BOOLEAN &&
|
|
|
|
!strcmp(sw->name, SND_MIXER_SW_IEC958OUT)) {
|
|
|
|
fprintf(out, "%sswitch( \"%s\", ", space, sw->name);
|
|
|
|
if (sw->value.data32[1] == (('C' << 8) | 'S')) { /* Cirrus Crystal */
|
1998-11-27 16:13:57 +01:00
|
|
|
switchok = 0;
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "iec958ocs( %s", sw->value.enable ? "enable" : "disable");
|
|
|
|
if (sw->value.data16[4] & 0x2000)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " 3d");
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->value.data16[4] & 0x0040)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " reset");
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->value.data16[4] & 0x0020)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " user");
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->value.data16[4] & 0x0010)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " valid");
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->value.data16[5] & 0x0002)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " data");
|
1999-03-27 20:45:01 +01:00
|
|
|
if (!(sw->value.data16[5] & 0x0004))
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " protect");
|
1999-03-27 20:45:01 +01:00
|
|
|
switch (sw->value.data16[5] & 0x0018) {
|
1998-11-27 16:13:57 +01:00
|
|
|
case 0x0008:
|
|
|
|
fprintf(out, " pre2");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->value.data16[5] & 0x0020)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " fsunlock");
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, " type( 0x%x )", (sw->value.data16[5] >> 6) & 0x7f);
|
|
|
|
if (sw->value.data16[5] & 0x2000)
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " gstatus");
|
|
|
|
fprintf(out, " )");
|
|
|
|
goto __end;
|
|
|
|
}
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "%sswitch(\"%s\", ", space, sw->name);
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!switchok) {
|
|
|
|
fprintf(out, v);
|
1999-03-27 20:45:01 +01:00
|
|
|
if (sw->type < 0 || sw->type > SND_SW_TYPE_LIST_ITEM) {
|
1998-11-27 16:13:57 +01:00
|
|
|
/* TODO: some well known types should be verbose */
|
|
|
|
fprintf(out, " rawdata( ");
|
|
|
|
for (idx = 0; idx < 31; idx++) {
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "@%02x:", sw->value.data8[idx]);
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "%02x@ )\n", sw->value.data8[31]);
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
__end:
|
|
|
|
fprintf(out, " )\n");
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1999-03-27 20:45:01 +01:00
|
|
|
static void soundcard_setup_write_switches(FILE *out, const char *space, int interface, struct ctl_switch **switches)
|
|
|
|
{
|
|
|
|
struct ctl_switch *sw;
|
|
|
|
|
|
|
|
if (!(*switches))
|
|
|
|
return;
|
|
|
|
for (sw = *switches; sw; sw = sw->next)
|
|
|
|
soundcard_setup_write_switch(out, space, interface, &sw->s);
|
|
|
|
}
|
1998-10-29 23:45:59 +01:00
|
|
|
|
1999-03-08 17:51:53 +01:00
|
|
|
static void soundcard_setup_write_mixer_channel(FILE * out, struct mixer_channel * channel)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1999-03-08 17:51:53 +01:00
|
|
|
int k, d;
|
|
|
|
struct capdes {
|
|
|
|
unsigned int flag;
|
|
|
|
char* description;
|
|
|
|
};
|
|
|
|
static struct capdes caps[] = {
|
|
|
|
{ SND_MIXER_CINFO_CAP_OUTPUT, "output" },
|
|
|
|
{ SND_MIXER_CINFO_CAP_INPUT, "input" },
|
|
|
|
{ SND_MIXER_CINFO_CAP_EXTINPUT, "external-input" },
|
|
|
|
{ SND_MIXER_CINFO_CAP_EFFECT, "effect" }
|
|
|
|
};
|
|
|
|
static struct capdes dcaps[] = {
|
|
|
|
{ SND_MIXER_CINFO_DCAP_STEREO, "stereo" },
|
|
|
|
{ SND_MIXER_CINFO_DCAP_HWMUTE, "hardware-mute" },
|
|
|
|
{ SND_MIXER_CINFO_DCAP_JOINMUTE, "join-mute" },
|
|
|
|
{ SND_MIXER_CINFO_DCAP_ROUTE, "route" },
|
|
|
|
{ SND_MIXER_CINFO_DCAP_SWAPROUTE, "swap-route" },
|
|
|
|
{ SND_MIXER_CINFO_DCAP_DIGITAL, "digital" },
|
|
|
|
{ SND_MIXER_CINFO_DCAP_RECORDBYMUTE, "recordbymute" },
|
|
|
|
};
|
|
|
|
|
|
|
|
fprintf(out, " ; Capabilities:");
|
|
|
|
for (k = 0; k < sizeof(caps)/sizeof(*caps); ++k) {
|
|
|
|
if (channel->info.caps & caps[k].flag)
|
|
|
|
fprintf(out, " %s", caps[k].description);
|
|
|
|
}
|
|
|
|
fprintf(out, "\n");
|
|
|
|
for (d = OUTPUT; d <= INPUT; ++d) {
|
|
|
|
snd_mixer_channel_direction_info_t *di;
|
|
|
|
if (d == OUTPUT &&
|
|
|
|
!(channel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT))
|
|
|
|
continue;
|
|
|
|
if (d == INPUT &&
|
|
|
|
!(channel->info.caps & SND_MIXER_CINFO_CAP_INPUT))
|
|
|
|
continue;
|
|
|
|
di = &channel->dinfo[d];
|
|
|
|
fprintf(out, " ; %s capabilities:",
|
|
|
|
d == OUTPUT ? "Output" : "Input" );
|
|
|
|
if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
|
|
|
|
fprintf(out, " volume(%i, %i)", di->min, di->max);
|
|
|
|
for (k = 0; k < sizeof(caps)/sizeof(*caps); ++k) {
|
|
|
|
if (di->caps & dcaps[k].flag)
|
|
|
|
fprintf(out, " %s", dcaps[k].description);
|
|
|
|
}
|
|
|
|
fprintf(out, "\n");
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, " channel(\"%s\"", channel->info.name);
|
1999-03-08 17:51:53 +01:00
|
|
|
for (d = OUTPUT; d <= INPUT; ++d) {
|
|
|
|
snd_mixer_channel_direction_info_t *di;
|
|
|
|
snd_mixer_channel_direction_t *dd;
|
|
|
|
if (d == OUTPUT &&
|
|
|
|
!(channel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT))
|
|
|
|
continue;
|
|
|
|
if (d == INPUT &&
|
|
|
|
!(channel->info.caps & SND_MIXER_CINFO_CAP_INPUT))
|
|
|
|
continue;
|
|
|
|
dd = &channel->ddata[d];
|
|
|
|
di = &channel->dinfo[d];
|
|
|
|
fprintf(out, ", %s ", d == OUTPUT ? "output" : "input" );
|
|
|
|
if (di->caps & SND_MIXER_CINFO_DCAP_STEREO) {
|
|
|
|
fprintf(out, "stereo(");
|
|
|
|
if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
|
|
|
|
fprintf(out, " %i", dd->left);
|
|
|
|
fprintf(out, "%s%s,",
|
|
|
|
dd->flags & SND_MIXER_DFLG_MUTE_LEFT ? " mute" : "",
|
|
|
|
dd->flags & SND_MIXER_DFLG_LTOR ? " swap" : ""
|
|
|
|
);
|
|
|
|
if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
|
|
|
|
fprintf(out, " %i", dd->right);
|
|
|
|
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "%s%s)",
|
1999-03-08 17:51:53 +01:00
|
|
|
dd->flags & SND_MIXER_DFLG_MUTE_RIGHT ? " mute" : "",
|
|
|
|
dd->flags & SND_MIXER_DFLG_RTOL ? " swap" : ""
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(out, "mono(");
|
|
|
|
if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
|
|
|
|
fprintf(out, " %i", (dd->left + dd->right)/2);
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "%s)",
|
1999-03-08 17:51:53 +01:00
|
|
|
dd->flags & SND_MIXER_DFLG_MUTE ? " mute" : ""
|
|
|
|
);
|
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
fprintf(out, " )\n");
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
int soundcard_setup_write(const char *cfgfile)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
FILE *out;
|
|
|
|
struct soundcard *first;
|
|
|
|
struct mixer *mixer;
|
|
|
|
struct mixer_channel *mixerchannel;
|
|
|
|
struct pcm *pcm;
|
|
|
|
struct rawmidi *rawmidi;
|
|
|
|
|
|
|
|
if ((out = fopen(cfgfile, "w+")) == NULL) {
|
|
|
|
error("Cannot open file '%s' for writing...\n", cfgfile);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
fprintf(out, "# ALSA driver configuration\n");
|
|
|
|
fprintf(out, "# Generated by alsactl\n");
|
|
|
|
fprintf(out, "\n");
|
|
|
|
for (first = soundcards; first; first = first->next) {
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id);
|
1998-11-27 16:13:57 +01:00
|
|
|
if (first->control.switches) {
|
|
|
|
fprintf(out, " control {\n");
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_setup_write_switches(out, " ", SND_INTERFACE_CONTROL, &first->control.switches);
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
for (mixer = first->mixers; mixer; mixer = mixer->next) {
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, " mixer(\"%s\") {\n", mixer->info.name);
|
|
|
|
soundcard_setup_write_switches(out, " ", SND_INTERFACE_MIXER, &mixer->switches);
|
1998-11-27 16:13:57 +01:00
|
|
|
for (mixerchannel = mixer->channels; mixerchannel; mixerchannel = mixerchannel->next)
|
1999-03-08 17:51:53 +01:00
|
|
|
soundcard_setup_write_mixer_channel(out, mixerchannel);
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
for (pcm = first->pcms; pcm; pcm = pcm->next) {
|
|
|
|
if (!pcm->pswitches && !pcm->rswitches)
|
|
|
|
continue;
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, " pcm(\"%s\") {\n", pcm->info.name);
|
1998-11-27 16:13:57 +01:00
|
|
|
if (pcm->pswitches) {
|
|
|
|
fprintf(out, " playback {");
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_setup_write_switches(out, " ", SND_INTERFACE_PCM, &pcm->pswitches);
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
if (pcm->rswitches) {
|
|
|
|
fprintf(out, " record {");
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_setup_write_switches(out, " ", SND_INTERFACE_PCM, &pcm->rswitches);
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
for (rawmidi = first->rawmidis; rawmidi; rawmidi = rawmidi->next) {
|
|
|
|
if (!rawmidi->oswitches && !rawmidi->iswitches)
|
|
|
|
continue;
|
1999-03-27 20:45:01 +01:00
|
|
|
fprintf(out, " rawmidi(\"%s\") {\n", rawmidi->info.name);
|
1998-11-27 16:13:57 +01:00
|
|
|
if (rawmidi->oswitches) {
|
|
|
|
fprintf(out, " output {");
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_setup_write_switches(out, " ", SND_INTERFACE_RAWMIDI, &rawmidi->oswitches);
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
if (rawmidi->iswitches) {
|
|
|
|
fprintf(out, " input {");
|
1999-03-27 20:45:01 +01:00
|
|
|
soundcard_setup_write_switches(out, " ", SND_INTERFACE_RAWMIDI, &rawmidi->iswitches);
|
1998-11-27 16:13:57 +01:00
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
fprintf(out, " }\n");
|
|
|
|
}
|
|
|
|
fprintf(out, "}\n%s", first->next ? "\n" : "");
|
|
|
|
}
|
|
|
|
fclose(out);
|
|
|
|
return 0;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static int soundcard_open_ctl(void **ctlhandle, struct soundcard *soundcard)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
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;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
static int soundcard_open_mix(void **mixhandle, struct soundcard *soundcard, struct mixer *mixer)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (*mixhandle)
|
|
|
|
return 0;
|
|
|
|
if ((err = snd_mixer_open(mixhandle, soundcard->no, mixer->no)) < 0) {
|
|
|
|
error("Cannot open mixer interface for soundcard #%i.", soundcard->no + 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if ((err = snd_mixer_exact_mode(*mixhandle, 1)) < 0) {
|
|
|
|
error("Cannot setup exact mode for mixer #%i/#%i: %s", soundcard->no + 1, mixer->no, snd_strerror(err));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|
|
|
|
|
1998-11-27 16:13:57 +01:00
|
|
|
int soundcard_setup_process(int cardno)
|
1998-10-29 23:45:59 +01:00
|
|
|
{
|
1998-11-27 16:13:57 +01:00
|
|
|
int err;
|
|
|
|
void *ctlhandle = NULL;
|
|
|
|
void *mixhandle = NULL;
|
|
|
|
struct soundcard *soundcard;
|
|
|
|
struct ctl_switch *ctlsw;
|
|
|
|
struct mixer *mixer;
|
|
|
|
struct mixer_channel *channel;
|
|
|
|
struct pcm *pcm;
|
|
|
|
struct rawmidi *rawmidi;
|
|
|
|
|
|
|
|
for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
|
|
|
|
if (cardno >= 0 && soundcard->no != cardno)
|
|
|
|
continue;
|
|
|
|
for (ctlsw = soundcard->control.switches; ctlsw; ctlsw = ctlsw->next) {
|
|
|
|
if (ctlsw->change)
|
|
|
|
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
|
1998-11-27 16:13:57 +01:00
|
|
|
error("Control switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
|
|
|
|
for (channel = mixer->channels; channel; channel = channel->next)
|
1999-03-08 17:51:53 +01:00
|
|
|
if (!soundcard_open_mix(&mixhandle, soundcard, mixer)) {
|
|
|
|
if ((channel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT) &&
|
|
|
|
(err = snd_mixer_channel_output_write(mixhandle, channel->no, &channel->ddata[OUTPUT])) < 0)
|
|
|
|
error("Mixer channel '%s' write error: %s", channel->info.name, snd_strerror(err));
|
|
|
|
if ((channel->info.caps & SND_MIXER_CINFO_CAP_INPUT) &&
|
|
|
|
(err = snd_mixer_channel_input_write(mixhandle, channel->no, &channel->ddata[INPUT])) < 0)
|
|
|
|
error("Mixer channel '%s' record write error: %s", channel->info.name, snd_strerror(err));
|
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
if (mixhandle) {
|
|
|
|
snd_mixer_close(mixhandle);
|
|
|
|
mixhandle = NULL;
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
for (ctlsw = mixer->switches; ctlsw; ctlsw = ctlsw->next)
|
|
|
|
if (ctlsw->change)
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if ((err = snd_ctl_mixer_switch_write(ctlhandle, mixer->no, &ctlsw->s)) < 0)
|
|
|
|
error("Mixer switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (pcm = soundcard->pcms; pcm; pcm = pcm->next) {
|
1999-03-27 20:45:01 +01:00
|
|
|
for (ctlsw = pcm->pswitches; ctlsw; ctlsw = ctlsw->next) {
|
|
|
|
if (ctlsw->change)
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if ((err = snd_ctl_pcm_playback_switch_write(ctlhandle, pcm->no, &ctlsw->s)) < 0)
|
|
|
|
error("PCM playback switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
for (ctlsw = pcm->rswitches; ctlsw; ctlsw = ctlsw->next) {
|
|
|
|
if (ctlsw->change)
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if ((err = snd_ctl_pcm_record_switch_write(ctlhandle, pcm->no, &ctlsw->s)) < 0)
|
|
|
|
error("PCM record switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (rawmidi = soundcard->rawmidis; rawmidi; rawmidi = rawmidi->next) {
|
1999-03-27 20:45:01 +01:00
|
|
|
for (ctlsw = rawmidi->oswitches; ctlsw; ctlsw = ctlsw->next) {
|
|
|
|
if (ctlsw->change)
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if ((err = snd_ctl_rawmidi_output_switch_write(ctlhandle, rawmidi->no, &ctlsw->s)) < 0)
|
|
|
|
error("RAWMIDI output switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
1999-03-27 20:45:01 +01:00
|
|
|
for (ctlsw = rawmidi->iswitches; ctlsw; ctlsw = ctlsw->next) {
|
|
|
|
if (ctlsw->change)
|
1998-11-27 16:13:57 +01:00
|
|
|
if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
|
1999-03-27 20:45:01 +01:00
|
|
|
if ((err = snd_ctl_rawmidi_output_switch_write(ctlhandle, rawmidi->no, &ctlsw->s)) < 0)
|
|
|
|
error("RAWMIDI input switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-12-05 12:19:22 +01:00
|
|
|
if(ctlhandle) {
|
|
|
|
snd_ctl_close(ctlhandle);
|
|
|
|
ctlhandle = NULL;
|
|
|
|
}
|
1998-11-27 16:13:57 +01:00
|
|
|
}
|
1999-01-19 11:08:51 +01:00
|
|
|
return 0;
|
1998-10-29 23:45:59 +01:00
|
|
|
}
|