Module Name:    src
Committed By:   mrg
Date:           Sat Feb 25 20:52:29 UTC 2012

Modified Files:
        src/sys/dev/usb [jmcneill-usbmp]: uhid.c

Log Message:
mark D_MPSAFE:
- spl -> mutex
- convert to SMP usb_detach_wait/wakeup()
- add a IPL_NONE access lock, used in most devsw entry points


To generate a diff of this commit:
cvs rdiff -u -r1.84.12.1 -r1.84.12.2 src/sys/dev/usb/uhid.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/uhid.c
diff -u src/sys/dev/usb/uhid.c:1.84.12.1 src/sys/dev/usb/uhid.c:1.84.12.2
--- src/sys/dev/usb/uhid.c:1.84.12.1	Fri Feb 24 09:11:43 2012
+++ src/sys/dev/usb/uhid.c	Sat Feb 25 20:52:29 2012
@@ -1,12 +1,12 @@
-/*	$NetBSD: uhid.c,v 1.84.12.1 2012/02/24 09:11:43 mrg Exp $	*/
+/*	$NetBSD: uhid.c,v 1.84.12.2 2012/02/25 20:52:29 mrg Exp $	*/
 
 /*
- * Copyright (c) 1998, 2004, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2004, 2008, 2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Lennart Augustsson (lenn...@augustsson.net) at
- * Carlstedt Research & Technology.
+ * Carlstedt Research & Technology and Matthew R. Green (m...@eterna.com.au).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.84.12.1 2012/02/24 09:11:43 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.84.12.2 2012/02/25 20:52:29 mrg Exp $");
 
 #include "opt_compat_netbsd.h"
 
@@ -78,6 +78,11 @@ int	uhiddebug = 0;
 struct uhid_softc {
 	struct uhidev sc_hdev;
 
+	kmutex_t sc_access_lock; /* serialises syscall accesses */
+	kmutex_t sc_lock;	/* protects refcnt, others */
+	kcondvar_t sc_cv;
+	kcondvar_t sc_detach_cv;
+
 	int sc_isize;
 	int sc_osize;
 	int sc_fsize;
@@ -110,7 +115,7 @@ dev_type_kqfilter(uhidkqfilter);
 
 const struct cdevsw uhid_cdevsw = {
 	uhidopen, uhidclose, uhidread, uhidwrite, uhidioctl,
-	nostop, notty, uhidpoll, nommap, uhidkqfilter, D_OTHER,
+	nostop, notty, uhidpoll, nommap, uhidkqfilter, D_OTHER | D_MPSAFE,
 };
 
 Static void uhid_intr(struct uhidev *, void *, u_int len);
@@ -168,6 +173,11 @@ uhid_attach(device_t parent, device_t se
 	aprint_normal(": input=%d, output=%d, feature=%d\n",
 	       sc->sc_isize, sc->sc_osize, sc->sc_fsize);
 
+	mutex_init(&sc->sc_access_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
+	cv_init(&sc->sc_cv, "uhidrea");
+	cv_init(&sc->sc_detach_cv, "uhiddet");
+
 	if (!pmf_device_register(self, NULL, NULL))
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
@@ -192,23 +202,23 @@ int
 uhid_detach(device_t self, int flags)
 {
 	struct uhid_softc *sc = device_private(self);
-	int s;
 	int maj, mn;
 
 	DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
 
 	sc->sc_dying = 1;
 
+	mutex_enter(&sc->sc_lock);
 	if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
-		s = splusb();
 		if (--sc->sc_refcnt >= 0) {
 			/* Wake everyone */
-			wakeup(&sc->sc_q);
+			cv_broadcast(&sc->sc_cv);
 			/* Wait for processes to go away. */
-			usb_detach_wait(sc->sc_hdev.sc_dev);
+			usb_detach_waitcv(sc->sc_hdev.sc_dev,
+			    &sc->sc_detach_cv, &sc->sc_lock);
 		}
-		splx(s);
 	}
+	mutex_exit(&sc->sc_lock);
 
 	/* locate the major number */
 	maj = cdevsw_lookup_major(&uhid_cdevsw);
@@ -222,6 +232,10 @@ uhid_detach(device_t self, int flags)
 			   sc->sc_hdev.sc_parent->sc_udev,
 			   sc->sc_hdev.sc_dev);
 #endif
+	cv_destroy(&sc->sc_cv);
+	cv_destroy(&sc->sc_detach_cv);
+	mutex_destroy(&sc->sc_lock);
+	mutex_destroy(&sc->sc_access_lock);
 	seldestroy(&sc->sc_rsel);
 	softint_disestablish(sc->sc_sih);
 
@@ -244,18 +258,20 @@ uhid_intr(struct uhidev *addr, void *dat
 	}
 #endif
 
+	mutex_enter(&sc->sc_lock);
 	(void)b_to_q(data, len, &sc->sc_q);
 
 	if (sc->sc_state & UHID_ASLP) {
 		sc->sc_state &= ~UHID_ASLP;
 		DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
-		wakeup(&sc->sc_q);
+		cv_broadcast(&sc->sc_cv);
 	}
 	selnotify(&sc->sc_rsel, 0, 0);
 	if (sc->sc_async != NULL) {
 		DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async));
 		softint_schedule(sc->sc_sih);
 	}
