Module Name:    src
Committed By:   skrll
Date:           Sat Sep 19 07:39:51 UTC 2015

Modified Files:
        src/sys/dev/usb [nick-nhusb]: ucom.c

Log Message:
Make ucom(4) MP safe


To generate a diff of this commit:
cvs rdiff -u -r1.108.2.7 -r1.108.2.8 src/sys/dev/usb/ucom.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/ucom.c
diff -u src/sys/dev/usb/ucom.c:1.108.2.7 src/sys/dev/usb/ucom.c:1.108.2.8
--- src/sys/dev/usb/ucom.c:1.108.2.7	Thu Jul 23 07:36:33 2015
+++ src/sys/dev/usb/ucom.c	Sat Sep 19 07:39:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: ucom.c,v 1.108.2.7 2015/07/23 07:36:33 skrll Exp $	*/
+/*	$NetBSD: ucom.c,v 1.108.2.8 2015/09/19 07:39:51 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.108.2.7 2015/07/23 07:36:33 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.108.2.8 2015/09/19 07:39:51 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -179,7 +179,11 @@ struct ucom_softc {
 
 	struct pps_state	sc_pps_state;	/* pps state */
 
-	krndsource_t	sc_rndsource;	/* random source */
+	krndsource_t		sc_rndsource;	/* random source */
+
+	kmutex_t		*sc_lock;
+	kcondvar_t		sc_opencv;
+	kcondvar_t		sc_detachcv;
 };
 
 dev_type_open(ucomopen);
@@ -203,7 +207,7 @@ const struct cdevsw ucom_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = ttykqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_TTY
+	.d_flag = D_TTY | D_MPSAFE
 };
 
 static void	ucom_cleanup(struct ucom_softc *);
@@ -278,7 +282,10 @@ ucom_attach(device_t parent, device_t se
 	sc->sc_refcnt = 0;
 	sc->sc_dying = 0;
 
-	sc->sc_si = softint_establish(SOFTINT_NET, ucom_softintr, sc);
+	sc->sc_si = softint_establish(SOFTINT_USB, ucom_softintr, sc);
+	sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTUSB);
+	cv_init(&sc->sc_opencv, "ucomopen");
+	cv_init(&sc->sc_detachcv, "ucomdtch");
 
 	tp = tty_alloc();
 	tp->t_oproc = ucomstart;
@@ -303,14 +310,17 @@ ucom_detach(device_t self, int flags)
 	struct ucom_softc *sc = device_private(self);
 	struct tty *tp = sc->sc_tty;
 	int maj, mn;
