From cc429c9b60f8402c9350ea6d0063db793edc09f2 Mon Sep 17 00:00:00 2001 From: hselasky Date: Mon, 13 Apr 2020 16:34:21 +0000 Subject: [PATCH] MFC r359446: Add support for multiple playback and recording devices per physical USB audio device. This requires some structural refactoring inside the driver, mostly about converting existing audio channel structures into arrays. The main audio mixer is provided by the first PCM instance. The non-first audio instances may only have a software mixer for PCM playback. Tested by: Horse Ma Sponsored by: Mellanox Technologies git-svn-id: svn://svn.freebsd.org/base/stable/10@359890 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/sound/usb/uaudio.c | 376 +++++++++++++++++++++------------ sys/dev/sound/usb/uaudio.h | 14 +- sys/dev/sound/usb/uaudio_pcm.c | 6 +- 3 files changed, 251 insertions(+), 145 deletions(-) diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index a4bae3653..fb2c98132 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -264,6 +264,8 @@ struct uaudio_chan { #define CHAN_OP_START 1 #define CHAN_OP_STOP 2 #define CHAN_OP_DRAIN 3 + + uint8_t iface_index; }; #define UMIDI_EMB_JACK_MAX 16 /* units */ @@ -349,37 +351,45 @@ struct uaudio_hid { #define UAUDIO_SPDIF_OUT_96K 0x04 /* Out sample rate = 96K */ #define UAUDIO_SPDIF_IN_MIX 0x10 /* Input mix enable */ +#define UAUDIO_MAX_CHILD 2 + +struct uaudio_softc_child { + device_t pcm_device; + struct mtx *mixer_lock; + struct snd_mixer *mixer_dev; + + uint32_t mix_info; + uint32_t recsrc_info; + + uint8_t pcm_registered:1; + uint8_t mixer_init:1; +}; + struct uaudio_softc { struct sbuf sc_sndstat; struct sndcard_func sc_sndcard_func; - struct uaudio_chan sc_rec_chan; - struct uaudio_chan sc_play_chan; + struct uaudio_chan sc_rec_chan[UAUDIO_MAX_CHILD]; + struct uaudio_chan sc_play_chan[UAUDIO_MAX_CHILD]; struct umidi_chan sc_midi_chan; struct uaudio_hid sc_hid; struct uaudio_search_result sc_mixer_clocks; struct uaudio_mixer_node sc_mixer_node; struct uaudio_configure_msg sc_config_msg[2]; + struct uaudio_softc_child sc_child[UAUDIO_MAX_CHILD]; - struct mtx *sc_mixer_lock; - struct snd_mixer *sc_mixer_dev; struct usb_device *sc_udev; struct usb_xfer *sc_mixer_xfer[1]; struct uaudio_mixer_node *sc_mixer_root; struct uaudio_mixer_node *sc_mixer_curr; int (*sc_set_spdif_fn) (struct uaudio_softc *, int); - uint32_t sc_mix_info; - uint32_t sc_recsrc_info; - uint16_t sc_audio_rev; uint16_t sc_mixer_count; - uint8_t sc_sndstat_valid; uint8_t sc_mixer_iface_index; uint8_t sc_mixer_iface_no; uint8_t sc_mixer_chan; - uint8_t sc_pcm_registered:1; - uint8_t sc_mixer_init:1; + uint8_t sc_sndstat_valid:1; uint8_t sc_uq_audio_swap_lr:1; uint8_t sc_uq_au_inp_async:1; uint8_t sc_uq_au_no_xu:1; @@ -479,7 +489,7 @@ static usb_proc_callback_t uaudio_configure_msg; static int uaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS); static void uaudio_mixer_ctl_free(struct uaudio_softc *); -static void uaudio_mixer_register_sysctl(struct uaudio_softc *, device_t); +static void uaudio_mixer_register_sysctl(struct uaudio_softc *, device_t, unsigned); static void uaudio_mixer_reload_all(struct uaudio_softc *); static void uaudio_mixer_controls_create_ftu(struct uaudio_softc *); @@ -539,7 +549,7 @@ static void uaudio_mixer_add_ctl(struct uaudio_softc *, static void uaudio_mixer_fill_info(struct uaudio_softc *, struct usb_device *, void *); static int uaudio_mixer_signext(uint8_t, int); -static void uaudio_mixer_init(struct uaudio_softc *); +static void uaudio_mixer_init(struct uaudio_softc *, unsigned); static uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t); static struct umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *); static void umidi_start_read(struct usb_fifo *); @@ -829,6 +839,33 @@ static const STRUCT_USB_HOST_ID __used uaudio_devs[] = { USB_IFACE_SUBCLASS(UISUBCLASS_MIDISTREAM),}, }; +static unsigned +uaudio_get_child_index_by_dev(struct uaudio_softc *sc, device_t dev) +{ + unsigned i; + + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { + if (dev == sc->sc_child[i].pcm_device) + return (i); + } + panic("uaudio_get_child_index_dev: Invalid device: %p\n", dev); + return (0); +} + +static unsigned +uaudio_get_child_index_by_chan(struct uaudio_softc *sc, struct uaudio_chan *ch) +{ + unsigned i; + + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { + if ((sc->sc_play_chan + i) == ch || + (sc->sc_rec_chan + i) == ch) + return (i); + } + panic("uaudio_get_child_index_by_chan: Invalid chan: %p\n", ch); + return (0); +} + static int uaudio_probe(device_t dev) { @@ -917,10 +954,8 @@ uaudio_attach(device_t dev) struct uaudio_softc *sc = device_get_softc(dev); struct usb_interface_descriptor *id; usb_error_t err; - device_t child; + unsigned i; - sc->sc_play_chan.priv_sc = sc; - sc->sc_rec_chan.priv_sc = sc; sc->sc_udev = uaa->device; sc->sc_mixer_iface_index = uaa->info.bIfaceIndex; sc->sc_mixer_iface_no = uaa->info.bIfaceNum; @@ -978,57 +1013,63 @@ uaudio_attach(device_t dev) DPRINTF("%d mixer controls\n", sc->sc_mixer_count); - if (sc->sc_play_chan.num_alt > 0) { + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { uint8_t x; + if (sc->sc_play_chan[i].num_alt <= 0) + break; + /* * Need to set a default alternate interface, else * some USB audio devices might go into an infinte * re-enumeration loop: */ err = usbd_set_alt_interface_index(sc->sc_udev, - sc->sc_play_chan.usb_alt[0].iface_index, - sc->sc_play_chan.usb_alt[0].iface_alt_index); + sc->sc_play_chan[i].usb_alt[0].iface_index, + sc->sc_play_chan[i].usb_alt[0].iface_alt_index); if (err) { DPRINTF("setting of alternate index failed: %s!\n", usbd_errstr(err)); } - for (x = 0; x != sc->sc_play_chan.num_alt; x++) { - device_printf(dev, "Play: %d Hz, %d ch, %s format, " - "2x8ms buffer.\n", - sc->sc_play_chan.usb_alt[x].sample_rate, - sc->sc_play_chan.usb_alt[x].channels, - sc->sc_play_chan.usb_alt[x].p_fmt->description); + for (x = 0; x != sc->sc_play_chan[i].num_alt; x++) { + device_printf(dev, "Play[%u]: %d Hz, %d ch, %s format, " + "2x8ms buffer.\n", i, + sc->sc_play_chan[i].usb_alt[x].sample_rate, + sc->sc_play_chan[i].usb_alt[x].channels, + sc->sc_play_chan[i].usb_alt[x].p_fmt->description); } - } else { - device_printf(dev, "No playback.\n"); } + if (i == 0) + device_printf(dev, "No playback.\n"); - if (sc->sc_rec_chan.num_alt > 0) { + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { uint8_t x; + if (sc->sc_rec_chan[i].num_alt <= 0) + break; + /* * Need to set a default alternate interface, else * some USB audio devices might go into an infinte * re-enumeration loop: */ err = usbd_set_alt_interface_index(sc->sc_udev, - sc->sc_rec_chan.usb_alt[0].iface_index, - sc->sc_rec_chan.usb_alt[0].iface_alt_index); + sc->sc_rec_chan[i].usb_alt[0].iface_index, + sc->sc_rec_chan[i].usb_alt[0].iface_alt_index); if (err) { DPRINTF("setting of alternate index failed: %s!\n", usbd_errstr(err)); } - for (x = 0; x != sc->sc_rec_chan.num_alt; x++) { - device_printf(dev, "Record: %d Hz, %d ch, %s format, " - "2x8ms buffer.\n", - sc->sc_rec_chan.usb_alt[x].sample_rate, - sc->sc_rec_chan.usb_alt[x].channels, - sc->sc_rec_chan.usb_alt[x].p_fmt->description); + for (x = 0; x != sc->sc_rec_chan[i].num_alt; x++) { + device_printf(dev, "Record[%u]: %d Hz, %d ch, %s format, " + "2x8ms buffer.\n", i, + sc->sc_rec_chan[i].usb_alt[x].sample_rate, + sc->sc_rec_chan[i].usb_alt[x].channels, + sc->sc_rec_chan[i].usb_alt[x].p_fmt->description); } - } else { - device_printf(dev, "No recording.\n"); } + if (i == 0) + device_printf(dev, "No recording.\n"); if (sc->sc_midi_chan.valid == 0) { if (usbd_lookup_id_by_uaa(uaudio_vendor_midi, @@ -1060,16 +1101,20 @@ uaudio_attach(device_t dev) * Only attach a PCM device if we have a playback, recording * or mixer device present: */ - if (sc->sc_play_chan.num_alt > 0 || - sc->sc_rec_chan.num_alt > 0 || - sc->sc_mix_info) { - child = device_add_child(dev, "pcm", -1); + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { + if (sc->sc_play_chan[i].num_alt <= 0 && + sc->sc_rec_chan[i].num_alt <= 0 && + sc->sc_child[i].mix_info == 0) + continue; + sc->sc_child[i].pcm_device = + device_add_child(dev, "pcm", -1); - if (child == NULL) { + if (sc->sc_child[i].pcm_device == NULL) { DPRINTF("out of memory\n"); goto detach; } - device_set_ivars(child, &sc->sc_sndcard_func); + device_set_ivars(sc->sc_child[i].pcm_device, + &sc->sc_sndcard_func); } if (bus_generic_attach(dev)) { @@ -1108,16 +1153,17 @@ int uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class) { struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); + unsigned i = uaudio_get_child_index_by_dev(sc, dev); char status[SND_STATUSLEN]; - uaudio_mixer_init(sc); + uaudio_mixer_init(sc, i); if (sc->sc_uq_audio_swap_lr) { DPRINTF("hardware has swapped left and right\n"); /* uaudio_pcm_setflags(dev, SD_F_PSWAPLR); */ } - if (sc->sc_play_chan.num_alt > 0 && - (sc->sc_mix_info & SOUND_MASK_PCM) == 0) { + if (sc->sc_play_chan[i].num_alt > 0 && + (sc->sc_child[i].mix_info & SOUND_MASK_PCM) == 0) { DPRINTF("emulating master volume\n"); @@ -1133,34 +1179,39 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas } if (mixer_init(dev, mixer_class, sc)) goto detach; - sc->sc_mixer_init = 1; + sc->sc_child[i].mixer_init = 1; mixer_hwvol_init(dev); snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio)); if (pcm_register(dev, sc, - (sc->sc_play_chan.num_alt > 0) ? 1 : 0, - (sc->sc_rec_chan.num_alt > 0) ? 1 : 0)) { + (sc->sc_play_chan[i].num_alt > 0) ? 1 : 0, + (sc->sc_rec_chan[i].num_alt > 0) ? 1 : 0)) { goto detach; } uaudio_pcm_setflags(dev, SD_F_MPSAFE); - sc->sc_pcm_registered = 1; + sc->sc_child[i].pcm_registered = 1; - if (sc->sc_play_chan.num_alt > 0) { - pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc); + if (sc->sc_play_chan[i].num_alt > 0) { + sc->sc_play_chan[i].priv_sc = sc; + pcm_addchan(dev, PCMDIR_PLAY, chan_class, + &sc->sc_play_chan[i]); } - if (sc->sc_rec_chan.num_alt > 0) { - pcm_addchan(dev, PCMDIR_REC, chan_class, sc); + + if (sc->sc_rec_chan[i].num_alt > 0) { + sc->sc_rec_chan[i].priv_sc = sc; + pcm_addchan(dev, PCMDIR_REC, chan_class, + &sc->sc_rec_chan[i]); } pcm_setstatus(dev, status); - uaudio_mixer_register_sysctl(sc, dev); + uaudio_mixer_register_sysctl(sc, dev, i); SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, - "feedback_rate", CTLFLAG_RD, &sc->sc_play_chan.feedback_rate, + "feedback_rate", CTLFLAG_RD, &sc->sc_play_chan[i].feedback_rate, 0, "Feedback sample rate in Hz"); return (0); /* success */ @@ -1174,18 +1225,15 @@ int uaudio_detach_sub(device_t dev) { struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); + unsigned i = uaudio_get_child_index_by_dev(sc, dev); int error = 0; - /* disable S/PDIF output, if any */ - (void) sc->sc_set_spdif_fn(sc, 0); - repeat: - if (sc->sc_pcm_registered) { + if (sc->sc_child[i].pcm_registered) { error = pcm_unregister(dev); } else { - if (sc->sc_mixer_init) { + if (sc->sc_child[i].mixer_init) error = mixer_uninit(dev); - } } if (error) { @@ -1200,6 +1248,7 @@ static int uaudio_detach(device_t dev) { struct uaudio_softc *sc = device_get_softc(dev); + unsigned i; /* * Stop USB transfers early so that any audio applications @@ -1207,14 +1256,18 @@ uaudio_detach(device_t dev) * any. */ usb_proc_explore_lock(sc->sc_udev); - sc->sc_play_chan.operation = CHAN_OP_DRAIN; - sc->sc_rec_chan.operation = CHAN_OP_DRAIN; + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { + sc->sc_play_chan[i].operation = CHAN_OP_DRAIN; + sc->sc_rec_chan[i].operation = CHAN_OP_DRAIN; + } usb_proc_explore_mwait(sc->sc_udev, &sc->sc_config_msg[0], &sc->sc_config_msg[1]); usb_proc_explore_unlock(sc->sc_udev); - usbd_transfer_unsetup(sc->sc_play_chan.xfer, UAUDIO_NCHANBUFS + 1); - usbd_transfer_unsetup(sc->sc_rec_chan.xfer, UAUDIO_NCHANBUFS + 1); + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { + usbd_transfer_unsetup(sc->sc_play_chan[i].xfer, UAUDIO_NCHANBUFS + 1); + usbd_transfer_unsetup(sc->sc_rec_chan[i].xfer, UAUDIO_NCHANBUFS + 1); + } uaudio_hid_detach(sc); @@ -1230,6 +1283,9 @@ uaudio_detach(device_t dev) uaudio_mixer_ctl_free(sc); + /* disable S/PDIF output, if any */ + (void) sc->sc_set_spdif_fn(sc, 0); + return (0); } @@ -1420,10 +1476,13 @@ static void uaudio_configure_msg(struct usb_proc_msg *pm) { struct uaudio_softc *sc = ((struct uaudio_configure_msg *)pm)->sc; + unsigned i; usb_proc_explore_unlock(sc->sc_udev); - uaudio_configure_msg_sub(sc, &sc->sc_play_chan, PCMDIR_PLAY); - uaudio_configure_msg_sub(sc, &sc->sc_rec_chan, PCMDIR_REC); + for (i = 0; i != UAUDIO_MAX_CHILD; i++) { + uaudio_configure_msg_sub(sc, &sc->sc_play_chan[i], PCMDIR_PLAY); + uaudio_configure_msg_sub(sc, &sc->sc_rec_chan[i], PCMDIR_REC); + } usb_proc_explore_lock(sc->sc_udev); } @@ -1589,6 +1648,22 @@ uaudio20_check_rate(struct usb_device *udev, uint8_t iface_no, return (USB_ERR_INVAL); } +static struct uaudio_chan * +uaudio_get_chan(struct uaudio_softc *sc, struct uaudio_chan *chan, + uint8_t iface_index) +{ + unsigned i; + + for (i = 0; i != UAUDIO_MAX_CHILD; i++, chan++) { + if (chan->num_alt == 0) { + chan->iface_index = iface_index; + return (chan); + } else if (chan->iface_index == iface_index) + return (chan); + } + return (NULL); +} + static void uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, uint32_t rate, uint8_t channels, uint8_t bit_resolution) @@ -1896,8 +1971,12 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, } } - chan = (ep_dir == UE_DIR_IN) ? - &sc->sc_rec_chan : &sc->sc_play_chan; + chan = uaudio_get_chan(sc, (ep_dir == UE_DIR_OUT) ? &sc->sc_play_chan[0] : + &sc->sc_rec_chan[0], curidx); + if (chan == NULL) { + DPRINTF("More than %d sub devices. (skipped)\n", UAUDIO_MAX_CHILD); + goto next_ep; + } if (usbd_get_iface(udev, curidx) == NULL) { DPRINTF("Interface is not valid\n"); @@ -1916,8 +1995,8 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, uaudio_chan_dump_ep_desc(ed1); #endif DPRINTF("Sample rate = %dHz, channels = %d, " - "bits = %d, format = %s\n", rate, channels, - bit_resolution, p_fmt->description); + "bits = %d, format = %s, ep 0x%02x, chan %p\n", rate, channels, + bit_resolution, p_fmt->description, ed1->bEndpointAddress, chan); chan_alt->sample_rate = rate; chan_alt->p_asf1d = asf1d; @@ -2101,12 +2180,15 @@ uaudio_chan_play_sync_callback(struct usb_xfer *xfer, usb_error_t error) uint64_t sample_rate; uint8_t buf[4]; uint64_t temp; + unsigned i; int len; int actlen; int nframes; usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); + i = uaudio_get_child_index_by_chan(ch->priv_sc, ch); + switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: @@ -2157,7 +2239,7 @@ uaudio_chan_play_sync_callback(struct usb_xfer *xfer, usb_error_t error) * Use feedback value as fallback when there is no * recording channel: */ - if (ch->priv_sc->sc_rec_chan.num_alt == 0) { + if (ch->priv_sc->sc_rec_chan[i].num_alt == 0) { int32_t jitter_max = howmany(sample_rate, 16000); /* @@ -2183,7 +2265,7 @@ uaudio_chan_play_sync_callback(struct usb_xfer *xfer, usb_error_t error) * source of jitter information to save some * isochronous bandwidth: */ - if (ch->priv_sc->sc_rec_chan.num_alt != 0 && + if (ch->priv_sc->sc_rec_chan[i].num_alt != 0 && uaudio_debug == 0) break; usbd_xfer_set_frames(xfer, 1); @@ -2214,6 +2296,7 @@ uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) uint32_t blockcount; uint32_t n; uint32_t offset; + unsigned i; int sample_size; int actlen; int sumlen; @@ -2223,10 +2306,12 @@ uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) return; } - /* check if there is a record channel */ - if (ch->priv_sc->sc_rec_chan.num_alt > 0) - ch_rec = &ch->priv_sc->sc_rec_chan; - else + i = uaudio_get_child_index_by_chan(ch->priv_sc, ch); + + /* check if there is a valid record channel */ + ch_rec = ch->priv_sc->sc_rec_chan + i; + + if (ch_rec->num_alt == 0) ch_rec = NULL; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); @@ -2490,11 +2575,9 @@ tr_setup: } void * -uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, +uaudio_chan_init(struct uaudio_chan *ch, struct snd_dbuf *b, struct pcm_channel *c, int dir) { - struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? - &sc->sc_play_chan : &sc->sc_rec_chan); uint32_t buf_size; uint8_t x; @@ -2685,36 +2768,36 @@ uaudio_chan_start_sub(struct uaudio_chan *ch) } static int -uaudio_chan_need_both(struct uaudio_softc *sc) +uaudio_chan_need_both(struct uaudio_chan *pchan, struct uaudio_chan *rchan) { - return (sc->sc_play_chan.num_alt > 0 && - sc->sc_play_chan.running != 0 && - uaudio_chan_is_async(&sc->sc_play_chan, - sc->sc_play_chan.set_alt) != 0 && - sc->sc_rec_chan.num_alt > 0 && - sc->sc_rec_chan.running == 0); + return (pchan->num_alt > 0 && + pchan->running != 0 && + uaudio_chan_is_async(pchan, pchan->set_alt) != 0 && + rchan->num_alt > 0 && + rchan->running == 0); } static int -uaudio_chan_need_none(struct uaudio_softc *sc) +uaudio_chan_need_none(struct uaudio_chan *pchan, struct uaudio_chan *rchan) { - return (sc->sc_play_chan.num_alt > 0 && - sc->sc_play_chan.running == 0 && - sc->sc_rec_chan.num_alt > 0 && - sc->sc_rec_chan.running == 0); + return (pchan->num_alt > 0 && + pchan->running == 0 && + rchan->num_alt > 0 && + rchan->running == 0); } void uaudio_chan_start(struct uaudio_chan *ch) { struct uaudio_softc *sc = ch->priv_sc; + unsigned i = uaudio_get_child_index_by_chan(sc, ch); /* make operation atomic */ usb_proc_explore_lock(sc->sc_udev); /* check if not running */ if (ch->running == 0) { - uint32_t temp; + uint32_t temp; /* get current buffer size */ temp = 2 * uaudio_get_buffer_size(ch, ch->set_alt); @@ -2727,13 +2810,15 @@ uaudio_chan_start(struct uaudio_chan *ch) ch->end = ch->buf + temp; ch->cur = ch->buf; - if (uaudio_chan_need_both(sc)) { + if (uaudio_chan_need_both( + &sc->sc_play_chan[i], + &sc->sc_rec_chan[i])) { /* * Start both endpoints because of need for * jitter information: */ - uaudio_chan_start_sub(&sc->sc_rec_chan); - uaudio_chan_start_sub(&sc->sc_play_chan); + uaudio_chan_start_sub(&sc->sc_rec_chan[i]); + uaudio_chan_start_sub(&sc->sc_play_chan[i]); } else { uaudio_chan_start_sub(ch); } @@ -2771,6 +2856,7 @@ void uaudio_chan_stop(struct uaudio_chan *ch) { struct uaudio_softc *sc = ch->priv_sc; + unsigned i = uaudio_get_child_index_by_chan(sc, ch); /* make operation atomic */ usb_proc_explore_lock(sc->sc_udev); @@ -2780,18 +2866,22 @@ uaudio_chan_stop(struct uaudio_chan *ch) /* clear running flag */ ch->running = 0; - if (uaudio_chan_need_both(sc)) { + if (uaudio_chan_need_both( + &sc->sc_play_chan[i], + &sc->sc_rec_chan[i])) { /* * Leave the endpoints running because we need * information about jitter! */ - } else if (uaudio_chan_need_none(sc)) { + } else if (uaudio_chan_need_none( + &sc->sc_play_chan[i], + &sc->sc_rec_chan[i])) { /* * Stop both endpoints in case the one was used for * jitter information: */ - uaudio_chan_stop_sub(&sc->sc_rec_chan); - uaudio_chan_stop_sub(&sc->sc_play_chan); + uaudio_chan_stop_sub(&sc->sc_rec_chan[i]); + uaudio_chan_stop_sub(&sc->sc_play_chan[i]); } else { uaudio_chan_stop_sub(ch); } @@ -2818,12 +2908,12 @@ uaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS) sc = (struct uaudio_softc *)oidp->oid_arg1; hint = oidp->oid_arg2; - if (sc->sc_mixer_lock == NULL) + if (sc->sc_child[0].mixer_lock == NULL) return (ENXIO); /* lookup mixer node */ - mtx_lock(sc->sc_mixer_lock); + mtx_lock(sc->sc_child[0].mixer_lock); for (pmc = sc->sc_mixer_root; pmc != NULL; pmc = pmc->next) { for (chan = 0; chan != (int)pmc->nchan; chan++) { if (pmc->wValue[chan] != -1 && @@ -2834,7 +2924,7 @@ uaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS) } } found: - mtx_unlock(sc->sc_mixer_lock); + mtx_unlock(sc->sc_child[0].mixer_lock); error = sysctl_handle_int(oidp, &temp, 0, req); if (error != 0 || req->newptr == NULL) @@ -2842,7 +2932,7 @@ found: /* update mixer value */ - mtx_lock(sc->sc_mixer_lock); + mtx_lock(sc->sc_child[0].mixer_lock); if (pmc != NULL && temp >= pmc->minval && temp <= pmc->maxval) { @@ -2853,7 +2943,7 @@ found: /* start the transfer, if not already started */ usbd_transfer_start(sc->sc_mixer_xfer[0]); } - mtx_unlock(sc->sc_mixer_lock); + mtx_unlock(sc->sc_child[0].mixer_lock); return (0); } @@ -2870,7 +2960,8 @@ uaudio_mixer_ctl_free(struct uaudio_softc *sc) } static void -uaudio_mixer_register_sysctl(struct uaudio_softc *sc, device_t dev) +uaudio_mixer_register_sysctl(struct uaudio_softc *sc, device_t dev, + unsigned index) { struct uaudio_mixer_node *pmc; struct sysctl_oid *mixer_tree; @@ -2879,6 +2970,9 @@ uaudio_mixer_register_sysctl(struct uaudio_softc *sc, device_t dev) int chan; int n; + if (index != 0) + return; + mixer_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "mixer", CTLFLAG_RD, NULL, ""); @@ -3082,10 +3176,10 @@ uaudio_mixer_reload_all(struct uaudio_softc *sc) struct uaudio_mixer_node *pmc; int chan; - if (sc->sc_mixer_lock == NULL) + if (sc->sc_child[0].mixer_lock == NULL) return; - mtx_lock(sc->sc_mixer_lock); + mtx_lock(sc->sc_child[0].mixer_lock); for (pmc = sc->sc_mixer_root; pmc != NULL; pmc = pmc->next) { /* use reset defaults for non-oss controlled settings */ if (pmc->ctl == SOUND_MIXER_NRDEVICES) @@ -3097,7 +3191,7 @@ uaudio_mixer_reload_all(struct uaudio_softc *sc) /* start HID volume keys, if any */ usbd_transfer_start(sc->sc_hid.xfer[0]); - mtx_unlock(sc->sc_mixer_lock); + mtx_unlock(sc->sc_child[0].mixer_lock); } static void @@ -5291,11 +5385,13 @@ uaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, } static void -uaudio_mixer_init(struct uaudio_softc *sc) +uaudio_mixer_init(struct uaudio_softc *sc, unsigned index) { struct uaudio_mixer_node *mc; int32_t i; + if (index != 0) + return; for (mc = sc->sc_mixer_root; mc; mc = mc->next) { if (mc->ctl != SOUND_MIXER_NRDEVICES) { @@ -5303,7 +5399,7 @@ uaudio_mixer_init(struct uaudio_softc *sc) * Set device mask bits. See * /usr/include/machine/soundcard.h */ - sc->sc_mix_info |= 1U << mc->ctl; + sc->sc_child[index].mix_info |= 1U << mc->ctl; } if ((mc->ctl == SOUND_MIXER_NRDEVICES) && (mc->type == MIX_SELECTOR)) { @@ -5311,7 +5407,7 @@ uaudio_mixer_init(struct uaudio_softc *sc) for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) continue; - sc->sc_recsrc_info |= 1U << mc->slctrtype[i - 1]; + sc->sc_child[index].recsrc_info |= 1U << mc->slctrtype[i - 1]; } } } @@ -5320,50 +5416,57 @@ uaudio_mixer_init(struct uaudio_softc *sc) int uaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) { - DPRINTF("\n"); + unsigned i = uaudio_get_child_index_by_dev(sc, mix_get_dev(m)); - sc->sc_mixer_lock = mixer_get_lock(m); - sc->sc_mixer_dev = m; + DPRINTF("child=%u\n", i); - if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, + sc->sc_child[i].mixer_lock = mixer_get_lock(m); + sc->sc_child[i].mixer_dev = m; + + if (i == 0 && + usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, - sc->sc_mixer_lock)) { - DPRINTFN(0, "could not allocate USB " - "transfer for audio mixer!\n"); + sc->sc_child[i].mixer_lock)) { + DPRINTFN(0, "could not allocate USB transfer for mixer!\n"); return (ENOMEM); } - if (sc->sc_play_chan.num_alt > 0 && - (sc->sc_mix_info & SOUND_MASK_VOLUME) == 0) { + if (sc->sc_play_chan[i].num_alt > 0 && + (sc->sc_child[i].mix_info & SOUND_MASK_VOLUME) == 0) { mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); } - mix_setdevs(m, sc->sc_mix_info); - mix_setrecdevs(m, sc->sc_recsrc_info); + mix_setdevs(m, sc->sc_child[i].mix_info); + mix_setrecdevs(m, sc->sc_child[i].recsrc_info); return (0); } int -uaudio_mixer_uninit_sub(struct uaudio_softc *sc) +uaudio_mixer_uninit_sub(struct uaudio_softc *sc, struct snd_mixer *m) { - DPRINTF("\n"); + unsigned index = uaudio_get_child_index_by_dev(sc, mix_get_dev(m)); - usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); + DPRINTF("child=%u\n", index); - sc->sc_mixer_lock = NULL; + if (index == 0) + usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); + + sc->sc_child[index].mixer_lock = NULL; return (0); } void -uaudio_mixer_set(struct uaudio_softc *sc, unsigned type, - unsigned left, unsigned right) +uaudio_mixer_set(struct uaudio_softc *sc, struct snd_mixer *m, + unsigned type, unsigned left, unsigned right) { + unsigned index = uaudio_get_child_index_by_dev(sc, mix_get_dev(m)); struct uaudio_mixer_node *mc; int chan; + if (index != 0) + return; for (mc = sc->sc_mixer_root; mc != NULL; mc = mc->next) { - if (mc->ctl == type) { for (chan = 0; chan < mc->nchan; chan++) { uaudio_mixer_ctl_set(sc, mc, chan, @@ -5374,13 +5477,16 @@ uaudio_mixer_set(struct uaudio_softc *sc, unsigned type, } uint32_t -uaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) +uaudio_mixer_setrecsrc(struct uaudio_softc *sc, struct snd_mixer *m, uint32_t src) { + unsigned index = uaudio_get_child_index_by_dev(sc, mix_get_dev(m)); struct uaudio_mixer_node *mc; uint32_t mask; uint32_t temp; int32_t i; + if (index != 0) + return (0); for (mc = sc->sc_mixer_root; mc; mc = mc->next) { if ((mc->ctl == SOUND_MIXER_NRDEVICES) && @@ -6008,7 +6114,7 @@ uaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error) id = 0; } - m = sc->sc_mixer_dev; + m = sc->sc_child[0].mixer_dev; if ((sc->sc_hid.flags & UAUDIO_HID_HAS_MUTE) && (sc->sc_hid.mute_id == id) && @@ -6073,7 +6179,7 @@ uaudio_hid_probe(struct uaudio_softc *sc, if (!(sc->sc_hid.flags & UAUDIO_HID_VALID)) return (-1); - if (sc->sc_mixer_lock == NULL) + if (sc->sc_child[0].mixer_lock == NULL) return (-1); /* Get HID descriptor */ @@ -6134,7 +6240,7 @@ uaudio_hid_probe(struct uaudio_softc *sc, /* allocate USB transfers */ error = usbd_transfer_setup(uaa->device, &sc->sc_hid.iface_index, sc->sc_hid.xfer, uaudio_hid_config, UAUDIO_HID_N_TRANSFER, - sc, sc->sc_mixer_lock); + sc, sc->sc_child[0].mixer_lock); if (error) { DPRINTF("error=%s\n", usbd_errstr(error)); return (-1); diff --git a/sys/dev/sound/usb/uaudio.h b/sys/dev/sound/usb/uaudio.h index 2d9a87568..ddd79c9cb 100644 --- a/sys/dev/sound/usb/uaudio.h +++ b/sys/dev/sound/usb/uaudio.h @@ -39,7 +39,7 @@ struct pcm_channel; extern int uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class); extern int uaudio_detach_sub(device_t dev); -extern void *uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, +extern void *uaudio_chan_init(struct uaudio_chan *ch, struct snd_dbuf *b, struct pcm_channel *c, int dir); extern int uaudio_chan_free(struct uaudio_chan *ch); extern int uaudio_chan_set_param_blocksize(struct uaudio_chan *ch, @@ -56,12 +56,12 @@ extern int uaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format); extern void uaudio_chan_start(struct uaudio_chan *ch); extern void uaudio_chan_stop(struct uaudio_chan *ch); -extern int uaudio_mixer_init_sub(struct uaudio_softc *sc, - struct snd_mixer *m); -extern int uaudio_mixer_uninit_sub(struct uaudio_softc *sc); -extern void uaudio_mixer_set(struct uaudio_softc *sc, unsigned type, - unsigned left, unsigned right); -extern uint32_t uaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src); +extern int uaudio_mixer_init_sub(struct uaudio_softc *, struct snd_mixer *); +extern int uaudio_mixer_uninit_sub(struct uaudio_softc *, struct snd_mixer *); +extern void uaudio_mixer_set(struct uaudio_softc *, struct snd_mixer *, + unsigned type, unsigned left, unsigned right); +extern uint32_t uaudio_mixer_setrecsrc(struct uaudio_softc *, struct snd_mixer *, + uint32_t src); int uaudio_get_vendor(device_t dev); int uaudio_get_product(device_t dev); diff --git a/sys/dev/sound/usb/uaudio_pcm.c b/sys/dev/sound/usb/uaudio_pcm.c index 10e8cc430..35409eced 100644 --- a/sys/dev/sound/usb/uaudio_pcm.c +++ b/sys/dev/sound/usb/uaudio_pcm.c @@ -144,7 +144,7 @@ ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right) do_unlock = 1; mtx_lock(mtx); } - uaudio_mixer_set(mix_getdevinfo(m), type, left, right); + uaudio_mixer_set(mix_getdevinfo(m), m, type, left, right); if (do_unlock) { mtx_unlock(mtx); } @@ -164,7 +164,7 @@ ua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) do_unlock = 1; mtx_lock(mtx); } - retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), src); + retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), m, src); if (do_unlock) { mtx_unlock(mtx); } @@ -174,7 +174,7 @@ ua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) static int ua_mixer_uninit(struct snd_mixer *m) { - return (uaudio_mixer_uninit_sub(mix_getdevinfo(m))); + return (uaudio_mixer_uninit_sub(mix_getdevinfo(m), m)); } static kobj_method_t ua_mixer_methods[] = { -- 2.42.0