+	mutex_exit(&sc->sc_lock);
 }
 
 void
@@ -272,8 +288,7 @@ uhid_softintr(void *cookie)
 }
 
 int
-uhidopen(dev_t dev, int flag, int mode,
-    struct lwp *l)
+uhidopen(dev_t dev, int flag, int mode, struct lwp *l)
 {
 	struct uhid_softc *sc;
 	int error;
@@ -287,16 +302,23 @@ uhidopen(dev_t dev, int flag, int mode,
 	if (sc->sc_dying)
 		return (ENXIO);
 
+	mutex_enter(&sc->sc_access_lock);
 	error = uhidev_open(&sc->sc_hdev);
-	if (error)
+	if (error) {
+		mutex_exit(&sc->sc_access_lock);
 		return (error);
+	}
+	mutex_exit(&sc->sc_access_lock);
 
 	if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
+		mutex_enter(&sc->sc_access_lock);
 		uhidev_close(&sc->sc_hdev);
+		mutex_exit(&sc->sc_access_lock);
 		return (ENOMEM);
 	}
 	sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
 	sc->sc_state &= ~UHID_IMMED;
+
 	mutex_enter(proc_lock);
 	sc->sc_async = NULL;
 	mutex_exit(proc_lock);
@@ -305,8 +327,7 @@ uhidopen(dev_t dev, int flag, int mode,
 }
 
 int
-uhidclose(dev_t dev, int flag, int mode,
-    struct lwp *l)
+uhidclose(dev_t dev, int flag, int mode, struct lwp *l)
 {
 	struct uhid_softc *sc;
 
@@ -316,10 +337,14 @@ uhidclose(dev_t dev, int flag, int mode,
 
 	clfree(&sc->sc_q);
 	free(sc->sc_obuf, M_USBDEV);
+
 	mutex_enter(proc_lock);
 	sc->sc_async = NULL;
 	mutex_exit(proc_lock);
+
+	mutex_enter(&sc->sc_access_lock);
 	uhidev_close(&sc->sc_hdev);
+	mutex_exit(&sc->sc_access_lock);
 
 	return (0);
 }
@@ -327,7 +352,6 @@ uhidclose(dev_t dev, int flag, int mode,
 int
 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
 {
-	int s;
 	int error = 0;
 	int extra;
 	size_t length;
@@ -345,15 +369,15 @@ uhid_do_read(struct uhid_softc *sc, stru
 		return (uiomove(buffer+extra, sc->sc_isize, uio));
 	}
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	while (sc->sc_q.c_cc == 0) {
 		if (flag & IO_NDELAY) {
-			splx(s);
+			mutex_exit(&sc->sc_lock);
 			return (EWOULDBLOCK);
 		}
 		sc->sc_state |= UHID_ASLP;
 		DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
-		error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0);
+		error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
 		DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
 		if (sc->sc_dying)
 			error = EIO;
@@ -362,7 +386,7 @@ uhid_do_read(struct uhid_softc *sc, stru
 			break;
 		}
 	}
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	/* Transfer as many chunks as possible. */
 	while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
@@ -390,10 +414,19 @@ uhidread(dev_t dev, struct uio *uio, int
 
 	sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
 
+	mutex_enter(&sc->sc_lock);
 	sc->sc_refcnt++;
+	mutex_exit(&sc->sc_lock);
+
+	mutex_enter(&sc->sc_access_lock);
 	error = uhid_do_read(sc, uio, flag);
+	mutex_exit(&sc->sc_access_lock);
+
+	mutex_enter(&sc->sc_lock);
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeup(sc->sc_hdev.sc_dev);
+		usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv);
+	mutex_exit(&sc->sc_lock);
+
 	return (error);
 }
 
@@ -432,10 +465,18 @@ uhidwrite(dev_t dev, struct uio *uio, in
 
 	sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
 
+	mutex_enter(&sc->sc_lock);
 	sc->sc_refcnt++;
+	mutex_exit(&sc->sc_lock);
+
+	mutex_enter(&sc->sc_access_lock);
 	error = uhid_do_write(sc, uio, flag);
+	mutex_exit(&sc->sc_access_lock);
+
+	mutex_enter(&sc->sc_lock);
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeup(sc->sc_hdev.sc_dev);
+		usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv);
+	mutex_exit(&sc->sc_lock);
 	return (error);
 }
 
@@ -605,11 +646,25 @@ uhidioctl(dev_t dev, u_long cmd, void *a
 	int error;
 
 	sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
+	if (sc == NULL)
+		return ENXIO;
+
+	if (sc->sc_dying)
+		return EIO;
 
+	mutex_enter(&sc->sc_lock);
 	sc->sc_refcnt++;
+	mutex_exit(&sc->sc_lock);
+
+	mutex_enter(&sc->sc_access_lock);
 	error = uhid_do_ioctl(sc, cmd, addr, flag, l);
+	mutex_exit(&sc->sc_access_lock);
+
+	mutex_enter(&sc->sc_lock);
 	if (--sc->sc_refcnt < 0)
-		usb_detach_wakeup(sc->sc_hdev.sc_dev);
+		usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv);
+	mutex_exit(&sc->sc_lock);
+
 	return (error);
 }
 
