--- sys/modules/Makefile 2016-08-15 21:46:27.000000000 -0700 +++ sys/modules/Makefile 2016-08-29 14:44:37.000000000 -0700 @@ -124,10 +124,11 @@ gem \ geom \ ${_glxiic} \ ${_glxsb} \ gpio \ + gpioshutdown \ hatm \ hifn \ hme \ ${_hpt27xx} \ ${_hptiop} \ --- /dev/null 2016-08-31 15:29:21.000000000 -0700 +++ sys/modules/gpioshutdown/Makefile 2016-08-29 14:46:26.000000000 -0700 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2012 Adrian Chadd, Xenion Pty Ltd +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer, +# without modification. +# 2. Redistributions in binary form must reproduce at minimum a disclaimer +# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any +# redistribution must be conditioned upon including a substantially +# similar Disclaimer requirement for further binary redistribution. +# +# NO WARRANTY +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY +# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, +# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGES. +# +# $FreeBSD: stable/11/sys/modules/gpio/gpioled/Makefile 300823 2016-05-27 04:34:42Z ian $ +# + +.PATH: ${.CURDIR}/../../dev/gpioshutdown + +KMOD= gpioshutdown +SRCS= gpioshutdown.c +SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h opt_platform.h ofw_bus_if.h + +CFLAGS+= -I. -I${.CURDIR}/../../dev/gpio/ + +.include + --- /dev/null 2016-08-31 16:25:43.000000000 -0700 +++ sys/dev/gpioshutdown/gpioshutdown.c 2016-08-31 16:18:21.000000000 -0700 @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +// gpioshutdown - written by Bob Frazier for S.F.T. Inc. http://mrp3.com/ +// contributed to the FreeBSD source as-is, to address +// bug report 211979 +// +// This module's purpose is to reset all non-reserved GPIO pins to a default +// (input) state on shutdown, right before halt. This way an external device +// that relies on GPIO pins being reset this way to identify a 'power off' +// condition can THEN detect a shutdown and power off the CPU, once it's safe. +// +// For more info, see bug 211979. +// +// This is primarily intended for the Raspberry Pi, but can be +// included by [or dynamically loaded into] any other kernel, as needed. + + +#include + +#include "opt_platform.h" + +// NOTE: these headers were copied from other driver sources, and some may not be needed +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "gpio_if.h" +#include "gpiobus_if.h" + +//#define USE_MOD_SHUTDOWN /* uncomment to use 'MOD_SHUTDOWN' in lieu of registered event handler */ + +//#define DEBUG_VERBOSE /* uncomment this define this to display verbose messages */ + +#ifdef DEBUG_VERBOSE +#define INTERNAL_DEBUG_PRINT(...) printf(__VA_ARGS__) +#else // !DEBUG_VERBOSE +#define INTERNAL_DEBUG_PRINT(...) +#endif // DEBUG_VERBOSE + + +static void internal_do_shutdown(device_t); + +// I added a handler proc so I can monitor certain things THAT way... +// however, I'm calling this from 'MOD_SHUTDOWN' for now +static int gpioshutdown_handler(module_t mod, int /*modeventtype_t*/ what, void *arg); + + +static void internal_do_shutdown(device_t dev) +{ +int max_pin, res, caps, pin, val; + + INTERNAL_DEBUG_PRINT("gpioshutdown - internal_do_shutdown\n"); + + // this is where I do all the work. for now, just assume all non-reserved + // GPIO pins are to be converted to inputs without pull up/down resistors, + // and that reserved pins will fail when I check the caps against the pin + + res = GPIO_PIN_MAX(dev, &max_pin); + + for(pin=0; pin < max_pin; pin++) + { + res = GPIO_PIN_GET(dev, pin, &val); + + if(!(val & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))) // pin is neither input nor output + { + INTERNAL_DEBUG_PRINT("skipping pin %d, neither input nor output\n", pin); + continue; + } + + // TODO: find out whether or not this is normally a reserved pin, such as having + // an 'ALT' designation in the broadcom implementation... + // (this is to correct the apparent bug caused by all of the I/O pin definitions + // being assigned to 'input' within the array, but not on the actual pin) + + res = GPIO_PIN_GETCAPS(dev, pin, &caps); + if (res == 0) + { + res = gpio_check_flags(caps, GPIO_PIN_INPUT); + + if (res == 0) // assume this excludes reserved GPIO pins + { + res = GPIO_PIN_SETFLAGS(dev, pin, GPIO_PIN_INPUT); + + if(val == GPIO_PIN_INPUT) + { + INTERNAL_DEBUG_PRINT("set flags on input pin %d, result=%d\n", pin, res); + } + else + { + INTERNAL_DEBUG_PRINT("set flags on output pin %d, result=%d\n", pin, res); + } + } + else + { + INTERNAL_DEBUG_PRINT("skipping pin %d, flags don't match caps (%xH)\n", pin, caps); + } + } + else + { + INTERNAL_DEBUG_PRINT("skipping pin %d, no caps\n", pin); + } + } + + INTERNAL_DEBUG_PRINT("gpioshutdown - internal_do_shutdown - done, max_pin=%d\n", max_pin); +} + + +#ifndef USE_MOD_SHUTDOWN +static eventhandler_tag evt_tag; // uncomment if I register an event handler instead +#endif // !USE_MOD_SHUTDOWN + +static int internal_shutdown_final(void *arg1) +{ +devclass_t dc; +device_t dev; +int nMaxUnit, nUnit; + + +// INTERNAL_DEBUG_PRINT("gpioshutdown - internal_shutdown_final\n"); + printf("gpioshutdown - I/O pin reset begin ..."); + + // scan for all gpio drivers, call internal_do_shutdown + + dc = devclass_find("gpio"); // we want all of the GPIO device class drivers + + if(dc) + { + nMaxUnit = devclass_get_maxunit(dc); + + for(nUnit=0; nUnit < nMaxUnit; nUnit++) + { + dev = devclass_get_device(dc, nUnit); + + if(dev) + { + INTERNAL_DEBUG_PRINT("gpioshutdown - internal_shutdown_final - temporary, doing unit %d\n", nUnit); + internal_do_shutdown(dev); // turn all of the IO pins into inputs + } + } + } + + // for now, always print this message so I know when it completes + printf(" complete\n"); + + return 0; +} + +static int gpioshutdown_handler(module_t mod, int what, void *arg) +{ +int err=0; + + switch(what) + { + case MOD_LOAD: + INTERNAL_DEBUG_PRINT("gpioshutdown_handler - module load\n"); + +#ifndef USE_MOD_SHUTDOWN + evt_tag = EVENTHANDLER_REGISTER(shutdown_final, internal_shutdown_final, 0, EVENTHANDLER_PRI_LAST); +#endif // !USE_MOD_SHUTDOWN + + break; + + case MOD_UNLOAD: +#ifndef USE_MOD_SHUTDOWN + EVENTHANDLER_DEREGISTER(shutdown_final, evt_tag); +#endif // !USE_MOD_SHUTDOWN + + INTERNAL_DEBUG_PRINT("gpioshutdown_handler - module unload\n"); + break; + + case MOD_SHUTDOWN: +#ifdef USE_MOD_SHUTDOWN + internal_shutdown_final(0); // do the GPIO shutdown from the 'MOD_SHUTDOWN' event +#endif // !USE_MOD_SHUTDOWN + + INTERNAL_DEBUG_PRINT("gpioshutdown_handler - module shutdown\n"); + break; + + case MOD_QUIESCE: + INTERNAL_DEBUG_PRINT("gpioshutdown_handler - module quiesce\n"); + break; + + default: + INTERNAL_DEBUG_PRINT("gpioshutdown_handler - module command %d (err)\n", what); + err = EINVAL; + break; + } + + return err; +} + +// this is a simple module, can be dynamically loaded + +DEV_MODULE(gpioshutdown, gpioshutdown_handler, 0); +MODULE_VERSION(gpioshutdown, 1); + +