/*
* Copyright (c) 2007-2009 Hypertriton, Inc.
* 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 COPYRIGHT HOLDERS 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.
*/
/*
* Driver for emergency stop button.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ESTOPUNIT(x) minor(x)
int estop_match(struct device *, void *, void *);
void estop_attach(struct device *, struct device *, void *);
int estop_detach(struct device *, int);
int estop_activate(struct device *, enum devact);
void estop_abort_all(void);
struct cfattach estop_ca = {
sizeof(struct estop_softc),
estop_match,
estop_attach,
estop_detach,
estop_activate
};
struct cfdriver estop_cd = {
NULL, "estop", DV_DULL
};
int
estop_match(struct device *parent, void *match, void *aux)
{
struct cfdata *cf = match;
return (strcmp(cf->cf_driver->cd_name, "estop") == 0);
}
void
estop_attach(struct device *parent, struct device *self, void *aux)
{
struct estop_softc *sc = (struct estop_softc *)self;
struct gpio_attach_args *ga = aux;
/* Generic CNC device initialization. */
if (cnc_device_attach(sc, CNC_DEVICE_ESTOP) == -1)
return;
sc->sc_flags = sc->sc_cdev.cd_dev.dv_cfdata->cf_flags;
if (gpio_npins(ga->ga_mask) != ESTOP_NPINS) {
printf(": invalid pin mask\n");
return;
}
sc->sc_gpio = ga->ga_gpio;
sc->sc_map.pm_map = sc->__map;
if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
&sc->sc_map)) {
printf(": can't map pins\n");
return;
}
/* Map the input signal. */
CNC_MAP_INPUT(sc, ESTOP_PIN, "ESTOP");
sc->sc_open = 0;
sc->sc_queued = 0;
if (sc->sc_flags & ESTOP_DEBOUNCE) {
printf(" debounce");
}
printf("\n");
return;
fail:
gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
}
int
estop_detach(struct device *self, int flags)
{
return (0);
}
int
estop_activate(struct device *self, enum devact act)
{
return (0);
}
/* Return e-stop status. */
int
estop_get_state(struct estop_softc *sc)
{
return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, ESTOP_PIN));
}
/* Return e-stop status with software debounce. */
int
estop_debounce(struct estop_softc *sc)
{
int j;
cnc_utime_t delay, k;
delay = (cnc_utime_t)cnc_timings.hz/100; /* 10ms */
for (j = 0; j < 10; j++) {
if (!estop_get_state(sc)) {
break;
}
for (k = 0; k < delay; k++)
;;
}
if (j == 10) {
return (1);
}
return (0);
}
int
estopopen(dev_t dev, int flag, int mode, struct proc *p)
{
int unit = ESTOPUNIT(dev);
struct estop_softc *sc;
if (unit >= estop_cd.cd_ndevs)
return (ENXIO);
sc = estop_cd.cd_devs[unit];
if (sc == NULL) {
return (ENXIO);
}
if (sc->sc_open) {
return (EBUSY);
}
sc->sc_open = 1;
return (0);
}
int
estopclose(dev_t dev, int flag, int mode, struct proc *p)
{
int unit = ESTOPUNIT(dev);
struct estop_softc *sc = estop_cd.cd_devs[unit];
sc->sc_open = 0;
sc->sc_queued = 0;
return (0);
}
int
estopread(dev_t dev, struct uio *uio, int flag)
{
int unit = ESTOPUNIT(dev);
struct estop_softc *sc = estop_cd.cd_devs[unit];
struct cnc_input_event ev;
int s;
ev.type = CNC_EVENT_BUTTONDOWN;
ev.which = 0;
if (sc->sc_queued) {
sc->sc_queued = 0;
ev.data = 1;
} else {
s = splhigh();
ev.data = estop_get_state(sc);
splx(s);
}
return uiomove((caddr_t)&ev, sizeof(struct cnc_input_event), uio);
}
int
estopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
return (ENXIO);
}