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:
parent
bf5d6cf0a9
commit
d752f0f69d
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user