forked from Minki/linux
[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:
parent
707e60732f
commit
84957a8ab0
@ -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(®ister_mutex);
|
||||
snd_card_free(card);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user