[ALSA] usb-audio - move mixer data into separate struct

USB generic driver
Move all data related to audio control interfaces into a separate struct
local to usbmixer.c.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
This commit is contained in:
Clemens Ladisch 2005-04-29 16:23:13 +02:00 committed by Jaroslav Kysela
parent 707e60732f
commit 84957a8ab0
3 changed files with 105 additions and 45 deletions

View File

@ -3091,6 +3091,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->card = card;
INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_usb_audio_free(chip);
@ -3290,6 +3291,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p);
}
/* release mixer resources */
list_for_each(p, &chip->mixer_list) {
snd_usb_mixer_disconnect(p);
}
usb_chip[chip->index] = NULL;
up(&register_mutex);
snd_card_free(card);

View File

@ -136,7 +136,7 @@ struct snd_usb_audio {
struct list_head midi_list; /* list of midi interfaces */
int next_midi_device;
unsigned int ignore_ctl_error; /* for mixer */
struct list_head mixer_list; /* list of mixer interfaces */
};
/*
@ -219,6 +219,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif);
void snd_usb_mixer_disconnect(struct list_head *p);
int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk);
void snd_usbmidi_input_stop(struct list_head* p);

View File

@ -50,6 +50,14 @@ typedef struct usb_audio_term usb_audio_term_t;
typedef struct usb_mixer_elem_info usb_mixer_elem_info_t;
struct usb_mixer_interface {
snd_usb_audio_t *chip;
unsigned int ctrlif;
struct list_head list;
unsigned int ignore_ctl_error;
};
struct usb_audio_term {
int id;
int type;
@ -62,9 +70,9 @@ struct usbmix_name_map;
struct usb_mixer_build {
snd_usb_audio_t *chip;
struct usb_mixer_interface *mixer;
unsigned char *buffer;
unsigned int buflen;
unsigned int ctrlif;
unsigned short vendor;
unsigned short product;
DECLARE_BITMAP(unitbitmap, 256);
@ -74,8 +82,7 @@ struct usb_mixer_build {
};
struct usb_mixer_elem_info {
snd_usb_audio_t *chip;
unsigned int ctrlif;
struct usb_mixer_interface *mixer;
unsigned int id;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
@ -317,16 +324,18 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
int timeout = 10;
while (timeout-- > 0) {
if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
if (snd_usb_ctl_msg(cval->mixer->chip->dev,
usb_rcvctrlpipe(cval->mixer->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, cval->ctrlif | (cval->id << 8),
validx, cval->mixer->ctrlif | (cval->id << 8),
buf, val_len, 100) >= 0) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
return 0;
}
}
snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type);
snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
return -EINVAL;
}
@ -355,13 +364,15 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
while (timeout -- > 0)
if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
if (snd_usb_ctl_msg(cval->mixer->chip->dev,
usb_sndctrlpipe(cval->mixer->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, cval->ctrlif | (cval->id << 8),
validx, cval->mixer->ctrlif | (cval->id << 8),
buf, val_len, 100) >= 0)
return 0;
snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
return -EINVAL;
}
@ -401,12 +412,13 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou
* if failed, give up and free the control instance.
*/
static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl)
static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl)
{
int err;
while (snd_ctl_find_id(card, &kctl->id))
while (snd_ctl_find_id(state->chip->card, &kctl->id))
kctl->id.index++;
if ((err = snd_ctl_add(card, kctl)) < 0) {
if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
snd_ctl_free_one(kctl);
}
@ -624,7 +636,8 @@ static int get_min_max(usb_mixer_elem_info_t *cval, int default_min)
}
if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id);
snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
cval->id, cval->mixer->ctrlif, cval->control, cval->id);
return -EINVAL;
}
if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
@ -684,7 +697,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
if (cval->cmask & (1 << c)) {
err = get_cur_mix_value(cval, c + 1, &val);
if (err < 0) {
if (cval->chip->ignore_ctl_error) {
if (cval->mixer->ignore_ctl_error) {
ucontrol->value.integer.value[0] = cval->min;
return 0;
}
@ -700,7 +713,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
/* master channel */
err = get_cur_mix_value(cval, 0, &val);
if (err < 0) {
if (cval->chip->ignore_ctl_error) {
if (cval->mixer->ignore_ctl_error) {
ucontrol->value.integer.value[0] = cval->min;
return 0;
}
@ -726,7 +739,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
if (cval->cmask & (1 << c)) {
err = get_cur_mix_value(cval, c + 1, &oval);
if (err < 0) {
if (cval->chip->ignore_ctl_error)
if (cval->mixer->ignore_ctl_error)
return 0;
return err;
}
@ -743,7 +756,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
} else {
/* master channel */
err = get_cur_mix_value(cval, 0, &oval);
if (err < 0 && cval->chip->ignore_ctl_error)
if (err < 0 && cval->mixer->ignore_ctl_error)
return 0;
if (err < 0)
return err;
@ -795,8 +808,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
snd_printk(KERN_ERR "cannot malloc kcontrol\n");
return;
}
cval->chip = state->chip;
cval->ctrlif = state->ctrlif;
cval->mixer = state->mixer;
cval->id = unitid;
cval->control = control;
cval->cmask = ctl_mask;
@ -880,7 +892,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
add_control_to_empty(state->chip->card, kctl);
add_control_to_empty(state, kctl);
}
@ -963,8 +975,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
if (! cval)
return;
cval->chip = state->chip;
cval->ctrlif = state->ctrlif;
cval->mixer = state->mixer;
cval->id = unitid;
cval->control = in_ch + 1; /* based on 1 */
cval->val_type = USB_MIXER_S16;
@ -995,7 +1006,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
add_control_to_empty(state->chip->card, kctl);
add_control_to_empty(state, kctl);
}
@ -1058,7 +1069,7 @@ static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
int err, val;
err = get_cur_ctl_value(cval, cval->control << 8, &val);
if (err < 0 && cval->chip->ignore_ctl_error) {
if (err < 0 && cval->mixer->ignore_ctl_error) {
ucontrol->value.integer.value[0] = cval->min;
return 0;
}
@ -1077,7 +1088,7 @@ static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
if (err < 0) {
if (cval->chip->ignore_ctl_error)
if (cval->mixer->ignore_ctl_error)
return 0;
return err;
}
@ -1215,8 +1226,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char
snd_printk(KERN_ERR "cannot malloc kcontrol\n");
return -ENOMEM;
}
cval->chip = state->chip;
cval->ctrlif = state->ctrlif;
cval->mixer = state->mixer;
cval->id = unitid;
cval->control = valinfo->control;
cval->val_type = valinfo->val_type;
@ -1257,7 +1267,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char
snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
if ((err = add_control_to_empty(state, kctl)) < 0)
return err;
}
return 0;
@ -1305,7 +1315,7 @@ static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
err = get_cur_ctl_value(cval, 0, &val);
if (err < 0) {
if (cval->chip->ignore_ctl_error) {
if (cval->mixer->ignore_ctl_error) {
ucontrol->value.enumerated.item[0] = 0;
return 0;
}
@ -1324,7 +1334,7 @@ static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
err = get_cur_ctl_value(cval, 0, &oval);
if (err < 0) {
if (cval->chip->ignore_ctl_error)
if (cval->mixer->ignore_ctl_error)
return 0;
return err;
}
@ -1402,8 +1412,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned
snd_printk(KERN_ERR "cannot malloc kcontrol\n");
return -ENOMEM;
}
cval->chip = state->chip;
cval->ctrlif = state->ctrlif;
cval->mixer = state->mixer;
cval->id = unitid;
cval->val_type = USB_MIXER_U8;
cval->channels = 1;
@ -1468,7 +1477,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned
snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
cval->id, kctl->id.name, num_ins);
if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
if ((err = add_control_to_empty(state, kctl)) < 0)
return err;
return 0;
@ -1511,27 +1520,38 @@ static int parse_audio_unit(mixer_build_t *state, int unitid)
}
}
static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
{
kfree(mixer);
}
static int snd_usb_mixer_dev_free(snd_device_t *device)
{
struct usb_mixer_interface *mixer = device->device_data;
snd_usb_mixer_free(mixer);
return 0;
}
/*
* create mixer controls
*
* walk through all OUTPUT_TERMINAL descriptors to search for mixers
*/
int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
{
unsigned char *desc;
mixer_build_t state;
int err;
const struct usbmix_ctl_map *map;
struct usb_device_descriptor *dev = &chip->dev->descriptor;
struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
strcpy(chip->card->mixername, "USB Mixer");
struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor;
struct usb_host_interface *hostif;
hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
memset(&state, 0, sizeof(state));
state.chip = chip;
state.chip = mixer->chip;
state.mixer = mixer;
state.buffer = hostif->extra;
state.buflen = hostif->extralen;
state.ctrlif = ctrlif;
state.vendor = le16_to_cpu(dev->idVendor);
state.product = le16_to_cpu(dev->idProduct);
@ -1540,13 +1560,10 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
if (map->vendor == state.vendor && map->product == state.product) {
state.map = map->map;
state.selector_map = map->selector_map;
chip->ignore_ctl_error = map->ignore_ctl_error;
mixer->ignore_ctl_error = map->ignore_ctl_error;
break;
}
}
#ifdef IGNORE_CTL_ERROR
chip->ignore_ctl_error = 1;
#endif
desc = NULL;
while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) {
@ -1562,3 +1579,40 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
}
return 0;
}
int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
{
static snd_device_ops_t dev_ops = {
.dev_free = snd_usb_mixer_dev_free
};
struct usb_mixer_interface *mixer;
int err;
strcpy(chip->card->mixername, "USB Mixer");
mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL);
if (!mixer)
return -ENOMEM;
mixer->chip = chip;
mixer->ctrlif = ctrlif;
#ifdef IGNORE_CTL_ERROR
mixer->ignore_ctl_error = 1;
#endif
if ((err = snd_usb_mixer_controls(mixer)) < 0) {
snd_usb_mixer_free(mixer);
return err;
}
err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
if (err < 0) {
snd_usb_mixer_free(mixer);
return err;
}
list_add(&mixer->list, &chip->mixer_list);
return 0;
}
void snd_usb_mixer_disconnect(struct list_head *p)
{
}