Index: sys/dev/sound/pcm/channel.h =================================================================== --- sys/dev/sound/pcm/channel.h +++ sys/dev/sound/pcm/channel.h @@ -258,6 +258,7 @@ int chn_reinit(struct pcm_channel *c); int chn_write(struct pcm_channel *c, struct uio *buf); int chn_read(struct pcm_channel *c, struct uio *buf); +u_int32_t chn_prepare(struct pcm_channel *c, int enable); u_int32_t chn_start(struct pcm_channel *c, int force); int chn_sync(struct pcm_channel *c, int threshold); int chn_flush(struct pcm_channel *c); @@ -367,6 +368,7 @@ #define CHN_F_VCHAN_ADAPTIVE 0x00008000 /* adaptive format/rate selection */ #define CHN_F_VCHAN_DYNAMIC (CHN_F_VCHAN_PASSTHROUGH | CHN_F_VCHAN_ADAPTIVE) +#define CHN_F_READY 0x01000000 #define CHN_F_VIRTUAL 0x10000000 /* not backed by hardware */ #define CHN_F_BITPERFECT 0x20000000 /* un-cooked, Heh.. */ #define CHN_F_PASSTHROUGH 0x40000000 /* passthrough re-config */ Index: sys/dev/sound/pcm/channel.c =================================================================== --- sys/dev/sound/pcm/channel.c +++ sys/dev/sound/pcm/channel.c @@ -670,6 +670,15 @@ CHN_UNLOCK(c); } +u_int32_t +chn_prepare(struct pcm_channel *c, int enable) +{ + int ret = 0; + + ret = CHANNEL_PREPARE(c->methods, c->devinfo, enable); + return ret; +} + u_int32_t chn_start(struct pcm_channel *c, int force) { Index: sys/dev/sound/pcm/channel_if.m =================================================================== --- sys/dev/sound/pcm/channel_if.m +++ sys/dev/sound/pcm/channel_if.m @@ -153,6 +153,12 @@ int go; }; +METHOD int prepare { + kobj_t obj; + void *data; + int go; +}; + METHOD u_int32_t getptr { kobj_t obj; void *data; Index: sys/dev/sound/pcm/dsp.c =================================================================== --- sys/dev/sound/pcm/dsp.c +++ sys/dev/sound/pcm/dsp.c @@ -1085,7 +1085,6 @@ ret = 0; xcmd = 0; chn = NULL; - if (IOCGROUP(cmd) == 'M') { if (cmd == OSS_GETVERSION) { *arg_i = SOUND_VERSION; @@ -1734,28 +1733,34 @@ case SNDCTL_DSP_SETTRIGGER: if (rdch) { - CHN_LOCK(rdch); - rdch->flags &= ~CHN_F_NOTRIGGER; - if (*arg_i & PCM_ENABLE_INPUT) + if (*arg_i & PCM_ENABLE_INPUT) { + chn_prepare(rdch, 1); + CHN_LOCK(rdch); chn_start(rdch, 1); - else { + rdch->flags &= ~CHN_F_NOTRIGGER; + CHN_UNLOCK(rdch); + } else { + CHN_LOCK(rdch); chn_abort(rdch); chn_resetbuf(rdch); rdch->flags |= CHN_F_NOTRIGGER; + CHN_UNLOCK(rdch); } - CHN_UNLOCK(rdch); } if (wrch) { - CHN_LOCK(wrch); - wrch->flags &= ~CHN_F_NOTRIGGER; - if (*arg_i & PCM_ENABLE_OUTPUT) + if (*arg_i & PCM_ENABLE_OUTPUT) { + chn_prepare(wrch, 1); + CHN_LOCK(wrch); chn_start(wrch, 1); - else { + wrch->flags &= ~CHN_F_NOTRIGGER; + CHN_UNLOCK(wrch); + } else { + CHN_LOCK(wrch); chn_abort(wrch); chn_resetbuf(wrch); wrch->flags |= CHN_F_NOTRIGGER; + CHN_UNLOCK(wrch); } - CHN_UNLOCK(wrch); } break; @@ -1789,11 +1794,17 @@ case SNDCTL_DSP_POST: if (wrch) { + chn_prepare(wrch, 1); CHN_LOCK(wrch); wrch->flags &= ~CHN_F_NOTRIGGER; chn_start(wrch, 1); CHN_UNLOCK(wrch); } +#if 0 + if (rdch) { + chn_prepare(rdch, 1); + } +#endif break; case SNDCTL_DSP_SETDUPLEX: Index: sys/dev/sound/pcm/vchan.c =================================================================== --- sys/dev/sound/pcm/vchan.c +++ sys/dev/sound/pcm/vchan.c @@ -184,6 +184,21 @@ return (ret); } +static int +vchan_prepare(kobj_t obj, void *data, int go) +{ + struct vchan_info *info; + struct pcm_channel *c, *p; + + info = data; + c = info->channel; + p = c->parentchannel; + + if (p) + chn_prepare(p, go); + return 1; +} + static struct pcmchan_caps * vchan_getcaps(kobj_t obj, void *data) { @@ -244,6 +259,7 @@ KOBJMETHOD(channel_setformat, vchan_setformat), KOBJMETHOD(channel_setspeed, vchan_setspeed), KOBJMETHOD(channel_trigger, vchan_trigger), + KOBJMETHOD(channel_prepare, vchan_prepare), KOBJMETHOD(channel_getcaps, vchan_getcaps), KOBJMETHOD(channel_getmatrix, vchan_getmatrix), KOBJMETHOD_END Index: sys/dev/sound/usb/uaudio.h =================================================================== --- sys/dev/sound/usb/uaudio.h +++ sys/dev/sound/usb/uaudio.h @@ -56,6 +56,7 @@ uint32_t format); extern int uaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format); +extern void uaudio_chan_prepare(struct uaudio_chan *ch, int enable); 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 *, struct snd_mixer *); Index: sys/dev/sound/usb/uaudio.c =================================================================== --- sys/dev/sound/usb/uaudio.c +++ sys/dev/sound/usb/uaudio.c @@ -267,6 +267,7 @@ #define CHAN_OP_DRAIN 3 uint8_t iface_index; + uint8_t cur_alt_index; }; #define UMIDI_EMB_JACK_MAX 16 /* units */ @@ -1342,6 +1343,8 @@ goto error; } + chan->cur_alt_index = (operation == CHAN_OP_START) ? + chan_alt->iface_alt_index : 0; /* * Only set the sample rate if the channel reports that it * supports the frequency control. @@ -2775,6 +2778,22 @@ rchan->running == 0); } +void +uaudio_chan_prepare(struct uaudio_chan *ch, int enable) +{ + struct uaudio_softc *sc = ch->priv_sc; + + if (ch->cur_alt_index == ch->usb_alt[ch->cur_alt].iface_alt_index) { + return; + } + usbd_req_set_alt_interface_no(sc->sc_udev, + NULL, + ch->iface_index, + ch->usb_alt[ch->cur_alt].iface_alt_index); + + ch->cur_alt_index = ch->usb_alt[ch->cur_alt].iface_alt_index; +} + void uaudio_chan_start(struct uaudio_chan *ch) { @@ -2836,8 +2855,20 @@ } } if (do_stop) { - usbd_transfer_stop(ch->xfer[0]); - usbd_transfer_stop(ch->xfer[1]); + usb_proc_explore_unlock(sc->sc_udev); + CHN_UNLOCK(ch->pcm_ch); + + usbd_transfer_drain(ch->xfer[0]); + usbd_transfer_drain(ch->xfer[1]); + + usbd_req_set_alt_interface_no(sc->sc_udev, + NULL, + ch->iface_index, + 0); + ch->cur_alt_index = 0; + CHN_LOCK(ch->pcm_ch); + usb_proc_explore_lock(sc->sc_udev); + } } Index: sys/dev/sound/usb/uaudio_pcm.c =================================================================== --- sys/dev/sound/usb/uaudio_pcm.c +++ sys/dev/sound/usb/uaudio_pcm.c @@ -79,6 +79,13 @@ return (uaudio_chan_set_param_fragments(data, blocksize, blockcount)); } +static int +ua_chan_prepare(kobj_t obj, void *data, int go) +{ + uaudio_chan_prepare(data, go); + return 0; +} + static int ua_chan_trigger(kobj_t obj, void *data, int go) { @@ -118,6 +125,7 @@ KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize), KOBJMETHOD(channel_setfragments, ua_chan_setfragments), KOBJMETHOD(channel_trigger, ua_chan_trigger), + KOBJMETHOD(channel_prepare, ua_chan_prepare), KOBJMETHOD(channel_getptr, ua_chan_getptr), KOBJMETHOD(channel_getcaps, ua_chan_getcaps), KOBJMETHOD(channel_getmatrix, ua_chan_getmatrix),