Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/avrdude/linuxgpio.c')
-rw-r--r--src/avrdude/linuxgpio.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/src/avrdude/linuxgpio.c b/src/avrdude/linuxgpio.c
new file mode 100644
index 000000000..b61631174
--- /dev/null
+++ b/src/avrdude/linuxgpio.c
@@ -0,0 +1,354 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Support for bitbanging GPIO pins using the /sys/class/gpio interface
+ *
+ * Copyright (C) 2013 Radoslav Kolev <radoslav@kolev.info>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#include "bitbang.h"
+
+#if HAVE_LINUXGPIO
+
+/*
+ * GPIO user space helpers
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+/*
+ * GPIO user space helpers
+ * The following functions are acting on an "unsigned gpio" argument, which corresponds to the
+ * gpio numbering scheme in the kernel (starting from 0).
+ * The higher level functions use "int pin" to specify the pins with an offset of 1:
+ * gpio = pin - 1;
+ */
+
+#define GPIO_DIR_IN 0
+#define GPIO_DIR_OUT 1
+
+static int linuxgpio_export(unsigned int gpio)
+{
+ int fd, len, r;
+ char buf[11];
+
+ fd = open("/sys/class/gpio/export", O_WRONLY);
+ if (fd < 0) {
+ perror("Can't open /sys/class/gpio/export");
+ return fd;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%u", gpio);
+ r = write(fd, buf, len);
+ close(fd);
+
+ return r;
+}
+
+static int linuxgpio_unexport(unsigned int gpio)
+{
+ int fd, len, r;
+ char buf[11];
+
+ fd = open("/sys/class/gpio/unexport", O_WRONLY);
+ if (fd < 0) {
+ perror("Can't open /sys/class/gpio/unexport");
+ return fd;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%u", gpio);
+ r = write(fd, buf, len);
+ close(fd);
+
+ return r;
+}
+
+static int linuxgpio_openfd(unsigned int gpio)
+{
+ char filepath[60];
+
+ snprintf(filepath, sizeof(filepath), "/sys/class/gpio/gpio%u/value", gpio);
+ return (open(filepath, O_RDWR));
+}
+
+static int linuxgpio_dir(unsigned int gpio, unsigned int dir)
+{
+ int fd, r;
+ char buf[60];
+
+ snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%u/direction", gpio);
+
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) {
+ perror("Can't open gpioX/direction");
+ return fd;
+ }
+
+ if (dir == GPIO_DIR_OUT)
+ r = write(fd, "out", 4);
+ else
+ r = write(fd, "in", 3);
+
+ close(fd);
+
+ return r;
+}
+
+static int linuxgpio_dir_out(unsigned int gpio)
+{
+ return linuxgpio_dir(gpio, GPIO_DIR_OUT);
+}
+
+static int linuxgpio_dir_in(unsigned int gpio)
+{
+ return linuxgpio_dir(gpio, GPIO_DIR_IN);
+}
+
+/*
+ * End of GPIO user space helpers
+ */
+
+#define N_GPIO (PIN_MAX + 1)
+
+/*
+* an array which holds open FDs to /sys/class/gpio/gpioXX/value for all needed pins
+*/
+static int linuxgpio_fds[N_GPIO] ;
+
+
+static int linuxgpio_setpin(PROGRAMMER * pgm, int pinfunc, int value)
+{
+ int r;
+ int pin = pgm->pinno[pinfunc]; // TODO
+
+ if (pin & PIN_INVERSE)
+ {
+ value = !value;
+ pin &= PIN_MASK;
+ }
+
+ if ( linuxgpio_fds[pin] < 0 )
+ return -1;
+
+ if (value)
+ r = write(linuxgpio_fds[pin], "1", 1);
+ else
+ r = write(linuxgpio_fds[pin], "0", 1);
+
+ if (r!=1) return -1;
+
+ if (pgm->ispdelay > 1)
+ bitbang_delay(pgm->ispdelay);
+
+ return 0;
+}
+
+static int linuxgpio_getpin(PROGRAMMER * pgm, int pinfunc)
+{
+ unsigned char invert=0;
+ char c;
+ int pin = pgm->pinno[pinfunc]; // TODO
+
+ if (pin & PIN_INVERSE)
+ {
+ invert = 1;
+ pin &= PIN_MASK;
+ }
+
+ if ( linuxgpio_fds[pin] < 0 )
+ return -1;
+
+ if (lseek(linuxgpio_fds[pin], 0, SEEK_SET)<0)
+ return -1;
+
+ if (read(linuxgpio_fds[pin], &c, 1)!=1)
+ return -1;
+
+ if (c=='0')
+ return 0+invert;
+ else if (c=='1')
+ return 1-invert;
+ else
+ return -1;
+
+}
+
+static int linuxgpio_highpulsepin(PROGRAMMER * pgm, int pinfunc)
+{
+ int pin = pgm->pinno[pinfunc]; // TODO
+
+ if ( linuxgpio_fds[pin & PIN_MASK] < 0 )
+ return -1;
+
+ linuxgpio_setpin(pgm, pinfunc, 1);
+ linuxgpio_setpin(pgm, pinfunc, 0);
+
+ return 0;
+}
+
+
+
+static void linuxgpio_display(PROGRAMMER *pgm, const char *p)
+{
+ avrdude_message(MSG_INFO, "%sPin assignment : /sys/class/gpio/gpio{n}\n",p);
+ pgm_display_generic_mask(pgm, p, SHOW_AVR_PINS);
+}
+
+static void linuxgpio_enable(PROGRAMMER *pgm)
+{
+ /* nothing */
+}
+
+static void linuxgpio_disable(PROGRAMMER *pgm)
+{
+ /* nothing */
+}
+
+static void linuxgpio_powerup(PROGRAMMER *pgm)
+{
+ /* nothing */
+}
+
+static void linuxgpio_powerdown(PROGRAMMER *pgm)
+{
+ /* nothing */
+}
+
+static int linuxgpio_open(PROGRAMMER *pgm, char *port)
+{
+ int r, i, pin;
+
+ if (bitbang_check_prerequisites(pgm) < 0)
+ return -1;
+
+
+ for (i=0; i<N_GPIO; i++)
+ linuxgpio_fds[i] = -1;
+ //Avrdude assumes that if a pin number is 0 it means not used/available
+ //this causes a problem because 0 is a valid GPIO number in Linux sysfs.
+ //To avoid annoying off by one pin numbering we assume SCK, MOSI, MISO
+ //and RESET pins are always defined in avrdude.conf, even as 0. If they're
+ //not programming will not work anyway. The drawbacks of this approach are
+ //that unwanted toggling of GPIO0 can occur and that other optional pins
+ //mostry LED status, can't be set to GPIO0. It can be fixed when a better
+ //solution exists.
+ for (i=0; i<N_PINS; i++) {
+ if ( (pgm->pinno[i] & PIN_MASK) != 0 ||
+ i == PIN_AVR_RESET ||
+ i == PIN_AVR_SCK ||
+ i == PIN_AVR_MOSI ||
+ i == PIN_AVR_MISO ) {
+ pin = pgm->pinno[i] & PIN_MASK;
+ if ((r=linuxgpio_export(pin)) < 0) {
+ avrdude_message(MSG_INFO, "Can't export GPIO %d, already exported/busy?: %s",
+ pin, strerror(errno));
+ return r;
+ }
+ if (i == PIN_AVR_MISO)
+ r=linuxgpio_dir_in(pin);
+ else
+ r=linuxgpio_dir_out(pin);
+
+ if (r < 0)
+ return r;
+
+ if ((linuxgpio_fds[pin]=linuxgpio_openfd(pin)) < 0)
+ return linuxgpio_fds[pin];
+ }
+ }
+
+ return(0);
+}
+
+static void linuxgpio_close(PROGRAMMER *pgm)
+{
+ int i, reset_pin;
+
+ reset_pin = pgm->pinno[PIN_AVR_RESET] & PIN_MASK;
+
+ //first configure all pins as input, except RESET
+ //this should avoid possible conflicts when AVR firmware starts
+ for (i=0; i<N_GPIO; i++) {
+ if (linuxgpio_fds[i] >= 0 && i != reset_pin) {
+ close(linuxgpio_fds[i]);
+ linuxgpio_dir_in(i);
+ linuxgpio_unexport(i);
+ }
+ }
+ //configure RESET as input, if there's external pull up it will go high
+ if (linuxgpio_fds[reset_pin] >= 0) {
+ close(linuxgpio_fds[reset_pin]);
+ linuxgpio_dir_in(reset_pin);
+ linuxgpio_unexport(reset_pin);
+ }
+}
+
+void linuxgpio_initpgm(PROGRAMMER *pgm)
+{
+ strcpy(pgm->type, "linuxgpio");
+
+ pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
+
+ pgm->rdy_led = bitbang_rdy_led;
+ pgm->err_led = bitbang_err_led;
+ pgm->pgm_led = bitbang_pgm_led;
+ pgm->vfy_led = bitbang_vfy_led;
+ pgm->initialize = bitbang_initialize;
+ pgm->display = linuxgpio_display;
+ pgm->enable = linuxgpio_enable;
+ pgm->disable = linuxgpio_disable;
+ pgm->powerup = linuxgpio_powerup;
+ pgm->powerdown = linuxgpio_powerdown;
+ pgm->program_enable = bitbang_program_enable;
+ pgm->chip_erase = bitbang_chip_erase;
+ pgm->cmd = bitbang_cmd;
+ pgm->open = linuxgpio_open;
+ pgm->close = linuxgpio_close;
+ pgm->setpin = linuxgpio_setpin;
+ pgm->getpin = linuxgpio_getpin;
+ pgm->highpulsepin = linuxgpio_highpulsepin;
+ pgm->read_byte = avr_read_byte_default;
+ pgm->write_byte = avr_write_byte_default;
+}
+
+const char linuxgpio_desc[] = "GPIO bitbanging using the Linux sysfs interface";
+
+#else /* !HAVE_LINUXGPIO */
+
+void linuxgpio_initpgm(PROGRAMMER * pgm)
+{
+ avrdude_message(MSG_INFO, "%s: Linux sysfs GPIO support not available in this configuration\n",
+ progname);
+}
+
+const char linuxgpio_desc[] = "GPIO bitbanging using the Linux sysfs interface (not available)";
+
+#endif /* HAVE_LINUXGPIO */