diff --git a/build.sh b/build.sh index 0b664807..bbb2f586 100755 --- a/build.sh +++ b/build.sh @@ -37,7 +37,7 @@ case "${ostype}" in # try to find out whether this is an Embedded Linux # platform (e.g. Raspberry Pi) machine=$(uname -m) - if expr "${machine}" : 'arm' >/dev/null + if expr "${machine}" : '^\(arm\|aarch\)' >/dev/null then extra_enable="${extra_enable} -D HAVE_LINUXGPIO=ON -D HAVE_LINUXSPI=ON" fi diff --git a/src/avrdude.1 b/src/avrdude.1 index 2cb606ec..a9b5b812 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1228,6 +1228,14 @@ specific. .Pp When not provided, driver/OS default value will be used. .El +.It Ar linuxspi +Extended parameter: +.Bl -tag -offset indent -width indent +.It Ar disable_no_cs +Ensures the programmer does not use the SPI_NO_CS bit for the SPI +driver. This parameter is useful for kernels that do not support +the CS line being managed outside the application. +.El .El .Sh FILES .Bl -tag -offset indent -width /dev/ppi0XXX diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index e1e73e3e..8644768c 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1121,6 +1121,16 @@ specific. When not provided, driver/OS default value will be used. @end table +@cindex @code{-x} linuxspi +@item linuxspi +Extended parameter: +@table @code +@item @samp{disable_no_cs} +Ensures the programmer does not use the SPI_NO_CS bit for the SPI +driver. This parameter is useful for kernels that do not support +the CS line being managed outside the application. +@end table + @end table @page diff --git a/src/linuxspi.c b/src/linuxspi.c index 512755e3..c7806081 100644 --- a/src/linuxspi.c +++ b/src/linuxspi.c @@ -62,6 +62,15 @@ #define LINUXSPI "linuxspi" +/* + * Private data for this programmer. + */ +struct pdata { + int disable_no_cs; +}; + +#define PDATA(pgm) ((struct pdata *)(pgm->cookie)) + static int fd_spidev, fd_gpiochip, fd_linehandle; /** @@ -77,21 +86,28 @@ static int linuxspi_spi_duplex(const PROGRAMMER *pgm, const unsigned char *tx, u .rx_buf = (unsigned long)rx, .len = len, .delay_usecs = 1, - .speed_hz = 1.0 / pgm->bitclock, // seconds to Hz + .speed_hz = 1.0 / pgm->bitclock, .bits_per_word = 8, }; + errno = 0; ret = ioctl(fd_spidev, SPI_IOC_MESSAGE(1), &tr); - if (ret != len) - avrdude_message(MSG_INFO, "\n%s: error: Unable to send SPI message\n", progname); + if (ret != len) { + avrdude_message(MSG_INFO, "\n%s: unable to send SPI message", progname); + if (errno) + avrdude_message(MSG_INFO, ". %s", strerror(errno)); + avrdude_message(MSG_INFO, "\n"); + } - return (ret == -1) ? -1 : 0; + return ret == -1? -1: 0; } static void linuxspi_setup(PROGRAMMER *pgm) { + pgm->cookie = cfg_malloc("linuxspi_setup()", sizeof(struct pdata)); } static void linuxspi_teardown(PROGRAMMER* pgm) { + free(pgm->cookie); } static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) { @@ -116,8 +132,8 @@ static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) { #endif if (ret == -1) { ret = -errno; - avrdude_message(MSG_INFO, "%s error: Unable to set GPIO line %d value\n", - progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE); + avrdude_message(MSG_INFO, "%s: unable to set GPIO line %d value. %s\n", + progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE, strerror(errno)); return ret; } @@ -126,8 +142,8 @@ static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) { static int linuxspi_open(PROGRAMMER *pgm, const char *pt) { const char *port_error = - "%s: error: Unknown port specification. " - "Please use the format /dev/spidev:/dev/gpiochip[:resetno]\n"; + "%s: error, unknown port specification; " + "please use the format /dev/spidev:/dev/gpiochip[:resetno]\n"; char port_default[] = "/dev/spidev0.0:/dev/gpiochip0"; char *spidev, *gpiochip, *reset_pin; char *port = cfg_strdup("linuxspi_open()", pt); @@ -158,20 +174,28 @@ static int linuxspi_open(PROGRAMMER *pgm, const char *pt) { strcpy(pgm->port, port); fd_spidev = open(pgm->port, O_RDWR); if (fd_spidev < 0) { - avrdude_message(MSG_INFO, "\n%s: error: Unable to open the spidev device %s", progname, pgm->port); + avrdude_message(MSG_INFO, "\n%s: unable to open the spidev device %s. %s", + progname, pgm->port, strerror(errno)); return -1; } - uint32_t mode = SPI_MODE_0 | SPI_NO_CS; + uint32_t mode = SPI_MODE_0; + if (!PDATA(pgm)->disable_no_cs) + mode |= SPI_NO_CS; + ret = ioctl(fd_spidev, SPI_IOC_WR_MODE32, &mode); if (ret == -1) { - avrdude_message(MSG_INFO, "%s: error: Unable to set SPI mode %0X on %s\n", - progname, mode, spidev); + int ioctl_errno = errno; + avrdude_message(MSG_INFO, "%s: unable to set SPI mode %02X on %s. %s\n", + progname, mode, spidev, strerror(errno)); + if(ioctl_errno == EINVAL && !PDATA(pgm)->disable_no_cs) + avrdude_message(MSG_INFO, "%s: try -x disable_no_cs\n", progname); goto close_spidev; } fd_gpiochip = open(gpiochip, 0); if (fd_gpiochip < 0) { - avrdude_message(MSG_INFO, "\n%s error: Unable to open the gpiochip %s", progname, gpiochip); + avrdude_message(MSG_INFO, "\n%s: unable to open the gpiochip %s. %s\n", + progname, gpiochip, strerror(errno)); ret = -1; goto close_spidev; } @@ -206,8 +230,8 @@ static int linuxspi_open(PROGRAMMER *pgm, const char *pt) { #endif if (ret == -1) { ret = -errno; - avrdude_message(MSG_INFO, "%s error: Unable to get GPIO line %d\n", - progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE); + avrdude_message(MSG_INFO, "%s: unable to get GPIO line %d. %s\n", + progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE, strerror(errno)); goto close_gpiochip; } @@ -216,16 +240,15 @@ static int linuxspi_open(PROGRAMMER *pgm, const char *pt) { goto close_out; if (pgm->baudrate != 0) { - avrdude_message(MSG_INFO, - "%s: obsolete use of -b option for bit clock; use -B \n", - progname); + avrdude_message(MSG_INFO, + "%s: obsolete use of -b option for bit clock; use -B \n", + progname); pgm->bitclock = 1.0 / pgm->baudrate; } if (pgm->bitclock == 0) { - avrdude_message(MSG_NOTICE, - "%s: defaulting bit clock to 200 kHz\n", - progname); - pgm->bitclock = 5E-6; // 200 kHz - 5 µs + avrdude_message(MSG_NOTICE, + "%s: defaulting bit clock to 200 kHz\n", progname); + pgm->bitclock = 5E-6; // 200 kHz - 5 µs } return 0; @@ -272,7 +295,7 @@ static int linuxspi_initialize(const PROGRAMMER *pgm, const AVRPART *p) { if (p->prog_modes & PM_TPI) { /* We do not support TPI. This is a dedicated SPI thing */ - avrdude_message(MSG_INFO, "%s: error: Programmer " LINUXSPI " does not support TPI\n", progname); + avrdude_message(MSG_INFO, "%s: error, programmer " LINUXSPI " does not support TPI\n", progname); return -1; } @@ -286,7 +309,7 @@ static int linuxspi_initialize(const PROGRAMMER *pgm, const AVRPART *p) { } while(tries++ < 65); if (ret) - avrdude_message(MSG_INFO, "%s: error: AVR device not responding\n", progname); + avrdude_message(MSG_INFO, "%s: error, AVR device not responding\n", progname); return ret; } @@ -300,7 +323,7 @@ static int linuxspi_program_enable(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char cmd[4], res[4]; if (!p->op[AVR_OP_PGM_ENABLE]) { - avrdude_message(MSG_INFO, "%s: error: program enable instruction not defined for part \"%s\"\n", progname, p->desc); + avrdude_message(MSG_INFO, "%s: error, program enable instruction not defined for part %s\n", progname, p->desc); return -1; } @@ -343,7 +366,7 @@ static int linuxspi_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char cmd[4], res[4]; if (!p->op[AVR_OP_CHIP_ERASE]) { - avrdude_message(MSG_INFO, "%s: error: chip erase instruction not defined for part \"%s\"\n", progname, p->desc); + avrdude_message(MSG_INFO, "%s: error, chip erase instruction not defined for part %s\n", progname, p->desc); return -1; } @@ -378,6 +401,27 @@ static int linuxspi_parseexitspecs(PROGRAMMER *pgm, const char *sp) { return 0; } +static int linuxspi_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { + LNODEID ln; + const char *extended_param; + int rc = 0; + + for (ln = lfirst(extparms); ln; ln = lnext(ln)) { + extended_param = ldata(ln); + + if (strcmp(extended_param, "disable_no_cs") == 0) { + PDATA(pgm)->disable_no_cs = 1; + continue; + } + + avrdude_message(MSG_INFO, "%s: linuxspi_parseextparams(): " + "invalid extended parameter '%s'\n", progname, extended_param); + rc = -1; + } + + return rc; +} + void linuxspi_initpgm(PROGRAMMER *pgm) { strcpy(pgm->type, LINUXSPI); @@ -400,6 +444,7 @@ void linuxspi_initpgm(PROGRAMMER *pgm) { pgm->setup = linuxspi_setup; pgm->teardown = linuxspi_teardown; pgm->parseexitspecs = linuxspi_parseexitspecs; + pgm->parseextparams = linuxspi_parseextparams; } const char linuxspi_desc[] = "SPI using Linux spidev driver";