aboutsummaryrefslogtreecommitdiff
path: root/sound/usb/usbmixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/usbmixer.c')
-rw-r--r--sound/usb/usbmixer.c142
1 files changed, 98 insertions, 44 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index e601f4ba5f2..7bbccebd76c 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -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)
+{
+}