Page MenuHomeFreeBSD

D20459.diff
No OneTemporary

D20459.diff

Index: head/share/man/man4/gpio.4
===================================================================
--- head/share/man/man4/gpio.4
+++ head/share/man/man4/gpio.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 26, 2019
+.Dd June 27, 2019
.Dt GPIO 4
.Os
.Sh NAME
@@ -109,7 +109,7 @@
attached to
.Nm
pins:
-.Bl -tag -width ".Va hint.driver.unit.pins"
+.Bl -tag -width ".Va hint.driver.unit.pin_list"
.It Va hint.driver.unit.at
The
.Nm gpiobus
@@ -125,6 +125,20 @@
.Nm gpiobus
that are connected to the device.
The pins will be allocated to the specified driver instance.
+Only pins with numbers from 0 to 31 can be specified using this hint.
+.It Va hint.driver.unit.pin_list
+This is a list of pin numbers of pins on the
+.Nm gpiobus
+that are connected to the device.
+The pins will be allocated to the specified driver instance.
+This is a more user friendly alternative to the
+.Ar pins
+hint.
+Additionally, this hint allows specifying pin numbers greater than 31.
+The numbers can be decimal or hexadecimal with 0x prefix.
+Any non-digit character can be used as a separator.
+For example, it can be a comma, a slash or a space.
+The separator can be followed by any number of space characters.
.El
.Pp
The following
Index: head/sys/dev/gpio/gpiobus.c
===================================================================
--- head/sys/dev/gpio/gpiobus.c
+++ head/sys/dev/gpio/gpiobus.c
@@ -255,13 +255,6 @@
M_NOWAIT | M_ZERO);
if (devi->pins == NULL)
return (ENOMEM);
- devi->flags = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF,
- M_NOWAIT | M_ZERO);
- if (devi->flags == NULL) {
- free(devi->pins, M_DEVBUF);
- return (ENOMEM);
- }
-
return (0);
}
@@ -269,14 +262,11 @@
gpiobus_free_ivars(struct gpiobus_ivar *devi)
{
- if (devi->flags) {
- free(devi->flags, M_DEVBUF);
- devi->flags = NULL;
- }
if (devi->pins) {
free(devi->pins, M_DEVBUF);
devi->pins = NULL;
}
+ devi->npins = 0;
}
int
@@ -326,6 +316,34 @@
}
static int
+gpiobus_acquire_child_pins(device_t dev, device_t child)
+{
+ struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+ int i;
+
+ for (i = 0; i < devi->npins; i++) {
+ /* Reserve the GPIO pin. */
+ if (gpiobus_acquire_pin(dev, devi->pins[i]) != 0) {
+ device_printf(child, "cannot acquire pin %d\n",
+ devi->pins[i]);
+ while (--i >= 0) {
+ (void)gpiobus_release_pin(dev,
+ devi->pins[i]);
+ }
+ gpiobus_free_ivars(devi);
+ return (EBUSY);
+ }
+ }
+ for (i = 0; i < devi->npins; i++) {
+ /* Use the child name as pin name. */
+ GPIOBUS_PIN_SETNAME(dev, devi->pins[i],
+ device_get_nameunit(child));
+
+ }
+ return (0);
+}
+
+static int
gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
{
struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
@@ -349,21 +367,70 @@
for (i = 0; i < 32; i++) {
if ((mask & (1 << i)) == 0)
continue;
- /* Reserve the GPIO pin. */
- if (gpiobus_acquire_pin(sc->sc_busdev, i) != 0) {
- gpiobus_free_ivars(devi);
- return (EINVAL);
- }
devi->pins[npins++] = i;
- /* Use the child name as pin name. */
- GPIOBUS_PIN_SETNAME(sc->sc_busdev, i,
- device_get_nameunit(child));
}
+ if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0)
+ return (EINVAL);
return (0);
}
static int
+gpiobus_parse_pin_list(struct gpiobus_softc *sc, device_t child,
+ const char *pins)
+{
+ struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+ const char *p;
+ char *endp;
+ unsigned long pin;
+ int i, npins;
+
+ npins = 0;
+ p = pins;
+ for (;;) {
+ pin = strtoul(p, &endp, 0);
+ if (endp == p)
+ break;
+ npins++;
+ if (*endp == '\0')
+ break;
+ p = endp + 1;
+ }
+
+ if (*endp != '\0') {
+ device_printf(child, "garbage in the pin list: %s\n", endp);
+ return (EINVAL);
+ }
+ if (npins == 0) {
+ device_printf(child, "empty pin list\n");
+ return (EINVAL);
+ }
+
+ devi->npins = npins;
+ if (gpiobus_alloc_ivars(devi) != 0) {
+ device_printf(child, "cannot allocate device ivars\n");
+ return (EINVAL);
+ }
+
+ i = 0;
+ p = pins;
+ for (;;) {
+ pin = strtoul(p, &endp, 0);
+
+ devi->pins[i] = pin;
+
+ if (*endp == '\0')
+ break;
+ i++;
+ p = endp + 1;
+ }
+
+ if (gpiobus_acquire_child_pins(sc->sc_busdev, child) != 0)
+ return (EINVAL);
+ return (0);
+}
+
+static int
gpiobus_probe(device_t dev)
{
device_set_desc(dev, "GPIO bus");
@@ -539,16 +606,27 @@
struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
struct gpiobus_ivar *devi;
device_t child;
- int irq, pins;
+ const char *pins;
+ int irq, pinmask;
child = BUS_ADD_CHILD(bus, 0, dname, dunit);
devi = GPIOBUS_IVAR(child);
- resource_int_value(dname, dunit, "pins", &pins);
- if (gpiobus_parse_pins(sc, child, pins)) {
- resource_list_free(&devi->rl);
- free(devi, M_DEVBUF);
- device_delete_child(bus, child);
+ if (resource_int_value(dname, dunit, "pins", &pinmask) == 0) {
+ if (gpiobus_parse_pins(sc, child, pinmask)) {
+ resource_list_free(&devi->rl);
+ free(devi, M_DEVBUF);
+ device_delete_child(bus, child);
+ return;
+ }
}
+ else if (resource_string_value(dname, dunit, "pin_list", &pins) == 0) {
+ if (gpiobus_parse_pin_list(sc, child, pins)) {
+ resource_list_free(&devi->rl);
+ free(devi, M_DEVBUF);
+ device_delete_child(bus, child);
+ return;
+ }
+ }
if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0)
device_printf(bus,
@@ -574,6 +652,61 @@
return (0);
}
+static int
+gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct gpiobus_ivar *devi;
+
+ devi = GPIOBUS_IVAR(child);
+ switch (which) {
+ case GPIOBUS_IVAR_NPINS:
+ *result = devi->npins;
+ break;
+ case GPIOBUS_IVAR_PINS:
+ /* Children do not ever need to directly examine this. */
+ return (ENOTSUP);
+ default:
+ return (ENOENT);
+ }
+
+ return (0);
+}
+
+static int
+gpiobus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct gpiobus_ivar *devi;
+ const uint32_t *ptr;
+ int i;
+
+ devi = GPIOBUS_IVAR(child);
+ switch (which) {
+ case GPIOBUS_IVAR_NPINS:
+ /* GPIO ivars are set once. */
+ if (devi->npins != 0) {
+ return (EBUSY);
+ }
+ devi->npins = value;
+ if (gpiobus_alloc_ivars(devi) != 0) {
+ device_printf(child, "cannot allocate device ivars\n");
+ devi->npins = 0;
+ return (ENOMEM);
+ }
+ break;
+ case GPIOBUS_IVAR_PINS:
+ ptr = (const uint32_t *)value;
+ for (i = 0; i < devi->npins; i++)
+ devi->pins[i] = ptr[i];
+ if (gpiobus_acquire_child_pins(dev, child) != 0)
+ return (EBUSY);
+ break;
+ default:
+ return (ENOENT);
+ }
+
+ return (0);
+}
+
static struct resource *
gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid,
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
@@ -833,6 +966,8 @@
DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, gpiobus_child_location_str),
DEVMETHOD(bus_hinted_child, gpiobus_hinted_child),
+ DEVMETHOD(bus_read_ivar, gpiobus_read_ivar),
+ DEVMETHOD(bus_write_ivar, gpiobus_write_ivar),
/* GPIO protocol */
DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus),
Index: head/sys/dev/gpio/gpiobusvar.h
===================================================================
--- head/sys/dev/gpio/gpiobusvar.h
+++ head/sys/dev/gpio/gpiobusvar.h
@@ -107,9 +107,21 @@
{
struct resource_list rl; /* isr resource list */
uint32_t npins; /* pins total */
- uint32_t *flags; /* pins flags */
uint32_t *pins; /* pins map */
};
+
+enum gpiobus_ivars {
+ GPIOBUS_IVAR_NPINS = 10500,
+ GPIOBUS_IVAR_PINS,
+};
+
+#define GPIOBUS_ACCESSOR(var, ivar, type) \
+ __BUS_ACCESSOR(gpiobus, var, GPIOBUS, ivar, type)
+
+GPIOBUS_ACCESSOR(npins, NPINS, uint32_t)
+GPIOBUS_ACCESSOR(pins, PINS, const uint32_t *)
+
+#undef GPIOBUS_ACCESSOR
#ifdef FDT
struct ofw_gpiobus_devinfo {

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 17, 2:56 PM (17 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27695386
Default Alt Text
D20459.diff (7 KB)

Event Timeline