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
This commit is contained in:
loos 2015-03-08 00:47:50 +00:00
parent 96f62b87a8
commit 04b6b93c32
11 changed files with 165 additions and 20 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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.

View File

@ -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
};

View File

@ -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;
};

View File

@ -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

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <dev/gpio/gpiobusvar.h>
#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;

View File

@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
#include <dev/gpio/gpiobusvar.h>
#include <dev/ofw/ofw_bus.h>
#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);

View File

@ -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__ */

View File

@ -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

View File

@ -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);