From d752f0f69de80ecb93e4d64e8353218edbdbdccf Mon Sep 17 00:00:00 2001 From: Luiz Otavio O Souza Date: Sun, 8 Mar 2015 00:47:50 +0000 Subject: [PATCH] Add a new ioctl to allow the setting of GPIO pin names. When a gpiobus child is added, use its name to identify the mapped pin names. Make the respective changes to libgpio. Add a new '-n' flag to gpioctl(8) to set the pin name. Differential Revision: https://reviews.freebsd.org/D2002 Reviewed by: rpaulo Requested by: many --- lib/libgpio/gpio.3 | 10 ++++-- lib/libgpio/gpio.c | 16 ++++++++++ lib/libgpio/libgpio.h | 5 +++ sys/dev/gpio/gpiobus.c | 62 +++++++++++++++++++++++++++++++++----- sys/dev/gpio/gpiobus_if.m | 18 +++++++++++ sys/dev/gpio/gpiobusvar.h | 8 ++++- sys/dev/gpio/gpioc.c | 13 +++++++- sys/dev/gpio/ofw_gpiobus.c | 11 ++++++- sys/sys/gpio.h | 1 + usr.sbin/gpioctl/gpioctl.8 | 15 ++++++--- usr.sbin/gpioctl/gpioctl.c | 26 ++++++++++++++-- 11 files changed, 165 insertions(+), 20 deletions(-) diff --git a/lib/libgpio/gpio.3 b/lib/libgpio/gpio.3 index 12b2d1eeed1f..67c988083b42 100644 --- a/lib/libgpio/gpio.3 +++ b/lib/libgpio/gpio.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 17, 2014 +.Dd March 7, 2015 .Dt GPIO 3 .Os .Sh NAME @@ -45,7 +45,9 @@ .Ft int .Fn gpio_pin_list "gpio_handle_t handle, gpio_config_t **pcfgs" .Ft int -.Fn gpio_pin_config "gpio_handle_t handle, gpio_config *cfg" +.Fn gpio_pin_config "gpio_handle_t handle, gpio_config_t *cfg" +.Ft int +.Fn gpio_pin_set_name "gpio_handle_t handle, gpio_pin_t pin, char *name" .Ft int .Fn gpio_pin_set_flags "gpio_handle_t handle, gpio_config_t *cfg" .Ft gpio_value_t @@ -111,6 +113,10 @@ variable which is part of the structure. .Pp The function +.Fn gpio_pin_set_name +sets the name used to describe a pin. +.Pp +The function .Fn gpio_pin_set_flags configures a pin with the flags passed in by the .Ft gpio_config_t diff --git a/lib/libgpio/gpio.c b/lib/libgpio/gpio.c index 8eb68712057a..7ec0955b096b 100644 --- a/lib/libgpio/gpio.c +++ b/lib/libgpio/gpio.c @@ -118,6 +118,22 @@ gpio_pin_config(gpio_handle_t handle, gpio_config_t *cfg) return (0); } +int +gpio_pin_set_name(gpio_handle_t handle, gpio_pin_t pin, char *name) +{ + struct gpio_pin gppin; + + if (name == NULL) + return (-1); + bzero(&gppin, sizeof(gppin)); + gppin.gp_pin = pin; + strlcpy(gppin.gp_name, name, GPIOMAXNAME); + if (ioctl(handle, GPIOSETNAME, &gppin) < 0) + return (-1); + + return (0); +} + int gpio_pin_set_flags(gpio_handle_t handle, gpio_config_t *cfg) { diff --git a/lib/libgpio/libgpio.h b/lib/libgpio/libgpio.h index b7486ebc5472..a832234ca13e 100644 --- a/lib/libgpio/libgpio.h +++ b/lib/libgpio/libgpio.h @@ -70,6 +70,11 @@ int gpio_pin_list(gpio_handle_t, gpio_config_t **); * passed through the gpio_config_t structure. */ int gpio_pin_config(gpio_handle_t, gpio_config_t *); +/* + * Sets the GPIO pin name. The pin number and pin name to be set are passed + * as parameters. + */ +int gpio_pin_set_name(gpio_handle_t, gpio_pin_t, char *); /* * Sets the GPIO flags on a specific GPIO pin. The pin number and the flags * to be set are passed through the gpio_config_t structure. diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index 11a33d73e614..bf5632b42c80 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -185,9 +185,9 @@ gpiobus_init_softc(device_t dev) /* Pins = GPIO_PIN_MAX() + 1 */ sc->sc_npins++; - sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF, + sc->sc_pins = malloc(sizeof(*sc->sc_pins) * sc->sc_npins, M_DEVBUF, M_NOWAIT | M_ZERO); - if (sc->sc_pins_mapped == NULL) + if (sc->sc_pins == NULL) return (ENOMEM); /* Initialize the bus lock. */ @@ -242,11 +242,11 @@ gpiobus_map_pin(device_t bus, uint32_t pin) return (-1); } /* Mark pin as mapped and give warning if it's already mapped. */ - if (sc->sc_pins_mapped[pin]) { + if (sc->sc_pins[pin].mapped) { device_printf(bus, "warning: pin %d is already mapped\n", pin); return (-1); } - sc->sc_pins_mapped[pin] = 1; + sc->sc_pins[pin].mapped = 1; return (0); } @@ -281,6 +281,9 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) return (EINVAL); } devi->pins[npins++] = i; + /* Use the child name as pin name. */ + GPIOBUS_PIN_SETNAME(sc->sc_busdev, i, + device_get_nameunit(child)); } return (0); @@ -340,10 +343,14 @@ gpiobus_detach(device_t dev) gpiobus_free_ivars(devi); } free(devlist, M_TEMP); - - if (sc->sc_pins_mapped) { - free(sc->sc_pins_mapped, M_DEVBUF); - sc->sc_pins_mapped = NULL; + if (sc->sc_pins) { + for (i = 0; i < sc->sc_npins; i++) { + if (sc->sc_pins[i].name != NULL) + free(sc->sc_pins[i].name, M_DEVBUF); + sc->sc_pins[i].name = NULL; + } + free(sc->sc_pins, M_DEVBUF); + sc->sc_pins = NULL; } return (0); @@ -664,6 +671,43 @@ gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin) return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]); } +static int +gpiobus_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct gpiobus_softc *sc; + + sc = GPIOBUS_SOFTC(dev); + if (pin > sc->sc_npins) + return (EINVAL); + /* Did we have a name for this pin ? */ + if (sc->sc_pins[pin].name != NULL) { + memcpy(name, sc->sc_pins[pin].name, GPIOMAXNAME); + return (0); + } + + /* Return the default pin name. */ + return (GPIO_PIN_GETNAME(device_get_parent(dev), pin, name)); +} + +static int +gpiobus_pin_setname(device_t dev, uint32_t pin, const char *name) +{ + struct gpiobus_softc *sc; + + sc = GPIOBUS_SOFTC(dev); + if (pin > sc->sc_npins) + return (EINVAL); + if (name == NULL) + return (EINVAL); + /* Save the pin name. */ + if (sc->sc_pins[pin].name == NULL) + sc->sc_pins[pin].name = malloc(GPIOMAXNAME, M_DEVBUF, + M_WAITOK | M_ZERO); + strlcpy(sc->sc_pins[pin].name, name, GPIOMAXNAME); + + return (0); +} + static device_method_t gpiobus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, gpiobus_probe), @@ -699,6 +743,8 @@ static device_method_t gpiobus_methods[] = { DEVMETHOD(gpiobus_pin_get, gpiobus_pin_get), DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set), DEVMETHOD(gpiobus_pin_toggle, gpiobus_pin_toggle), + DEVMETHOD(gpiobus_pin_getname, gpiobus_pin_getname), + DEVMETHOD(gpiobus_pin_setname, gpiobus_pin_setname), DEVMETHOD_END }; diff --git a/sys/dev/gpio/gpiobus_if.m b/sys/dev/gpio/gpiobus_if.m index 242502005428..ee926d5b96f0 100644 --- a/sys/dev/gpio/gpiobus_if.m +++ b/sys/dev/gpio/gpiobus_if.m @@ -106,3 +106,21 @@ METHOD int pin_setflags { uint32_t pin_num; uint32_t flags; }; + +# +# Get the pin name +# +METHOD int pin_getname { + device_t dev; + uint32_t pin_num; + char *name; +}; + +# +# Set the pin name +# +METHOD int pin_setname { + device_t dev; + uint32_t pin_num; + const char *name; +}; diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h index 315709a448ae..6a614cf8a6af 100644 --- a/sys/dev/gpio/gpiobusvar.h +++ b/sys/dev/gpio/gpiobusvar.h @@ -60,6 +60,12 @@ #define GPIOBUS_WAIT 1 #define GPIOBUS_DONTWAIT 2 +struct gpiobus_pin_data +{ + int mapped; /* pin is mapped/reserved. */ + char *name; /* pin name. */ +}; + struct gpiobus_softc { struct mtx sc_mtx; /* bus mutex */ @@ -68,7 +74,7 @@ struct gpiobus_softc device_t sc_owner; /* bus owner */ device_t sc_dev; /* driver device */ int sc_npins; /* total pins on bus */ - int *sc_pins_mapped; /* mark mapped pins */ + struct gpiobus_pin_data *sc_pins; /* pin data */ }; struct gpiobus_pin diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c index 2fad4dffb286..708a3c2043a5 100644 --- a/sys/dev/gpio/gpioc.c +++ b/sys/dev/gpio/gpioc.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include "gpio_if.h" +#include "gpiobus_if.h" #undef GPIOC_DEBUG #ifdef GPIOC_DEBUG @@ -112,12 +113,16 @@ static int gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, struct thread *td) { + device_t bus; int max_pin, res; struct gpioc_softc *sc = cdev->si_drv1; struct gpio_pin pin; struct gpio_req req; uint32_t caps; + bus = GPIO_GET_BUS(sc->sc_pdev); + if (bus == NULL) + return (EINVAL); switch (cmd) { case GPIOMAXPIN: max_pin = -1; @@ -133,7 +138,7 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, if (res) break; GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps); - GPIO_PIN_GETNAME(sc->sc_pdev, pin.gp_pin, pin.gp_name); + GPIOBUS_PIN_GETNAME(bus, pin.gp_pin, pin.gp_name); bcopy(&pin, arg, sizeof(pin)); break; case GPIOSETCONFIG: @@ -167,6 +172,12 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, req.gp_pin); res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin); break; + case GPIOSETNAME: + bcopy(arg, &pin, sizeof(pin)); + dprintf("set name on pin %d\n", pin.gp_pin); + res = GPIOBUS_PIN_SETNAME(bus, pin.gp_pin, + pin.gp_name); + break; default: return (ENOTTY); break; diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c index da72d4dfed20..368528de18f0 100644 --- a/sys/dev/gpio/ofw_gpiobus.c +++ b/sys/dev/gpio/ofw_gpiobus.c @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "gpiobus_if.h" + static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t, device_t, phandle_t); static void ofw_gpiobus_destroy_devinfo(device_t, struct ofw_gpiobus_devinfo *); @@ -49,6 +51,8 @@ device_t ofw_gpiobus_add_fdt_child(device_t bus, const char *drvname, phandle_t child) { device_t childdev; + int i; + struct gpiobus_ivar *devi; struct ofw_gpiobus_devinfo *dinfo; /* @@ -67,6 +71,11 @@ ofw_gpiobus_add_fdt_child(device_t bus, const char *drvname, phandle_t child) device_delete_child(bus, childdev); return (NULL); } + /* Use the child name as pin name. */ + devi = &dinfo->opd_dinfo; + for (i = 0; i < devi->npins; i++) + GPIOBUS_PIN_SETNAME(bus, devi->pins[i], + device_get_nameunit(childdev)); return (childdev); } @@ -159,7 +168,7 @@ ofw_gpiobus_destroy_devinfo(device_t bus, struct ofw_gpiobus_devinfo *dinfo) for (i = 0; i < devi->npins; i++) { if (devi->pins[i] > sc->sc_npins) continue; - sc->sc_pins_mapped[devi->pins[i]] = 0; + sc->sc_pins[devi->pins[i]].mapped = 0; } gpiobus_free_ivars(devi); resource_list_free(&dinfo->opd_dinfo.rl); diff --git a/sys/sys/gpio.h b/sys/sys/gpio.h index b1f3ba8f8890..c8724cbe6e89 100644 --- a/sys/sys/gpio.h +++ b/sys/sys/gpio.h @@ -93,5 +93,6 @@ struct gpio_req { #define GPIOGET _IOWR('G', 3, struct gpio_req) #define GPIOSET _IOW('G', 4, struct gpio_req) #define GPIOTOGGLE _IOWR('G', 5, struct gpio_req) +#define GPIOSETNAME _IOW('G', 6, struct gpio_pin) #endif /* __GPIO_H__ */ diff --git a/usr.sbin/gpioctl/gpioctl.8 b/usr.sbin/gpioctl/gpioctl.8 index a0bf6536f8f3..31fb36f8d06f 100644 --- a/usr.sbin/gpioctl/gpioctl.8 +++ b/usr.sbin/gpioctl/gpioctl.8 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 7, 2013 +.Dd March 7, 2015 .Dt GPIOCTL 1 .Os .Sh NAME @@ -35,20 +35,25 @@ .Nd GPIO control utility .Sh SYNOPSIS .Nm -.Cm -l .Op Fl f Ar ctldev +.Cm -l .Op Fl v .Nm -.Cm -t .Op Fl f Ar ctldev +.Cm -t .Ar pin .Nm -.Cm -c .Op Fl f Ar ctldev +.Cm -c .Ar pin .Ar flag .Op flag ... .Nm +.Op Fl f Ar ctldev +.Cm -n +.Ar pin +.Ar pin-name +.Nm .Op Cm -f Ar ctldev .Ar pin .Ar [0|1] @@ -87,6 +92,8 @@ If not specified, defaults to .Pa /dev/gpioc0 .It Fl l list available pins +.It Fl n Ar pin Ar pin-name +set the name used to describe the pin .It Fl t Ar pin toggle value of provided pin number .It Fl v diff --git a/usr.sbin/gpioctl/gpioctl.c b/usr.sbin/gpioctl/gpioctl.c index 37f84fa16b90..38e53e7f2fee 100644 --- a/usr.sbin/gpioctl/gpioctl.c +++ b/usr.sbin/gpioctl/gpioctl.c @@ -68,6 +68,7 @@ usage(void) fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n"); fprintf(stderr, "\tgpioctl [-f ctldev] -t pin\n"); fprintf(stderr, "\tgpioctl [-f ctldev] -c pin flag ...\n"); + fprintf(stderr, "\tgpioctl [-f ctldev] -n pin pin-name\n"); fprintf(stderr, "\tgpioctl [-f ctldev] pin [0|1]\n"); exit(1); } @@ -182,11 +183,11 @@ main(int argc, char **argv) char *ctlfile = NULL; int pinn, pinv, ch; int flags, flag, ok; - int config, toggle, verbose, list; + int config, list, name, toggle, verbose; - config = toggle = verbose = list = pinn = 0; + config = toggle = verbose = list = name = pinn = 0; - while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) { + while ((ch = getopt(argc, argv, "c:f:ln:t:v")) != -1) { switch (ch) { case 'c': config = 1; @@ -200,6 +201,12 @@ main(int argc, char **argv) case 'l': list = 1; break; + case 'n': + name = 1; + pinn = str2int(optarg, &ok); + if (!ok) + fail("Invalid pin number: %s\n", optarg); + break; case 't': toggle = 1; pinn = str2int(optarg, &ok); @@ -225,6 +232,19 @@ main(int argc, char **argv) exit(1); } + /* Set the pin name. */ + if (name) { + if (argc == 0) { + usage(); + exit(1); + } + if (gpio_pin_set_name(handle, pinn, argv[0]) < 0) { + perror("gpio_pin_set_name"); + exit(1); + } + exit(0); + } + if (list) { dump_pins(handle, verbose); gpio_close(handle);