svn commit: r280594 - stable/9/sys/dev/sound/usb

Hans Petter Selasky hselasky at FreeBSD.org
Wed Mar 25 13:16:41 UTC 2015


Author: hselasky
Date: Wed Mar 25 13:16:39 2015
New Revision: 280594
URL: https://svnweb.freebsd.org/changeset/base/280594

Log:
  MFC r280322 and r280429:
  The synchronisation value returned by the so-called feedback endpoint
  appears to be too inaccurate that it can be used to synchronize the
  playback data stream. If there is a recording endpoint associated with
  the playback endpoint, use that instead. That means if the isochronous
  OUT endpoint is asynchronus the USB audio driver will automatically
  start recording, if possible, to get exact information about the
  needed sample rate adjustments. In no recording endpoint is present,
  no rate adaption will be done.
  
  While at it fix an issue where the hardware buffer pointers don't get
  reset at the first device PCM trigger.
  
  Make some variables 32-bit to avoid problems with multithreading.
  
  Use the feedback value from the synchronization endpoint as fallback
  when there is no recording channel.
  
  PR: 		198444

Modified:
  stable/9/sys/dev/sound/usb/uaudio.c
  stable/9/sys/dev/sound/usb/uaudio.h
  stable/9/sys/dev/sound/usb/uaudio_pcm.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/sound/usb/uaudio.c
==============================================================================
--- stable/9/sys/dev/sound/usb/uaudio.c	Wed Mar 25 13:15:47 2015	(r280593)
+++ stable/9/sys/dev/sound/usb/uaudio.c	Wed Mar 25 13:16:39 2015	(r280594)
@@ -218,26 +218,25 @@ struct uaudio_chan {
 	uint32_t sample_rem;
 	uint32_t sample_curr;
 	uint32_t max_buf;
+	int32_t jitter_rem;
+	int32_t jitter_curr;
+
+	int feedback_rate;
 
 	uint32_t pcm_format[2];
 
 	uint16_t bytes_per_frame[2];
 
-	uint8_t	num_alt;
-	uint8_t cur_alt;
-	uint8_t set_alt;
-	uint8_t operation;
+	uint32_t intr_counter;
+	uint32_t running;
+	uint32_t num_alt;
+	uint32_t cur_alt;
+	uint32_t set_alt;
+	uint32_t operation;
 #define	CHAN_OP_NONE 0
 #define	CHAN_OP_START 1
 #define	CHAN_OP_STOP 2
 #define	CHAN_OP_DRAIN 3
-
-	/* USB audio feedback endpoint state */
-	struct {
-		uint16_t time;		/* I/O interrupt count */
-		int16_t constant;	/* sample rate adjustment in Hz */
-		int16_t remainder;	/* current remainder */
-	} feedback;
 };
 
 #define	UMIDI_EMB_JACK_MAX   16		/* units */
@@ -1096,6 +1095,11 @@ uaudio_attach_sub(device_t dev, kobj_cla
 
 	uaudio_mixer_register_sysctl(sc, dev);
 
+	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,
+	    0, "Feedback sample rate in Hz");
+
 	return (0);			/* success */
 
 detach:
