Module Name:    src
Committed By:   mbalmer
Date:           Fri Aug 21 12:53:42 UTC 2009

Modified Files:
        src/sys/dev/gpio: gpio.c gpiovar.h

Log Message:
Before trying to attach a child device driver, make sure the GPIO pins can
be mapped.  This prevents drivers from later failing in the attach routine.
Problem found by me, solution suggested by jmcneill.


To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/dev/gpio/gpio.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/gpio/gpiovar.h

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/gpio/gpio.c
diff -u src/sys/dev/gpio/gpio.c:1.26 src/sys/dev/gpio/gpio.c:1.27
--- src/sys/dev/gpio/gpio.c:1.26	Mon Aug 17 12:44:44 2009
+++ src/sys/dev/gpio/gpio.c	Fri Aug 21 12:53:42 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: gpio.c,v 1.26 2009/08/17 12:44:44 mbalmer Exp $ */
+/* $NetBSD: gpio.c,v 1.27 2009/08/21 12:53:42 mbalmer Exp $ */
 /*	$OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $	*/
 
 /*
@@ -19,7 +19,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.26 2009/08/17 12:44:44 mbalmer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.27 2009/08/21 12:53:42 mbalmer Exp $");
 
 /*
  * General Purpose Input/Output framework.
@@ -217,6 +217,30 @@
 	return UNCONF;
 }
 
+/* return 1 if all pins can be mapped, 0 if not */
+
+int
+gpio_pin_can_map(void *gpio, int offset, u_int32_t mask)
+{
+	struct gpio_softc *sc = gpio;
+	int npins, pin, i;
+
+	npins = gpio_npins(mask);
+	if (npins > sc->sc_npins)
+		return 0;
+
+	for (npins = 0, i = 0; i < 32; i++)
+		if (mask & (1 << i)) {
+			pin = offset + i;
+			if (pin < 0 || pin >= sc->sc_npins)
+				return 0;
+			if (sc->sc_pins[pin].pin_mapped)
+				return 0;
+		}
+
+	return 1;
+}
+
 int
 gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
 {
@@ -483,8 +507,13 @@
 		if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
 		    NULL, NULL, NULL, NULL))
 			return EPERM;
-                        
+
 		attach = (struct gpio_attach *)data;
+
+		/* do not try to attach if the pins are already mapped */
+		if (!gpio_pin_can_map(sc, attach->ga_offset, attach->ga_mask))
+			return EBUSY;
+
 		ga.ga_gpio = sc;
 		ga.ga_dvname = attach->ga_dvname;
 		ga.ga_offset = attach->ga_offset;

Index: src/sys/dev/gpio/gpiovar.h
diff -u src/sys/dev/gpio/gpiovar.h:1.9 src/sys/dev/gpio/gpiovar.h:1.10
--- src/sys/dev/gpio/gpiovar.h:1.9	Sat Jul 25 16:30:44 2009
+++ src/sys/dev/gpio/gpiovar.h	Fri Aug 21 12:53:42 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: gpiovar.h,v 1.9 2009/07/25 16:30:44 mbalmer Exp $ */
+/* $NetBSD: gpiovar.h,v 1.10 2009/08/21 12:53:42 mbalmer Exp $ */
 /*	$OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $	*/
 
 /*
@@ -88,6 +88,7 @@
 	LIST_ENTRY(gpio_name)	gp_next;
 };
 
+int	gpio_pin_can_map(void *, int, u_int32_t);
 int	gpio_pin_map(void *, int, u_int32_t, struct gpio_pinmap *);
 void	gpio_pin_unmap(void *, struct gpio_pinmap *);
 int	gpio_pin_read(void *, struct gpio_pinmap *, int);

Reply via email to