diff --git a/AUTHORS b/AUTHORS index 1e51bfe..cc66ac2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -83,3 +83,4 @@ Jose Angel Caso Sanchez : Paolo Zebelloni : * Testing, debugging and research for the ROM BSL driver. + * BSL entry via GPIOs. diff --git a/Makefile b/Makefile index e1e9a46..68cb044 100644 --- a/Makefile +++ b/Makefile @@ -121,6 +121,7 @@ OBJ=\ util/powerbuf.o \ util/ctrlc.o \ util/chipinfo.o \ + util/gpio.o \ transport/cp210x.o \ transport/cdc_acm.o \ transport/ftdi.o \ diff --git a/drivers/bsllib.c b/drivers/bsllib.c index e313ec8..bdda343 100644 --- a/drivers/bsllib.c +++ b/drivers/bsllib.c @@ -18,6 +18,7 @@ #include "util/util.h" #include "bsllib.h" +#include "gpio.h" int bsllib_seq_do(sport_t fd, const char *seq) { @@ -58,6 +59,48 @@ int bsllib_seq_do(sport_t fd, const char *seq) return 0; } +int bsllib_seq_do_gpio(int rts, int dtr, const char *seq) +{ + gpio_export ( rts ); + gpio_set_dir ( rts, 1 ); + gpio_export ( dtr ); + gpio_set_dir ( dtr, 1 ); + + while (*seq && *seq != ':') { + const char c = *(seq++); + + // Logic is reversed! + switch (c) { + case 'R': + gpio_set_value ( rts, 0 ); + break; + + case 'r': + gpio_set_value ( rts, 1 ); + break; + + case 'D': + gpio_set_value ( dtr, 0 ); + break; + + case 'd': + gpio_set_value ( dtr, 1 ); + break; + + case ',': + delay_ms(50); + break; + } + } + + gpio_unexport ( rts ); + gpio_unexport ( dtr ); + + delay_ms(50); + + return 0; +} + const char *bsllib_seq_next(const char *seq) { while (*seq && *seq != ':') diff --git a/drivers/bsllib.h b/drivers/bsllib.h index a740aaf..9da3477 100644 --- a/drivers/bsllib.h +++ b/drivers/bsllib.h @@ -23,6 +23,7 @@ /* Execute the given sequence specifier with the modem control lines */ int bsllib_seq_do(sport_t sport, const char *seq); +int bsllib_seq_do_gpio(int rts, int dtr, const char *seq); /* Skip to the next part of a sequence specified */ const char *bsllib_seq_next(const char *seq); diff --git a/drivers/device.h b/drivers/device.h index 8eca9a6..f4f21e7 100644 --- a/drivers/device.h +++ b/drivers/device.h @@ -81,6 +81,9 @@ struct device_args { const char *requested_serial; const char *require_fwupdate; const char *bsl_entry_seq; + int bsl_gpio_used; + int bsl_gpio_rts; + int bsl_gpio_dtr; }; struct device_class { diff --git a/drivers/rom_bsl.c b/drivers/rom_bsl.c index 7a5b0b8..f7bf353 100644 --- a/drivers/rom_bsl.c +++ b/drivers/rom_bsl.c @@ -425,9 +425,19 @@ static device_t rom_bsl_open(const struct device_args *args) if (!dev->seq) dev->seq = "DR,r,R,r,d,R:DR,r"; - if (bsllib_seq_do(dev->fd, dev->seq) < 0) { - pr_error("rom_bsl: entry sequence failed"); - goto fail; + if ( args->bsl_gpio_used ) + { + if (bsllib_seq_do_gpio(args->bsl_gpio_rts, args->bsl_gpio_dtr, dev->seq) < 0) { + pr_error("rom_bsl: entry sequence failed"); + goto fail; + } + } + else + { + if (bsllib_seq_do(dev->fd, dev->seq) < 0) { + pr_error("rom_bsl: entry sequence failed"); + goto fail; + } } delay_ms(500); diff --git a/ui/main.c b/ui/main.c index 5bd8483..74554a1 100644 --- a/ui/main.c +++ b/ui/main.c @@ -148,6 +148,10 @@ static void usage(const char *progname) " Specify a BSL entry sequence. Each character specifies a modem\n" " control line transition (R: RTS on, r: RTS off, D: DTR on, \n" " d: DTR off).\n" +" --bsl-gpio-rts\n" +" On some host (say RaspberryPi) defines a GPIO pin# to be used as RTS\n" +" --bsl-gpio-dtr\n" +" On some host (say RaspberryPi) defines a GPIO pin# to be used as DTR\n" "\n" "Most drivers connect by default via USB, unless told otherwise via the\n" "-d option. By default, the first USB device found is opened.\n" @@ -247,6 +251,8 @@ static int parse_cmdline_args(int argc, char **argv, LOPT_REQUIRE_FW_UPDATE, LOPT_EMBEDDED, LOPT_BSL_ENTRY_SEQUENCE, + LOPT_BSL_GPIO_RTS, + LOPT_BSL_GPIO_DTR, }; static const struct option longopts[] = { @@ -262,6 +268,8 @@ static int parse_cmdline_args(int argc, char **argv, {"require-fw-update", 1, 0, LOPT_REQUIRE_FW_UPDATE}, {"embedded", 0, 0, LOPT_EMBEDDED}, {"bsl-entry-sequence", 1, 0, LOPT_BSL_ENTRY_SEQUENCE}, + {"bsl-gpio-rts", 1, 0, LOPT_BSL_GPIO_RTS}, + {"bsl-gpio-dtr", 1, 0, LOPT_BSL_GPIO_DTR}, {NULL, 0, 0, 0} }; @@ -289,6 +297,15 @@ static int parse_cmdline_args(int argc, char **argv, args->devarg.bsl_entry_seq = optarg; break; + case LOPT_BSL_GPIO_RTS: + args->devarg.bsl_gpio_used = 1; + args->devarg.bsl_gpio_rts = atoi ( optarg ); + break; + case LOPT_BSL_GPIO_DTR: + args->devarg.bsl_gpio_used = 1; + args->devarg.bsl_gpio_dtr = atoi ( optarg ); + break; + case LOPT_EMBEDDED: args->flags |= OPT_EMBEDDED; break; diff --git a/util/gpio.c b/util/gpio.c new file mode 100644 index 0000000..dd64e05 --- /dev/null +++ b/util/gpio.c @@ -0,0 +1,161 @@ +/* +* C Implementation: gpio +* +* Description: +* +* +* Author: Paolo Zebelloni , (C) 2014 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gpio.h" + +#define SYSFS_GPIO_DIR "/sys/class/gpio" +#define MAX_BUF 64 + +/** + * Before a Linux application can configure and use a GPIO, the GPIO first has to be exported to user. + * Each GPIO is not accessible from user space until the GPIO has been exported. + * You can only export a GPIO that isn't owned by a Linux kernel driver + * @param gpio GPIO number + * @return 0 if OK, -1 if fails + */ +int gpio_export ( unsigned int gpio ) +{ + int fd, len; + char buf[MAX_BUF]; + + fd = open ( SYSFS_GPIO_DIR "/export", O_WRONLY ); + if ( fd < 0 ) + { + perror ( "gpio/export" ); + return -1; + } + + len = snprintf ( buf, sizeof ( buf ), "%d", gpio ); + write ( fd, buf, len ); + close ( fd ); + + return 0; +} + +/** + * Complement of gpio_export(). + * @param gpio GPIO number + * @return 0 if OK, -1 if fails + */ +int gpio_unexport ( unsigned int gpio ) +{ + int fd, len; + char buf[MAX_BUF]; + + fd = open ( SYSFS_GPIO_DIR "/unexport", O_WRONLY ); + if ( fd < 0 ) + { + perror ( "gpio/unexport" ); + return -1; + } + + len = snprintf ( buf, sizeof ( buf ), "%d", gpio ); + write ( fd, buf, len ); + close ( fd ); + + return 0; +} + +/** + * To avoid hardware issues where two devices are driving the same signal, GPIOs default to be configured as an input. + * If you want to use the GPIO as an output, you need to change the configuration + * @param gpio GPIO number + * @param out_flag TRUE means OUT, FALSE means IN + * @return 0 if OK, -1 if fails + */ +int gpio_set_dir ( unsigned int gpio, unsigned int out_flag ) +{ + int fd; + char buf[MAX_BUF]; + + snprintf ( buf, MAX_BUF, SYSFS_GPIO_DIR "/gpio%d/direction", gpio ); + + fd = open ( buf, O_WRONLY ); + if ( fd < 0 ) + { + perror ( "gpio/direction" ); + return -1; + } + + if ( out_flag ) + write ( fd, "out", 4 ); + else + write ( fd, "in", 3 ); + + close ( fd ); + + return 0; +} + +/** + * Set HI or LO state to GPIO (output) pin. + * @param gpio GPIO number + * @param value TRUE means HI, FALSE means LO + * @return 0 if OK, -1 if fails + */ +int gpio_set_value ( unsigned int gpio, unsigned int value ) +{ + int fd; + char buf[MAX_BUF]; + + snprintf ( buf, MAX_BUF, SYSFS_GPIO_DIR "/gpio%d/value", gpio ); + + fd = open ( buf, O_WRONLY ); + if ( fd < 0 ) + { + perror ( "gpio/set-value" ); + return -1; + } + + write ( fd, value ? "1" : "0", 2 ); + + close ( fd ); + + return 0; +} + +/** + * Read state of GPIO (input) pin. + * @param gpio GPIO number + * @return 0 if LO, 1 if HI, -1 if fails + */ +int gpio_get_value ( unsigned int gpio ) +{ + int fd; + char buf[MAX_BUF]; + char ch; + + snprintf ( buf, MAX_BUF, SYSFS_GPIO_DIR "/gpio%d/value", gpio ); + + fd = open ( buf, O_RDONLY ); + if ( fd < 0 ) + { + perror ( "gpio/get-value" ); + return -1; + } + + read ( fd, &ch, 1 ); + + close ( fd ); + + return ( ch != '0' ); +} + diff --git a/util/gpio.h b/util/gpio.h new file mode 100644 index 0000000..c77cf73 --- /dev/null +++ b/util/gpio.h @@ -0,0 +1,22 @@ +// +// C++ Interface: gpio +// +// Description: +// +// +// Author: Paolo Zebelloni , (C) 2014 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef _GPIO_H +#define _GPIO_H + +int gpio_export ( unsigned int gpio ); +int gpio_unexport ( unsigned int gpio ); +int gpio_set_dir ( unsigned int gpio, unsigned int out_flag ); +int gpio_set_value ( unsigned int gpio, unsigned int value ); +int gpio_get_value ( unsigned int gpio ); + +#endif \ No newline at end of file