alsa-utils/xamixer2/cinit.c
1999-07-20 22:00:59 +00:00

386 lines
13 KiB
C

/*****************************************************************************
cinit.c - routines to initialize the mixer devices
Written by Raistlinn (lansdoct@cs.alfred.edu)
Copyright (C) 1998 by Christopher Lansdown
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
/*****************************************************************************/
/* Begin #include's */
#include "main.h"
/* End #include's */
/*****************************************************************************/
/*****************************************************************************/
/* Begin Global Variables */
extern Card *card; /* And array of the cards */
extern int cards; /* The number of cards in the system. */
extern Config config; /* The system config */
/* End Global Variables */
/*****************************************************************************/
/*****************************************************************************/
/* Begin function prototypes */
int init_group(void *handle, Group *group);
int init_element_route(void *handle, snd_mixer_routes_t *routes, snd_mixer_eid_t *eid);
int misc_group_hack(Mixer *mixer, int index);
/* End function prototypes */
/*****************************************************************************/
int init_cards()
{
int i,j,k;
int err;
snd_ctl_t *handle;
cards = snd_cards();
card = calloc(cards, sizeof(Card));
for(i = 0; i < cards; i++) {
/* Open the hardware */
if((err = snd_ctl_open(&handle, i)) < 0) {
printf("Unable to open card #%i!\nError: %s\n", i, snd_strerror(err));
card[i].mixer = NULL;
card[i].number = -1;
continue;
} else {
card[i].number = i;
}
/* Get the hardware info - the primary use of this is to find out how many
mixer devices the card has, but it's also useful to find out the human-readable
name of the card. */
if((err = snd_ctl_hw_info(handle, &card[i].hw_info)) < 0) {
printf("Unable to get hardware information about card #%i!\nError: %s\n",
i, snd_strerror(err));
printf("Trying to guess the appropriate values.\n");
card[i].hw_info.mixerdevs = 1;
}
/* Allocate out the mixer array */
card[i].mixer = calloc(card[i].hw_info.mixerdevs, sizeof(Mixer));
for(j = 0; j < card[i].hw_info.mixerdevs; j++) {
/* Open the mixer to begin with. Isn't it funny how there's all this
nice generalized code that can handle nearly any situation, and it
will be necessary in only a very small percentage of the situations.
Oh well, I guess that that's what distinguishes us from windows. :-) */
if((err = snd_mixer_open(&card[i].mixer[j].handle, i, j)) < 0) {
printf("Unable to open mixer #%i on card #%i~\nError: %s\n",
j, i, snd_strerror(err));
card[i].mixer[j].number = -1;
} else {
card[i].mixer[j].number = j;
}
/* Get the mixer info */
if((err = snd_mixer_info(card[i].mixer[j].handle, &card[i].mixer[j].info)) < 0) {
printf("Unable to get the info for mixer #%i on card %i! Error: %s\n", j, i, snd_strerror(err));
printf("There's not much more I can do on this mixer.");
printf(" Shutting it down.\n");
if((err = snd_mixer_close(card[i].mixer[j].handle)) < 0) {
printf("Oh well. I couldn't even close the mixer. I suspect that something is seriously wrong here. Good luck.\n");
}
card[i].mixer[j].number = -1;
continue;
}
bzero(&card[i].mixer[j].groups, sizeof(snd_mixer_groups_t));
if ((err = snd_mixer_groups(card[i].mixer[j].handle,
&card[i].mixer[j].groups)) < 0) {
printf("Mixer %i/%i groups error: %s",
i, j, snd_strerror(err));
return -1;
}
/* Allocate the space for the group array */
card[i].mixer[j].groups.pgroups = (snd_mixer_gid_t *)
calloc(card[i].mixer[j].groups.groups_over,
sizeof(snd_mixer_gid_t));
if (!card[i].mixer[j].groups.pgroups) {
printf("No enough memory");
return -1;
}
card[i].mixer[j].groups.groups_size = card[i].mixer[j].info.groups;
card[i].mixer[j].groups.groups_over = card[i].mixer[j].groups.groups = 0;
if ((err = snd_mixer_groups(card[i].mixer[j].handle,
&card[i].mixer[j].groups)) < 0) {
printf("Mixer %i/%i groups (2) error: %s",
i, j, snd_strerror(err));
return -1;
}
/* Allocate the space for the array of the groups - this is more than
just their gid's, it's got group-specific info in it */
card[i].mixer[j].group = calloc(card[i].mixer[j].info.groups + 1,
sizeof(Group));
/* get the group structures filled out */
for(k = 0; k < card[i].mixer[j].info.groups; k++) {
card[i].mixer[j].group[k].group.gid =
card[i].mixer[j].groups.pgroups[k];
init_group(card[i].mixer[j].handle,
&card[i].mixer[j].group[k]);
}
misc_group_hack(&card[i].mixer[j], k);
}
if((err = snd_ctl_close(handle)) < 0) {
printf("strange, there was an error closing card #%i!\nError: %s\n",
i, snd_strerror(err));
printf("Oh well.\n");
}
}
/* return a successful execution. */
return 0;
}
int misc_group_hack(Mixer *mixer, int index)
{
/* This code is largely copied straight from amixer. - God I love the GPL. */
snd_mixer_elements_t elements;
snd_mixer_eid_t *element;
snd_mixer_group_t *group;
int err, idx, gdx, idx2;
int flag;
int count=0; /* The count of elements not in any group */
snd_mixer_eid_t **array;
bzero(&elements, sizeof(elements));
if ((err = snd_mixer_elements(mixer->handle, &elements)) < 0) {
printf("Mixer elements error: %s", snd_strerror(err));
return -1;
}
elements.pelements = (snd_mixer_eid_t *)malloc(elements.elements_over *
sizeof(snd_mixer_eid_t));
if (!elements.pelements) {
printf("Not enough memory");
return -1;
}
elements.elements_size = elements.elements_over;
elements.elements_over = elements.elements = 0;
if ((err = snd_mixer_elements(mixer->handle, &elements)) < 0) {
printf("Mixer elements (2) error: %s", snd_strerror(err));
return -1;
}
/* Allocate the temporary array to hold the mixer ID structs */
array = malloc(elements.elements * sizeof(snd_mixer_eid_t *));
if(!array)
printf("Not enough memory.\n");
for (idx = 0; idx < elements.elements; idx++) {
element = &elements.pelements[idx];
flag = 0; /* The flag will be set if the same element name & type
is encountered */
for(gdx = 0; gdx < mixer->info.groups; gdx++) {
group = &mixer->group[gdx].group;
for(idx2 = 0; idx2 < group->elements; idx2++) {
if(group && element)
if(group->pelements[idx2].type == element->type &&
is_same(group->pelements[idx2].name, element->name))
flag = 1;
}
}
if(!flag) {
/* We found a mixer element that's not in a group */
array[count] = element;
count++;
if(count > elements.elements)
printf("Houston, we have a problem.\n");
}
}
/* Set up the group member */
strncpy(mixer->group[index].group.gid.name, "Miscellaneous\0", 24);
mixer->group[index].group.gid.index = 0;
mixer->group[index].group.elements_size = 0; /* I hope that this doesn't matter */
mixer->group[index].group.elements = count;
mixer->group[index].group.elements_over = 0; /* I hope tha this doesn't matter */
mixer->group[index].group.pelements = (snd_mixer_eid_t *)malloc(count *
sizeof(snd_mixer_eid_t));
mixer->group[index].routes = calloc(mixer->group[index].group.elements,
sizeof(snd_mixer_routes_t));
mixer->group[index].element = calloc(mixer->group[index].group.elements,
sizeof(snd_mixer_element_t));
mixer->group[index].einfo = calloc(mixer->group[index].group.elements,
sizeof(snd_mixer_element_info_t));
mixer->group[index].gtk = calloc(mixer->group[index].group.elements,
sizeof(Gtk_Channel));
/* Copy the snd_mixer_eid_t structures into the new group structure and init the routes */
for(idx = 0; idx < count; idx++) {
mixer->group[index].group.pelements[idx] = *array[idx];
mixer->group[index].einfo[idx].eid = mixer->group[index].group.pelements[idx];
if(snd_mixer_element_has_info(&mixer->group[index].group.pelements[idx]) == 1)
if((err =
snd_mixer_element_info_build(mixer->handle,
&mixer->group[index].einfo[idx])) < 0) {
printf("Unable to get element information for element %s! ",
mixer->group[index].group.pelements[idx].name);
printf("Error: %s.\n", snd_strerror(err));
}
mixer->group[index].element[idx].eid = mixer->group[index].group.pelements[idx];
if(snd_mixer_element_has_control(&mixer->group[index].element[idx].eid))
if((err = snd_mixer_element_build(mixer->handle,
&mixer->group[index].element[idx])) < 0) {
printf("Unable to read element %s! ",
mixer->group[index].group.pelements[idx].name);
printf("Error: %s.\n", snd_strerror(err));
}
init_element_route(mixer->handle,
&mixer->group[index].routes[idx],
&mixer->group[index].group.pelements[idx]);
}
/* Increase the number of groups to include the new group */
mixer->info.groups++;
if(elements.pelements)
free(elements.pelements);
if(array)
free(array);
return 1;
}
int init_group(void *handle, Group *group)
{
/* This is largely a mess copied from amixer that gets the group info in a very strange
way, I wish that I knew how it really worked. Anyhow, once we get the group into
and the info about the elements in the group, we'll set up the element array. */
int idx, err;
if((err = snd_mixer_group_read(handle,
&group->group)) < 0) {
printf("Unable to get info for group %s! ", group->group.gid.name);
printf("Error: %s\n", snd_strerror(err));
printf("elements_size = %i, elements_over=%i, elements=%i\n",
group->group.elements_size,
group->group.elements_over,
group->group.elements);
return 0;
}
group->group.pelements = (snd_mixer_eid_t *)calloc(group->group.elements_over,
sizeof(snd_mixer_eid_t));
if (!group->group.pelements) {
printf("Not enough memory...");
return 0;
}
group->group.elements_size = group->group.elements_over;
group->group.elements = group->group.elements_over = 0;
if ((err = snd_mixer_group_read(handle, &group->group)) < 0) {
printf("Unable to get second group info for group %s. Error: %s\n",
group->group.gid.name, snd_strerror(err));
printf("elements_size = %i, elements_over=%i, elements=%i\n",
group->group.elements_size,
group->group.elements_over,
group->group.elements);
return 0;
}
/* Allocate out the arrays for the elements and element info */
group->element = calloc(group->group.elements, sizeof(snd_mixer_element_t));
group->einfo = calloc(group->group.elements, sizeof(snd_mixer_element_info_t));
group->routes = calloc(group->group.elements, sizeof(snd_mixer_routes_t));
group->gtk = calloc(group->group.elements, sizeof(Gtk_Channel));
/* Now go through and get that info */
for (idx = 0; idx < group->group.elements; idx++) {
group->einfo[idx].eid = group->group.pelements[idx];
if(snd_mixer_element_has_info(&group->group.pelements[idx]) == 1)
if((err = snd_mixer_element_info_build(handle, &group->einfo[idx])) < 0) {
printf("Unable to get element information for element %s! ",
group->group.pelements[idx].name);
printf("Error: %s.\n", snd_strerror(err));
}
group->element[idx].eid = group->group.pelements[idx];
if((err = snd_mixer_element_build(handle, &group->element[idx])) < 0) {
printf("Unable to read element %s! ",
group->group.pelements[idx].name);
printf("Error: %s.\n", snd_strerror(err));
}
init_element_route(handle, &group->routes[idx], &group->group.pelements[idx]);
}
return 1;
}
int init_element_route(void *handle, snd_mixer_routes_t *routes, snd_mixer_eid_t *eid)
{
int err, idx;
/* Most of this code is taken straight from amixer as well. */
/* This just gets the routes for the mixer element and stores them. */
bzero(routes, sizeof(snd_mixer_routes_t));
routes->eid = *eid;
if ((err = snd_mixer_routes(handle, routes)) < 0) {
printf("Element %s route error: %s", eid->name, snd_strerror(err));
return -1;
}
if (!routes->routes_over)
return 0;
routes->proutes = (snd_mixer_eid_t *)malloc(routes->routes_over *
sizeof(snd_mixer_eid_t));
if (!routes->proutes) {
printf("No enough memory...");
return -1;
}
routes->routes_size = routes->routes_over;
routes->routes = routes->routes_over = 0;
if ((err = snd_mixer_routes(handle, routes)) < 0) {
printf("Element (2) %s route error: %s", eid->name, snd_strerror(err));
return -1;
}
return 1;
}