-	int s, i;
+	int i;
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
 	DPRINTF("sc=%p flags=%d tp=%p", sc, flags, tp, 0);
 	DPRINTF("... pipe=%d,%d",sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
 
+	mutex_enter(sc->sc_lock);
 	sc->sc_dying = 1;
+	mutex_exit(sc->sc_lock);
+
 	pmf_device_deregister(self);
 
 	if (sc->sc_bulkin_pipe != NULL)
@@ -318,8 +328,8 @@ ucom_detach(device_t self, int flags)
 	if (sc->sc_bulkout_pipe != NULL)
 		usbd_abort_pipe(sc->sc_bulkout_pipe);
 
-	s = splusb();
-	if (--sc->sc_refcnt >= 0) {
+	mutex_enter(sc->sc_lock);
+	while (sc->sc_refcnt > 0) {
 		/* Wake up anyone waiting */
 		if (tp != NULL) {
 			mutex_spin_enter(&tty_lock);
@@ -329,11 +339,11 @@ ucom_detach(device_t self, int flags)
 			mutex_spin_exit(&tty_lock);
 		}
 		/* Wait for processes to go away. */
-		usb_detach_waitold(sc->sc_dev);
+		usb_detach_wait(sc->sc_dev, &sc->sc_detachcv, sc->sc_lock);
 	}
 
 	softint_disestablish(sc->sc_si);
-	splx(s);
+	mutex_exit(sc->sc_lock);
 
 	/* locate the major number */
 	maj = cdevsw_lookup_major(&ucom_cdevsw);
@@ -365,6 +375,10 @@ ucom_detach(device_t self, int flags)
 	/* Detach the random source */
 	rnd_detach_source(&sc->sc_rndsource);
 
+	mutex_destroy(sc->sc_lock);
+	cv_destroy(&sc->sc_opencv);
+	cv_destroy(&sc->sc_detachcv);
+
 	return 0;
 }
 
@@ -379,7 +393,9 @@ ucom_activate(device_t self, enum devact
 
 	switch (act) {
 	case DVACT_DEACTIVATE:
+		mutex_enter(sc->sc_lock);
 		sc->sc_dying = 1;
+		mutex_exit(sc->sc_lock);
 		return 0;
 	default:
 		return EOPNOTSUPP;
@@ -393,13 +409,15 @@ ucom_shutdown(struct ucom_softc *sc)
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
+	KASSERT(mutex_owned(sc->sc_lock));
 	/*
 	 * Hang up if necessary.  Wait a bit, so the other side has time to
 	 * notice even if we immediately open the port again.
 	 */
 	if (ISSET(tp->t_cflag, HUPCL)) {
 		ucom_dtr(sc, 0);
-		(void)tsleep(sc, TTIPRI, ttclos, hz);
+		/* XXX will only timeout */
+		(void) kpause(ttclos, false, hz, sc->sc_lock);
 	}
 }
 
@@ -411,7 +429,7 @@ ucomopen(dev_t dev, int flag, int mode, 
 	struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
 	struct ucom_buffer *ub;
 	struct tty *tp;
-	int s, i;
+	int i;
 	int error;
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
@@ -419,31 +437,38 @@ ucomopen(dev_t dev, int flag, int mode, 
 	if (sc == NULL)
 		return ENXIO;
 
-	if (sc->sc_dying)
+	mutex_enter(sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(sc->sc_lock);
 		return EIO;
+	}
 
-	if (!device_is_active(sc->sc_dev))
+	if (!device_is_active(sc->sc_dev)) {
+		mutex_exit(sc->sc_lock);
 		return ENXIO;
+	}
 
 	tp = sc->sc_tty;
 
 	DPRINTF("unit=%d, tp=%p\n", unit, tp, 0, 0);
 
-	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
+	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
+		mutex_exit(sc->sc_lock);
 		return EBUSY;
-
-	s = spltty();
+	}
 
 	/*
 	 * Do the following iff this is a first open.
 	 */
-	while (sc->sc_opening)
-		tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
+	while (sc->sc_opening) {
+		error = cv_wait_sig(&sc->sc_opencv, sc->sc_lock);
 
-	if (sc->sc_dying) {
-		splx(s);
-		return EIO;
+		if (error) {
+			mutex_exit(sc->sc_lock);
+			return error;
+		}
 	}
+
 	sc->sc_opening = 1;
 
 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
@@ -457,8 +482,8 @@ ucomopen(dev_t dev, int flag, int mode, 
 			if (error) {
 				ucom_cleanup(sc);
 				sc->sc_opening = 0;
-				wakeup(&sc->sc_opening);
-				splx(s);
+				cv_signal(&sc->sc_opencv);
+				mutex_exit(sc->sc_lock);
 				return error;
 			}
 		}
@@ -577,8 +602,8 @@ ucomopen(dev_t dev, int flag, int mode, 
 
 	}
 	sc->sc_opening = 0;
-	wakeup(&sc->sc_opening);
-	splx(s);
+	cv_signal(&sc->sc_opencv);
+	mutex_exit(sc->sc_lock);
 
 	error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
 	if (error)
@@ -614,13 +639,15 @@ fail_1:
 	usbd_close_pipe(sc->sc_bulkin_pipe);
 	sc->sc_bulkin_pipe = NULL;
 fail_0:
+	mutex_enter(sc->sc_lock);
 	sc->sc_opening = 0;
-	wakeup(&sc->sc_opening);
-	splx(s);
+	cv_signal(&sc->sc_opencv);
+	mutex_exit(sc->sc_lock);
+
 	return error;
 
 bad:
-	s = spltty();
+	mutex_spin_enter(&tty_lock);
 	CLR(tp->t_state, TS_BUSY);
 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
 		/*
@@ -629,7 +656,7 @@ bad:
 		 */
 		ucom_cleanup(sc);
 	}
-	splx(s);
+	mutex_spin_exit(&tty_lock);
 
 	return error;
 }
@@ -639,7 +666,6 @@ ucomclose(dev_t dev, int flag, int mode,
 {
 	struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
 	struct tty *tp;
-	int s;
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
@@ -648,12 +674,13 @@ ucomclose(dev_t dev, int flag, int mode,
 	if (sc == NULL)
 		return 0;
 
+	mutex_enter(sc->sc_lock);
 	tp = sc->sc_tty;
 
-	if (!ISSET(tp->t_state, TS_ISOPEN))
-		return 0;
+	if (!ISSET(tp->t_state, TS_ISOPEN)) {
+		goto out;
+	}
 
-	s = spltty();
 	sc->sc_refcnt++;
 
 	(*tp->t_linesw->l_close)(tp, flag);
@@ -672,8 +699,10 @@ ucomclose(dev_t dev, int flag, int mode,
 		sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
 
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeupold(sc->sc_dev);
-	splx(s);
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
+
+out:
+	mutex_exit(sc->sc_lock);
 
 	return 0;
 }
@@ -687,15 +716,26 @@ ucomread(dev_t dev, struct uio *uio, int
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
-	if (sc == NULL || sc->sc_dying)
+	if (sc == NULL)
+		return EIO;
+
+	mutex_enter(sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(sc->sc_lock);
 		return EIO;
+	}
 
 	tp = sc->sc_tty;
 
 	sc->sc_refcnt++;
+	mutex_exit(sc->sc_lock);
 	error = ((*tp->t_linesw->l_read)(tp, uio, flag));
+	mutex_enter(sc->sc_lock);
+
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeupold(sc->sc_dev);
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
+	mutex_exit(sc->sc_lock);
+
 	return error;
 }
 
@@ -706,15 +746,25 @@ ucomwrite(dev_t dev, struct uio *uio, in
 	struct tty *tp;
 	int error;
 
-	if (sc == NULL || sc->sc_dying)
+	if (sc == NULL)
+		return EIO;
+
+	mutex_enter(sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(sc->sc_lock);
 		return EIO;
+	}
 
 	tp = sc->sc_tty;
 
 	sc->sc_refcnt++;
+	mutex_exit(sc->sc_lock);
 	error = ((*tp->t_linesw->l_write)(tp, uio, flag));
+	mutex_enter(sc->sc_lock);
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeupold(sc->sc_dev);
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
+	mutex_exit(sc->sc_lock);
+
 	return error;
 }
 
@@ -726,15 +776,24 @@ ucompoll(dev_t dev, int events, struct l
 	int revents;
 
 	sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
-	if (sc == NULL || sc->sc_dying)
+	if (sc == NULL)
 		return POLLHUP;
 
+	mutex_enter(sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(sc->sc_lock);
+		return POLLHUP;
+	}
 	tp = sc->sc_tty;
 
 	sc->sc_refcnt++;
+	mutex_exit(sc->sc_lock);
 	revents = ((*tp->t_linesw->l_poll)(tp, events, l));
+	mutex_enter(sc->sc_lock);
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeupold(sc->sc_dev);
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
+	mutex_exit(sc->sc_lock);
+
 	return revents;
 }
 
@@ -752,13 +811,20 @@ ucomioctl(dev_t dev, u_long cmd, void *d
 	struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
 	int error;
 
-	if (sc == NULL || sc->sc_dying)
+	if (sc == NULL)
 		return EIO;
 
+	mutex_enter(sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(sc->sc_lock);
+		return EIO;
+	}
+
 	sc->sc_refcnt++;
 	error = ucom_do_ioctl(sc, cmd, data, flag, l);
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeupold(sc->sc_dev);
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
+	mutex_exit(sc->sc_lock);
 	return error;
 }
 
@@ -768,7 +834,6 @@ ucom_do_ioctl(struct ucom_softc *sc, u_l
 {
 	struct tty *tp = sc->sc_tty;
 	int error;
-	int s;
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
@@ -792,7 +857,7 @@ ucom_do_ioctl(struct ucom_softc *sc, u_l
 	error = 0;
 
 	DPRINTF("our cmd=0x%08lx", cmd, 0, 0, 0);
-	s = spltty();
+	//mutex_enter(&tty_lock);
 
 	switch (cmd) {
 	case TIOCSBRK:
@@ -852,7 +917,7 @@ ucom_do_ioctl(struct ucom_softc *sc, u_l
 		break;
 	}
 
-	splx(s);
+	//mutex_exit(&tty_lock);
 
 	return error;
 }
@@ -1066,15 +1131,15 @@ ucomhwiflow(struct tty *tp, int block)
 	if (sc == NULL)
 		return 0;
 
+	mutex_enter(sc->sc_lock);
 	old = sc->sc_rx_stopped;
 	sc->sc_rx_stopped = (u_char)block;
 
 	if (old && !block) {
-		int s = splusb();
 		sc->sc_rx_unblock = 1;
 		softint_schedule(sc->sc_si);
-		splx(s);
 	}
+	mutex_exit(sc->sc_lock);
 
 	return 1;
 }
@@ -1085,14 +1150,18 @@ ucomstart(struct tty *tp)
 	struct ucom_softc *sc = device_lookup_private(&ucom_cd,
 	    UCOMUNIT(tp->t_dev));
 	struct ucom_buffer *ub;
-	int s;
 	u_char *data;
 	int cnt;
 
-	if (sc == NULL || sc->sc_dying)
+	if (sc == NULL)
 		return;
 
-	s = spltty();
+	KASSERT(sc->sc_lock);
+	KASSERT(mutex_owned(&tty_lock));
+	if (sc->sc_dying) {
+		return;
+	}
+
 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
 		goto out;
 	if (sc->sc_tx_stopped)
@@ -1113,6 +1182,7 @@ ucomstart(struct tty *tp)
 		SET(tp->t_state, TS_BUSY);
 		goto out;
 	}
+
 	SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_free, ub_link);
 
 	if (SIMPLEQ_FIRST(&sc->sc_obuff_free) == NULL)
@@ -1135,24 +1205,26 @@ ucomstart(struct tty *tp)
 	softint_schedule(sc->sc_si);
 
  out:
-	splx(s);
+	return;
 }
 
 void
 ucomstop(struct tty *tp, int flag)
 {
 #if 0
-	/*struct ucom_softc *sc =
-	    device_lookup_private(&ucom_cd, UCOMUNIT(tp->t_dev));*/
-	int s;
+	struct ucom_softc *sc =
+	    device_lookup_private(&ucom_cd, UCOMUNIT(tp->t_dev));
 
-	s = spltty();
+	mutex_enter(sc->sc_lock);
+	mutex_spin_enter(&tty_lock);
 	if (ISSET(tp->t_state, TS_BUSY)) {
+		/* obuff_full -> obuff_free? */
 		/* sc->sc_tx_stopped = 1; */
 		if (!ISSET(tp->t_state, TS_TTSTOP))
 			SET(tp->t_state, TS_FLUSH);
 	}
-	splx(s);
+	mutex_spin_exit(&tty_lock);
+	mutex_exit(sc->sc_lock);
 #endif
 }
 
@@ -1163,6 +1235,8 @@ ucom_write_status(struct ucom_softc *sc,
 	struct tty *tp = sc->sc_tty;
 	uint32_t cc = ub->ub_len;
 
+	KASSERT(mutex_owned(sc->sc_lock));
+
 	switch (err) {
 	case USBD_IN_PROGRESS:
 		ub->ub_index = ub->ub_len;
@@ -1193,17 +1267,20 @@ ucom_write_status(struct ucom_softc *sc,
 			if ((ub = SIMPLEQ_FIRST(&sc->sc_obuff_full)) != NULL)
 				ucom_submit_write(sc, ub);
 
+			mutex_spin_enter(&tty_lock);
 			(*tp->t_linesw->l_start)(tp);
+			mutex_spin_exit(&tty_lock);
 		}
 		break;
 	}
 }
 
-/* Call at spltty() */
 static void
 ucom_submit_write(struct ucom_softc *sc, struct ucom_buffer *ub)
 {
 
+	KASSERT(mutex_owned(sc->sc_lock));
+
 	usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkout_pipe,
 	    (void *)sc, ub->ub_data, ub->ub_len,
 	    0, USBD_NO_TIMEOUT, ucomwritecb);
@@ -1215,13 +1292,11 @@ static void
 ucomwritecb(struct usbd_xfer *xfer, void *p, usbd_status status)
 {
 	struct ucom_softc *sc = (struct ucom_softc *)p;
-	int s;
-
-	s = spltty();
 
+	mutex_enter(sc->sc_lock);
 	ucom_write_status(sc, SIMPLEQ_FIRST(&sc->sc_obuff_full), status);
+	mutex_exit(sc->sc_lock);
 
-	splx(s);
 }
 
 static void
@@ -1230,12 +1305,15 @@ ucom_softintr(void *arg)
 	struct ucom_softc *sc = arg;
 	struct tty *tp = sc->sc_tty;
 	struct ucom_buffer *ub;
-	int s;
 
-	if (!ISSET(tp->t_state, TS_ISOPEN))
+	mutex_enter(sc->sc_lock);
+	mutex_enter(&tty_lock);
+	if (!ISSET(tp->t_state, TS_ISOPEN)) {
+		mutex_exit(&tty_lock);
+		mutex_exit(sc->sc_lock);
 		return;
-
-	s = spltty();
+	}
+	mutex_exit(&tty_lock);
 
 	ub = SIMPLEQ_FIRST(&sc->sc_obuff_full);
 
@@ -1245,7 +1323,7 @@ ucom_softintr(void *arg)
 	if (sc->sc_rx_unblock)
 		ucom_read_complete(sc);
 
-	splx(s);
+	mutex_exit(sc->sc_lock);
 }
 
 static void
@@ -1254,7 +1332,8 @@ ucom_read_complete(struct ucom_softc *sc
 	int (*rint)(int, struct tty *);
 	struct ucom_buffer *ub;
 	struct tty *tp;
-	int s;
+
+	KASSERT(mutex_owned(sc->sc_lock));
 
 	tp = sc->sc_tty;
 	rint = tp->t_linesw->l_rint;
@@ -1262,8 +1341,7 @@ ucom_read_complete(struct ucom_softc *sc
 
 	while (ub != NULL && !sc->sc_rx_stopped) {
 
-		s = spltty();
-
+		/* XXX ttyinput takes tty_lock */
 		while (ub->ub_index < ub->ub_len && !sc->sc_rx_stopped) {
 			/* Give characters to tty layer. */
 			if ((*rint)(ub->ub_data[ub->ub_index], tp) == -1) {
@@ -1273,8 +1351,6 @@ ucom_read_complete(struct ucom_softc *sc
 				ub->ub_index++;
 		}
 
-		splx(s);
-
 		if (ub->ub_index == ub->ub_len) {
 			SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_full, ub_link);
 
@@ -1315,10 +1391,10 @@ ucomreadcb(struct usbd_xfer *xfer, void 
 	struct ucom_buffer *ub;
 	uint32_t cc;
 	u_char *cp;
-	int s;
 
 	UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
+	mutex_enter(sc->sc_lock);
 	ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty);
 	SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link);
 
@@ -1327,25 +1403,26 @@ ucomreadcb(struct usbd_xfer *xfer, void 
 		DPRINTF("dying", 0, 0, 0, 0);
 		ub->ub_index = ub->ub_len = 0;
 		/* Send something to wake upper layer */
-		s = spltty();
 		if (status != USBD_CANCELLED) {
 			(tp->t_linesw->l_rint)('\n', tp);
 			mutex_spin_enter(&tty_lock);	/* XXX */
 			ttwakeup(tp);
 			mutex_spin_exit(&tty_lock);	/* XXX */
 		}
-		splx(s);
+		mutex_exit(sc->sc_lock);
 		return;
 	}
 
 	if (status == USBD_STALLED) {
 		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
 		ucomsubmitread(sc, ub);
+		mutex_exit(sc->sc_lock);
 		return;
 	}
 
 	if (status != USBD_NORMAL_COMPLETION) {
 		printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status));
+		mutex_exit(sc->sc_lock);
 		return;
 	}
 
@@ -1364,6 +1441,7 @@ ucomreadcb(struct usbd_xfer *xfer, void 
 
 	if (sc->sc_opening) {
 		ucomsubmitread(sc, ub);
+		mutex_exit(sc->sc_lock);
 		return;
 	}
 
@@ -1379,6 +1457,7 @@ ucomreadcb(struct usbd_xfer *xfer, void 
 	SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_full, ub, ub_link);
 
 	ucom_read_complete(sc);
+	mutex_exit(sc->sc_lock);
 }
 
 static void
@@ -1390,16 +1469,24 @@ ucom_cleanup(struct ucom_softc *sc)
 
 	DPRINTF("closing pipes", 0, 0, 0, 0);
 
+	KASSERT(mutex_owned(sc->sc_lock));
+
 	ucom_shutdown(sc);
 	if (sc->sc_bulkin_pipe != NULL) {
-		usbd_abort_pipe(sc->sc_bulkin_pipe);
-		usbd_close_pipe(sc->sc_bulkin_pipe);
+		struct usbd_pipe *bulkin_pipe = sc->sc_bulkin_pipe;
 		sc->sc_bulkin_pipe = NULL;
+		mutex_exit(sc->sc_lock);
+		usbd_abort_pipe(bulkin_pipe);
+		usbd_close_pipe(bulkin_pipe);
+		mutex_enter(sc->sc_lock);
 	}
 	if (sc->sc_bulkout_pipe != NULL) {
-		usbd_abort_pipe(sc->sc_bulkout_pipe);
-		usbd_close_pipe(sc->sc_bulkout_pipe);
+		struct usbd_pipe *bulkout_pipe = sc->sc_bulkout_pipe;
 		sc->sc_bulkout_pipe = NULL;
+		mutex_exit(sc->sc_lock);
+		usbd_abort_pipe(bulkout_pipe);
+		usbd_close_pipe(bulkout_pipe);
+		mutex_enter(sc->sc_lock);
 	}
 	for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS]; ub++) {
 		if (ub->ub_xfer != NULL) {

Reply via email to