@@ -1294,7 +1298,6 @@ uaudio_configure_msg_sub(struct uaudio_s
 	chan->frames_per_second = fps;
 	chan->sample_rem = chan_alt->sample_rate % fps;
 	chan->sample_curr = 0;
-	chan->frames_per_second = fps;
 
 	/* compute required buffer size */
 	buf_size = (chan->bytes_per_frame[1] * frames);
@@ -1974,7 +1977,7 @@ uaudio_chan_play_sync_callback(struct us
 {
 	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
 	struct usb_page_cache *pc;
-	uint64_t sample_rate = ch->usb_alt[ch->cur_alt].sample_rate;
+	uint64_t sample_rate;
 	uint8_t buf[4];
 	uint64_t temp;
 	int len;
@@ -2017,6 +2020,8 @@ uaudio_chan_play_sync_callback(struct us
 
 		temp *= 125ULL;
 
+		sample_rate = ch->usb_alt[ch->cur_alt].sample_rate;
+
 		/* auto adjust */
 		while (temp < (sample_rate - (sample_rate / 4)))
 			temp *= 2;
@@ -2024,35 +2029,17 @@ uaudio_chan_play_sync_callback(struct us
 		while (temp > (sample_rate + (sample_rate / 2)))
 			temp /= 2;
 
-		/*
-		 * Some USB audio devices only report a sample rate
-		 * different from the nominal one when they want one
-		 * more or less sample. Make sure we catch this case
-		 * by pulling the sample rate offset slowly towards
-		 * zero if the reported value is equal to the sample
-		 * rate.
-		 */
-		if (temp > sample_rate)
-			ch->feedback.constant += 1;
-		else if (temp < sample_rate)
-			ch->feedback.constant -= 1;
-		else if (ch->feedback.constant > 0)
-			ch->feedback.constant--;
-		else if (ch->feedback.constant < 0)
-			ch->feedback.constant++;
-
-		DPRINTF("Comparing %d Hz :: %d Hz :: %d samples drift\n",
-		    (int)temp, (int)sample_rate, (int)ch->feedback.constant);
+		DPRINTF("Comparing %d Hz :: %d Hz\n",
+		    (int)temp, (int)sample_rate);
 
 		/*
-		 * Range check sync constant. We cannot change the
-		 * number of samples per second by more than the value
-		 * defined by "UAUDIO_IRQS":
+		 * Use feedback value as fallback when there is no
+		 * recording channel:
 		 */
-		if (ch->feedback.constant > UAUDIO_IRQS)
-			ch->feedback.constant = UAUDIO_IRQS;
-		else if (ch->feedback.constant < -UAUDIO_IRQS)
-			ch->feedback.constant = -UAUDIO_IRQS;
+		if (ch->priv_sc->sc_rec_chan.num_alt == 0)
+			ch->jitter_curr = temp - sample_rate;
+
+		ch->feedback_rate = temp;
 		break;
 
 	case USB_ST_SETUP:
@@ -2066,43 +2053,98 @@ uaudio_chan_play_sync_callback(struct us
 	}
 }
 
+static int
+uaudio_chan_is_async(struct uaudio_chan *ch, uint8_t alt)
+{
+	uint8_t attr = ch->usb_alt[alt].p_ed1->bmAttributes;
+	return (UE_GET_ISO_TYPE(attr) == UE_ISO_ASYNC);
+}
+
 static void
 uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
+	struct uaudio_chan *ch_rec;
 	struct usb_page_cache *pc;
-	uint32_t sample_size = ch->usb_alt[ch->cur_alt].sample_size;
 	uint32_t mfl;
 	uint32_t total;
 	uint32_t blockcount;
 	uint32_t n;
 	uint32_t offset;
+	int sample_size;
 	int actlen;
 	int sumlen;
 
-	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
-
-	if (ch->end == ch->start) {
-		DPRINTF("no buffer!\n");
+	if (ch->running == 0 || ch->start == ch->end) {
+		DPRINTF("not running or no buffer!\n");
 		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
+		ch_rec = NULL;
+
+	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
+
 	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_SETUP:
+tr_setup:
+		if (ch_rec != NULL) {
+			/* reset receive jitter counters */
+			mtx_lock(ch_rec->pcm_mtx);
+			ch_rec->jitter_curr = 0;
+			ch_rec->jitter_rem = 0;
+			mtx_unlock(ch_rec->pcm_mtx);
+		}
+
+		/* reset transmit jitter counters */
+		ch->jitter_curr = 0;
+		ch->jitter_rem = 0;
+
+		/* FALLTHROUGH */
 	case USB_ST_TRANSFERRED:
-tr_transferred:
 		if (actlen < sumlen) {
 			DPRINTF("short transfer, "
 			    "%d of %d bytes\n", actlen, sumlen);
 		}
 		chn_intr(ch->pcm_ch);
 
+		/*
+		 * Check for asynchronous playback endpoint and that
+		 * the playback endpoint is properly configured:
+		 */
+		if (ch_rec != NULL &&
+		    uaudio_chan_is_async(ch, ch->cur_alt) != 0) {
+			mtx_lock(ch_rec->pcm_mtx);
+			if (ch_rec->cur_alt < ch_rec->num_alt) {
+				int64_t tx_jitter;
+				int64_t rx_rate;
+
+				/* translate receive jitter into transmit jitter */
+				tx_jitter = ch->usb_alt[ch->cur_alt].sample_rate;
+				tx_jitter = (tx_jitter * ch_rec->jitter_curr) +
+				    ch->jitter_rem;
+
+				/* reset receive jitter counters */
+				ch_rec->jitter_curr = 0;
+				ch_rec->jitter_rem = 0;
+		
+				/* compute exact number of transmit jitter samples */
+				rx_rate = ch_rec->usb_alt[ch_rec->cur_alt].sample_rate;
+				ch->jitter_curr += tx_jitter / rx_rate;
+				ch->jitter_rem = tx_jitter % rx_rate;
+			}
+			mtx_unlock(ch_rec->pcm_mtx);
+		}
+
 		/* start the SYNC transfer one time per second, if any */
-		if (++(ch->feedback.time) >= UAUDIO_IRQS) {
-			ch->feedback.time = 0;
+		if (++(ch->intr_counter) >= UAUDIO_IRQS) {
+			ch->intr_counter = 0;
 			usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]);
 		}
 
-	case USB_ST_SETUP:
 		mfl = usbd_xfer_max_framelen(xfer);
 
 		if (ch->bytes_per_frame[1] > mfl) {
@@ -2118,6 +2160,9 @@ tr_transferred:
 		/* setup number of frames */
 		usbd_xfer_set_frames(xfer, blockcount);
 
+		/* get sample size */
+		sample_size = ch->usb_alt[ch->cur_alt].sample_size;
+
 		/* reset total length */
 		total = 0;
 
@@ -2133,31 +2178,23 @@ tr_transferred:
 				frame_len = ch->bytes_per_frame[0];
 			}
 
-			if (n == (blockcount - 1)) {
-				/*
-				 * Update sync remainder and check if
-				 * we should transmit more or less
-				 * data:
-				 */
-				ch->feedback.remainder += ch->feedback.constant;
-				if (ch->feedback.remainder >= UAUDIO_IRQS) {
-					ch->feedback.remainder -= UAUDIO_IRQS;
-					DPRINTFN(6, "sending one sample more\n");
-					if ((frame_len + sample_size) <= mfl)
-						frame_len += sample_size;
-				} else if (ch->feedback.remainder <= -UAUDIO_IRQS) {
-					ch->feedback.remainder += UAUDIO_IRQS;
-					DPRINTFN(6, "sending one sample less\n");
-					if (frame_len >= sample_size)
-						frame_len -= sample_size;
-				}
+			/* handle free running clock case */
+			if (ch->jitter_curr > 0 &&
+			    (frame_len + sample_size) <= mfl) {
+				DPRINTFN(6, "sending one sample more\n");
+				ch->jitter_curr--;
+				frame_len += sample_size;
+			} else if (ch->jitter_curr < 0 &&
+			    frame_len >= sample_size) {
+				DPRINTFN(6, "sending one sample less\n");
+				ch->jitter_curr++;
+				frame_len -= sample_size;
 			}
-
 			usbd_xfer_set_frame_len(xfer, n, frame_len);
 			total += frame_len;
 		}
 
-		DPRINTFN(6, "transfer %d bytes\n", total);
+		DPRINTFN(6, "transferring %d bytes\n", total);
 
 		offset = 0;
 
@@ -2165,28 +2202,25 @@ tr_transferred:
 		while (total > 0) {
 
 			n = (ch->end - ch->cur);
-			if (n > total) {
+			if (n > total)
 				n = total;
-			}
+
 			usbd_copy_in(pc, offset, ch->cur, n);
 
 			total -= n;
 			ch->cur += n;
 			offset += n;
 
-			if (ch->cur >= ch->end) {
+			if (ch->cur >= ch->end)
 				ch->cur = ch->start;
-			}
 		}
-
 		usbd_transfer_submit(xfer);
 		break;
 
 	default:			/* Error */
-		if (error == USB_ERR_CANCELLED) {
-			break;
-		}
-		goto tr_transferred;
+		if (error != USB_ERR_CANCELLED)
+			goto tr_setup;
+		break;
 	}
 }
 
@@ -2202,36 +2236,59 @@ uaudio_chan_record_callback(struct usb_x
 	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
 	struct usb_page_cache *pc;
 	uint32_t offset0;
-	uint32_t offset1;
 	uint32_t mfl;
 	int m;
 	int n;
 	int len;
 	int actlen;
 	int nframes;
-	int blockcount;
-
-	usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
-	mfl = usbd_xfer_max_framelen(xfer);
+	int expected_bytes;
+	int sample_size;
 
-	if (ch->end == ch->start) {
+	if (ch->start == ch->end) {
 		DPRINTF("no buffer!\n");
 		return;
 	}
 
+	usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
+	mfl = usbd_xfer_max_framelen(xfer);
+
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
 
-		DPRINTFN(6, "transferred %d bytes\n", actlen);
-
 		offset0 = 0;
 		pc = usbd_xfer_get_frame(xfer, 0);
 
+		/* try to compute the number of expected bytes */
+		ch->sample_curr += (ch->sample_rem * ch->intr_frames);
+
+		/* compute number of expected bytes */
+		expected_bytes = (ch->intr_frames * ch->bytes_per_frame[0]) +
+		    ((ch->sample_curr / ch->frames_per_second) *
+		    (ch->bytes_per_frame[1] - ch->bytes_per_frame[0]));
+
+		/* keep remainder */
+		ch->sample_curr %= ch->frames_per_second;
+
+		/* get current sample size */
+		sample_size = ch->usb_alt[ch->cur_alt].sample_size;
+
 		for (n = 0; n != nframes; n++) {
+			uint32_t offset1 = offset0;
 
-			offset1 = offset0;
 			len = usbd_xfer_frame_len(xfer, n);
 
+			/* make sure we only receive complete samples */
+			len = len - (len % sample_size);
+
+			/* subtract bytes received from expected payload */
+			expected_bytes -= len;
+
+			/* don't receive data when not ready */
+			if (ch->running == 0 || ch->cur_alt != ch->set_alt)
+				continue;
+
+			/* fill ring buffer with samples, if any */
 			while (len > 0) {
 
 				m = (ch->end - ch->cur);
@@ -2245,33 +2302,46 @@ uaudio_chan_record_callback(struct usb_x
 				offset1 += m;
 				ch->cur += m;
 
-				if (ch->cur >= ch->end) {
+				if (ch->cur >= ch->end)
 					ch->cur = ch->start;
-				}
 			}
 
 			offset0 += mfl;
 		}
 
-		chn_intr(ch->pcm_ch);
+		/* update current jitter */
+		ch->jitter_curr -= (expected_bytes / sample_size);
+
+		/* don't allow a huge amount of jitter to accumulate */
+		nframes = 2 * ch->intr_frames;
+
+		/* range check current jitter */
+		if (ch->jitter_curr < -nframes)
+			ch->jitter_curr = -nframes;
+		else if (ch->jitter_curr > nframes)
+			ch->jitter_curr = nframes;
+
+		DPRINTFN(6, "transferred %d bytes, jitter %d samples\n",
+		    actlen, ch->jitter_curr);
+
+		if (ch->running != 0)
+			chn_intr(ch->pcm_ch);
 
 	case USB_ST_SETUP:
 tr_setup:
-		blockcount = ch->intr_frames;
+		nframes = ch->intr_frames;
 
-		usbd_xfer_set_frames(xfer, blockcount);
-		for (n = 0; n < blockcount; n++) {
+		usbd_xfer_set_frames(xfer, nframes);
+		for (n = 0; n != nframes; n++)
 			usbd_xfer_set_frame_len(xfer, n, mfl);
-		}
 
 		usbd_transfer_submit(xfer);
 		break;
 
 	default:			/* Error */
-		if (error == USB_ERR_CANCELLED) {
-			break;
-		}
-		goto tr_setup;
+		if (error != USB_ERR_CANCELLED)
+			goto tr_setup;
+		break;
 	}
 }
 
@@ -2344,13 +2414,7 @@ int
 uaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize)
 {
 	uint32_t temp = 2 * uaudio_get_buffer_size(ch, ch->set_alt);
-
 	sndbuf_setup(ch->pcm_buf, ch->buf, temp);
-
-	ch->start = ch->buf;
-	ch->end = ch->buf + temp;
-	ch->cur = ch->buf;
-
 	return (temp / 2);
 }
 
@@ -2364,8 +2428,11 @@ uaudio_chan_set_param_fragments(struct u
 int
 uaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed)
 {
+	struct uaudio_softc *sc;
 	uint8_t x;
 
+	sc = ch->priv_sc;
+
 	for (x = 0; x < ch->num_alt; x++) {
 		if (ch->usb_alt[x].sample_rate < speed) {
 			/* sample rate is too low */
@@ -2376,7 +2443,9 @@ uaudio_chan_set_param_speed(struct uaudi
 	if (x != 0)
 		x--;
 
+	usb_proc_explore_lock(sc->sc_udev);
 	ch->set_alt = x;
+	usb_proc_explore_unlock(sc->sc_udev);
 
 	DPRINTF("Selecting alt %d\n", (int)x);
 
@@ -2447,16 +2516,16 @@ uaudio_chan_set_param_format(struct uaud
 	return (0);
 }
 
-int
-uaudio_chan_start(struct uaudio_chan *ch)
+static void
+uaudio_chan_start_sub(struct uaudio_chan *ch)
 {
 	struct uaudio_softc *sc = ch->priv_sc;
 	int do_start = 0;
 
-	usb_proc_explore_lock(sc->sc_udev);
 	if (ch->operation != CHAN_OP_DRAIN) {
 		if (ch->cur_alt == ch->set_alt &&
-		    ch->operation == CHAN_OP_NONE) {
+		    ch->operation == CHAN_OP_NONE &&
+		    mtx_owned(ch->pcm_mtx) != 0) {
 			/* save doing the explore task */
 			do_start = 1;
 		} else {
@@ -2465,28 +2534,81 @@ uaudio_chan_start(struct uaudio_chan *ch
 			    &sc->sc_config_msg[0], &sc->sc_config_msg[1]);
 		}
 	}
-	usb_proc_explore_unlock(sc->sc_udev);
-
-	/* reset feedback endpoint state */
-	memset(&ch->feedback, 0, sizeof(ch->feedback));
-
 	if (do_start) {
 		usbd_transfer_start(ch->xfer[0]);
 		usbd_transfer_start(ch->xfer[1]);
 	}
-	return (0);
 }
 
-int
-uaudio_chan_stop(struct uaudio_chan *ch)
+static int
+uaudio_chan_need_both(struct uaudio_softc *sc)
+{
+	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);
+}
+
+static int
+uaudio_chan_need_none(struct uaudio_softc *sc)
+{
+	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);
+}
+
+void
+uaudio_chan_start(struct uaudio_chan *ch)
 {
 	struct uaudio_softc *sc = ch->priv_sc;
-	int do_stop = 0;
 
+	/* make operation atomic */
 	usb_proc_explore_lock(sc->sc_udev);
+
+	/* check if not running */
+	if (ch->running == 0) {
+	  	uint32_t temp;
+
+		/* get current buffer size */
+		temp = 2 * uaudio_get_buffer_size(ch, ch->set_alt);
+
+		/* set running flag */
+		ch->running = 1;
+
+		/* ensure the hardware buffer is reset */
+		ch->start = ch->buf;
+		ch->end = ch->buf + temp;
+		ch->cur = ch->buf;
+
+		if (uaudio_chan_need_both(sc)) {
+			/*
+			 * 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);
+		} else {
+			uaudio_chan_start_sub(ch);
+		}
+	}
+
+	/* exit atomic operation */
+	usb_proc_explore_unlock(sc->sc_udev);
+}
+
+static void
+uaudio_chan_stop_sub(struct uaudio_chan *ch)
+{
+	struct uaudio_softc *sc = ch->priv_sc;
+	int do_stop = 0;
+
 	if (ch->operation != CHAN_OP_DRAIN) {
 		if (ch->cur_alt == ch->set_alt &&
-		    ch->operation == CHAN_OP_NONE) {
+		    ch->operation == CHAN_OP_NONE &&
+		    mtx_owned(ch->pcm_mtx) != 0) {
 			/* save doing the explore task */
 			do_stop = 1;
 		} else {
@@ -2495,13 +2617,44 @@ uaudio_chan_stop(struct uaudio_chan *ch)
 			    &sc->sc_config_msg[0], &sc->sc_config_msg[1]);
 		}
 	}
-	usb_proc_explore_unlock(sc->sc_udev);
-
 	if (do_stop) {
 		usbd_transfer_stop(ch->xfer[0]);
 		usbd_transfer_stop(ch->xfer[1]);
 	}
-	return (0);
+}
+
+void
+uaudio_chan_stop(struct uaudio_chan *ch)
+{
+	struct uaudio_softc *sc = ch->priv_sc;
+
+	/* make operation atomic */
+	usb_proc_explore_lock(sc->sc_udev);
+
+	/* check if running */
+	if (ch->running != 0) {
+		/* clear running flag */
+		ch->running = 0;
+
+		if (uaudio_chan_need_both(sc)) {
+			/*
+			 * Leave the endpoints running because we need
+			 * information about jitter!
+			 */
+		} else if (uaudio_chan_need_none(sc)) {
+			/*
+			 * 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);
+		} else {
+			uaudio_chan_stop_sub(ch);
+		}
+	}
+
+	/* exit atomic operation */
+	usb_proc_explore_unlock(sc->sc_udev);
 }
 
 /*========================================================================*

Modified: stable/9/sys/dev/sound/usb/uaudio.h
==============================================================================
--- stable/9/sys/dev/sound/usb/uaudio.h	Wed Mar 25 13:15:47 2015	(r280593)
+++ stable/9/sys/dev/sound/usb/uaudio.h	Wed Mar 25 13:16:39 2015	(r280594)
@@ -54,8 +54,8 @@ extern struct	pcmchan_matrix *uaudio_cha
 		    uint32_t format);
 extern int	uaudio_chan_set_param_format(struct uaudio_chan *ch,
 		    uint32_t format);
-extern int	uaudio_chan_start(struct uaudio_chan *ch);
-extern int	uaudio_chan_stop(struct uaudio_chan *ch);
+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);

Modified: stable/9/sys/dev/sound/usb/uaudio_pcm.c
==============================================================================
--- stable/9/sys/dev/sound/usb/uaudio_pcm.c	Wed Mar 25 13:15:47 2015	(r280593)
+++ stable/9/sys/dev/sound/usb/uaudio_pcm.c	Wed Mar 25 13:16:39 2015	(r280594)
@@ -81,14 +81,14 @@ ua_chan_setfragments(kobj_t obj, void *d
 static int
 ua_chan_trigger(kobj_t obj, void *data, int go)
 {
-	if (!PCMTRIG_COMMON(go)) {
-		return (0);
-	}
-	if (go == PCMTRIG_START) {
-		return (uaudio_chan_start(data));
-	} else {
-		return (uaudio_chan_stop(data));
+	if (PCMTRIG_COMMON(go)) {
+		if (go == PCMTRIG_START) {
+			uaudio_chan_start(data);
+		} else {
+			uaudio_chan_stop(data);
+		}
 	}
+	return (0);
 }
 
 static uint32_t


More information about the svn-src-all mailing list