@@ -618,14 +673,15 @@ uhidpoll(dev_t dev, int events, struct l
 {
 	struct uhid_softc *sc;
 	int revents = 0;
-	int s;
 
 	sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
+	if (sc == NULL)
+		return ENXIO;
 
 	if (sc->sc_dying)
-		return (POLLHUP);
+		return EIO;
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	if (events & (POLLOUT | POLLWRNORM))
 		revents |= events & (POLLOUT | POLLWRNORM);
 	if (events & (POLLIN | POLLRDNORM)) {
@@ -634,8 +690,8 @@ uhidpoll(dev_t dev, int events, struct l
 		else
 			selrecord(l, &sc->sc_rsel);
 	}
+	mutex_exit(&sc->sc_lock);
 
-	splx(s);
 	return (revents);
 }
 
@@ -643,11 +699,10 @@ static void
 filt_uhidrdetach(struct knote *kn)
 {
 	struct uhid_softc *sc = kn->kn_hook;
-	int s;
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 }
 
 static int
@@ -670,7 +725,6 @@ uhidkqfilter(dev_t dev, struct knote *kn
 {
 	struct uhid_softc *sc;
 	struct klist *klist;
-	int s;
 
 	sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
 
@@ -694,9 +748,9 @@ uhidkqfilter(dev_t dev, struct knote *kn
 
 	kn->kn_hook = sc;
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	return (0);
 }

Reply via email to