Patchwork Bus Pirate SPI support in flashrom

login
register
about
Submitter Carl-Daniel Hailfinger
Date 2009-11-21 04:53:11
Message ID <4B077237.80007@gmx.net>
Download mbox | patch
Permalink /patch/572/
State Superseded
Headers show

Comments

Carl-Daniel Hailfinger - 2009-11-21 04:53:11
Add Bus Pirate SPI support to flashrom.

Untested, should work.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Stefan Reinauer - 2009-11-21 08:47:02
On 11/21/09 5:53 AM, Carl-Daniel Hailfinger wrote:
> Add Bus Pirate SPI support to flashrom.
>
> Untested, should work.
>
> Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
>   

Acked-by: Stefan Reinauer <stepan@coresystems.de>
Sean Nelson - 2009-11-21 11:37:20
Patch with SPI mode init code.

On Sat, Nov 21, 2009 at 2:50 AM, Sean Nelson <audiohacked@gmail.com> wrote:
> Verbose log of flashrom-buspiratespi.
>
> On Fri, Nov 20, 2009 at 8:53 PM, Carl-Daniel Hailfinger
> <c-d.hailfinger.devel.2006@gmx.net> wrote:
>> Add Bus Pirate SPI support to flashrom.
>>
>> Untested, should work.
>>
>> Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
>>
>> Index: flashrom-buspiratespi/flash.h
>> ===================================================================
>> --- flashrom-buspiratespi/flash.h       (Revision 767)
>> +++ flashrom-buspiratespi/flash.h       (Arbeitskopie)
>> @@ -104,6 +104,9 @@
>>  #if SERPROG_SUPPORT == 1
>>        PROGRAMMER_SERPROG,
>>  #endif
>> +#if BUSPIRATE_SPI_SUPPORT == 1
>> +       PROGRAMMER_BUSPIRATESPI,
>> +#endif
>>        PROGRAMMER_INVALID /* This must always be the last entry. */
>>  };
>>
>> @@ -484,6 +487,12 @@
>>  int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
>>  int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
>>
>> +/* buspirate_spi.c */
>> +int buspirate_spi_init(void);
>> +int buspirate_spi_shutdown(void);
>> +int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
>> +int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
>> +
>>  /* flashrom.c */
>>  extern char *programmer_param;
>>  extern int verbose;
>> @@ -527,6 +536,9 @@
>>  #if DUMMY_SUPPORT == 1
>>        SPI_CONTROLLER_DUMMY,
>>  #endif
>> +#if BUSPIRATE_SPI_SUPPORT == 1
>> +       SPI_CONTROLLER_BUSPIRATE,
>> +#endif
>>        SPI_CONTROLLER_INVALID /* This must always be the last entry. */
>>  };
>>  extern const int spi_programmer_count;
>> @@ -736,5 +748,8 @@
>>  uint8_t serprog_chip_readb(const chipaddr addr);
>>  void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
>>  void serprog_delay(int delay);
>> +void sp_flush_incoming(void);
>> +int sp_openserport(char *dev, unsigned int baud);
>> +extern int sp_fd;
>>
>>  #endif                         /* !__FLASH_H__ */
>> Index: flashrom-buspiratespi/buspirate_spi.c
>> ===================================================================
>> --- flashrom-buspiratespi/buspirate_spi.c       (Revision 0)
>> +++ flashrom-buspiratespi/buspirate_spi.c       (Revision 0)
>> @@ -0,0 +1,317 @@
>> +/*
>> + * This file is part of the flashrom project.
>> + *
>> + * Copyright (C) 2009 Carl-Daniel Hailfinger
>> + *
>> + * 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; version 2 of the License.
>> + *
>> + * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
>> + */
>> +
>> +#include <stdio.h>
>> +#include <stdint.h>
>> +#include <string.h>
>> +#include <stdlib.h>
>> +#include <ctype.h>
>> +#include <fcntl.h>
>> +#include "flash.h"
>> +#include "spi.h"
>> +
>> +int buspirate_serialport_setup(char *dev)
>> +{
>> +       /* 115200bps, 8 databits, no parity, 1 stopbit */
>> +       sp_fd = sp_openserport(dev, 115200);
>> +       return 0;
>> +}
>> +
>> +int buspirate_serialport_shutdown(void)
>> +{
>> +       close(sp_fd);
>> +       return 0;
>> +}
>> +
>> +int serialport_write(unsigned char *buf, unsigned int writecnt)
>> +{
>> +       int tmp = 0;
>> +
>> +       while (tmp != writecnt) {
>> +               tmp = write(sp_fd, buf + tmp, writecnt - tmp);
>> +               if (tmp == -1)
>> +                       return 1;
>> +               if (!tmp)
>> +                       printf_debug("Empty write\n");
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +int serialport_read(unsigned char *buf, unsigned int readcnt)
>> +{
>> +       int tmp = 0;
>> +
>> +       while (tmp != readcnt) {
>> +               tmp = read(sp_fd, buf + tmp, readcnt - tmp);
>> +               if (tmp == -1)
>> +                       return 1;
>> +               if (!tmp)
>> +                       printf_debug("Empty read\n");
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +int buspirate_discard_read(void)
>> +{
>> +       int flags;
>> +
>> +       printf_debug("%s\n", __func__);
>> +       flags = fcntl(sp_fd, F_GETFL);
>> +       flags |= O_NONBLOCK;
>> +       fcntl(sp_fd, F_SETFL, flags);
>> +       sp_flush_incoming();
>> +       flags &= ~O_NONBLOCK;
>> +       fcntl(sp_fd, F_SETFL, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +#undef FAKE_COMMUNICATION
>> +int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
>> +{
>> +       int i, ret = 0;
>> +
>> +       printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt);
>> +       if (!writecnt && !readcnt) {
>> +               fprintf(stderr, "Zero length command!\n");
>> +               return 1;
>> +       }
>> +       printf_debug("Sending");
>> +       for (i = 0; i < writecnt; i++)
>> +               printf_debug(" 0x%02x", buf[i]);
>> +#ifdef FAKE_COMMUNICATION
>> +       /* Placate the caller for now. */
>> +       buf[0] = 0x01;
>> +       memset(buf + 1, 0xff, readcnt - 1);
>> +       ret = 0;
>> +#else
>> +       if (writecnt)
>> +               ret = serialport_write(buf, writecnt);
>> +       if (ret)
>> +               return ret;
>> +       if (readcnt)
>> +               ret = serialport_read(buf, readcnt);
>> +       if (ret)
>> +               return ret;
>> +#endif
>> +       printf_debug(", receiving");
>> +       for (i = 0; i < readcnt; i++)
>> +               printf_debug(" 0x%02x", buf[i]);
>> +       printf_debug("\n");
>> +       return 0;
>> +}
>> +
>> +int buspirate_spi_init(void)
>> +{
>> +       unsigned char buf[512];
>> +       int ret = 0;
>> +       int i;
>> +       char *devpos = NULL;
>> +       char *dev = NULL;
>> +       int devlen;
>> +
>> +       if (programmer_param && !strlen(programmer_param)) {
>> +               free(programmer_param);
>> +               programmer_param = NULL;
>> +       }
>> +       if (programmer_param) {
>> +               devpos = strstr(programmer_param, "dev=");
>> +               if (devpos) {
>> +                       devpos += 4;
>> +                       devlen = strcspn(devpos, ",:");
>> +                       if (devlen) {
>> +                               dev = malloc(devlen + 1);
>> +                               if (!dev) {
>> +                                       fprintf(stderr, "Out of memory!\n");
>> +                                       exit(1);
>> +                               }
>> +                               strncpy(dev, devpos, devlen);
>> +                               dev[devlen] = '\0';
>> +                       }
>> +               }
>> +               free(programmer_param);
>> +               programmer_param = NULL;
>> +       }
>> +       if (!dev) {
>> +               fprintf(stderr, "No serial device given. Use flashrom -p "
>> +                       "buspiratespi:dev=/dev/ttyUSB0\n");
>> +               return 1;
>> +       }
>> +
>> +       ret = buspirate_serialport_setup(dev);
>> +       if (ret)
>> +               return ret;
>> +
>> +       /* This is the brute force version, but it should work. */
>> +       for (i = 0; i < 19; i++) {
>> +               /* Enter raw bitbang mode */
>> +               buf[0] = 0x00;
>> +               /* Send the command, don't read the response. */
>> +               ret = buspirate_sendrecv(buf, 1, 0);
>> +               if (ret)
>> +                       return ret;
>> +               /* Read any response and discard it. */
>> +               ret = buspirate_discard_read();
>> +               if (ret)
>> +                       return ret;
>> +       }
>> +       /* Enter raw bitbang mode */
>> +       buf[0] = 0x00;
>> +       ret = buspirate_sendrecv(buf, 1, 5);
>> +       if (ret)
>> +               return ret;
>> +       if (memcmp(buf, "BBIO", 4)) {
>> +               fprintf(stderr, "Entering raw bitbang mode failed!\n");
>> +               return 1;
>> +       }
>> +       printf_debug("Raw bitbang mode version %c\n", buf[4]);
>> +       if (buf[4] != '1') {
>> +               fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
>> +                       buf[4]);
>> +               return 1;
>> +       }
>> +       /* Enter raw SPI mode */
>> +       buf[0] = 0x01;
>> +       ret = buspirate_sendrecv(buf, 1, 4);
>> +       if (memcmp(buf, "SPI", 3)) {
>> +               fprintf(stderr, "Entering raw SPI mode failed!\n");
>> +               return 1;
>> +       }
>> +       printf_debug("Raw SPI mode version %c\n", buf[3]);
>> +       if (buf[3] != '1') {
>> +               fprintf(stderr, "Can't handle raw SPI mode version %c!\n",
>> +                       buf[3]);
>> +               return 1;
>> +       }
>> +
>> +       /* Initial setup: Enable power, */
>> +       /* De-assert CS# */
>> +       buf[0] = 0x03;
>> +       ret = buspirate_sendrecv(buf, 1, 1);
>> +       if (ret)
>> +               return 1;
>> +       if (buf[0] != 0x01) {
>> +               fprintf(stderr, "Protocol error!\n");
>> +               return 1;
>> +       }
>> +
>> +       buses_supported = CHIP_BUSTYPE_SPI;
>> +       spi_controller = SPI_CONTROLLER_BUSPIRATE;
>> +
>> +       return 0;
>> +}
>> +
>> +int buspirate_spi_shutdown(void)
>> +{
>> +       unsigned char buf[5];
>> +       int ret = 0;
>> +
>> +       /* Exit raw SPI mode (enter raw bitbang mode) */
>> +       buf[0] = 0x00;
>> +       ret = buspirate_sendrecv(buf, 1, 5);
>> +       if (ret)
>> +               return ret;
>> +       if (memcmp(buf, "BBIO", 4)) {
>> +               fprintf(stderr, "Entering raw bitbang mode failed!\n");
>> +               return 1;
>> +       }
>> +       printf_debug("Raw bitbang mode version %c\n", buf[4]);
>> +       if (buf[4] != '1') {
>> +               fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
>> +                       buf[4]);
>> +               return 1;
>> +       }
>> +       /* Reset Bus Pirate (return to user terminal) */
>> +       buf[0] = 0x0f;
>> +       ret = buspirate_sendrecv(buf, 1, 0);
>> +       if (ret)
>> +               return ret;
>> +
>> +       /* Shut down serial port communication */
>> +       ret = buspirate_serialport_shutdown();
>> +       if (ret)
>> +               return ret;
>> +       printf_debug("Bus Pirate shutdown completed.\n");
>> +
>> +       return 0;
>> +}
>> +
>> +int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
>> +               const unsigned char *writearr, unsigned char *readarr)
>> +{
>> +       static unsigned char *buf = NULL;
>> +       int i = 0, ret = 0;
>> +
>> +       if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
>> +               return SPI_INVALID_LENGTH;
>> +
>> +       /* +2 is pretty arbitrary. */
>> +       buf = realloc(buf, writecnt + readcnt + 2);
>> +       if (!buf) {
>> +               fprintf(stderr, "Out of memory!\n");
>> +               exit(1); // -1
>> +       }
>> +
>> +       /* Assert CS# */
>> +       buf[i++] = 0x02;
>> +       ret = buspirate_sendrecv(buf, 1, 1);
>> +       if (ret)
>> +               return SPI_GENERIC_ERROR;
>> +       if (buf[0] != 0x01) {
>> +               fprintf(stderr, "Protocol error!\n");
>> +               return SPI_GENERIC_ERROR;
>> +       }
>> +
>> +       i = 0;
>> +       buf[i++] = 0x10 | (writecnt + readcnt - 1);
>> +       memcpy(buf + i, writearr, writecnt);
>> +       i += writecnt;
>> +       memset(buf + i, 0, readcnt);
>> +       ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt);
>> +       if (ret)
>> +               return SPI_GENERIC_ERROR;
>> +       if (buf[0] != 0x01) {
>> +               fprintf(stderr, "Protocol error!\n");
>> +               return SPI_GENERIC_ERROR;
>> +       }
>> +       memcpy(readarr, buf + i, readcnt);
>> +
>> +       i = 0;
>> +       /* De-assert CS# */
>> +       buf[i++] = 0x03;
>> +       ret = buspirate_sendrecv(buf, 1, 1);
>> +       if (ret)
>> +               return SPI_GENERIC_ERROR;
>> +       if (buf[0] != 0x01) {
>> +               fprintf(stderr, "Protocol error!\n");
>> +               return SPI_GENERIC_ERROR;
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
>> +{
>> +       /* Maximum read length is 12 bytes, use 8 for now. */
>> +       return spi_read_chunked(flash, buf, start, len, 8);
>> +}
>> +
>> +/* We could do 12-byte writes, but for now we use the generic 1-byte code. */
>> Index: flashrom-buspiratespi/serprog.c
>> ===================================================================
>> --- flashrom-buspiratespi/serprog.c     (Revision 767)
>> +++ flashrom-buspiratespi/serprog.c     (Arbeitskopie)
>> @@ -61,7 +61,7 @@
>>  #define S_CMD_Q_RDNMAXLEN      0x11    /* Query read-n maximum length                  */
>>  #define S_CMD_S_BUSTYPE                0x12    /* Set used bustype(s).                         */
>>
>> -static int sp_fd;
>> +int sp_fd;
>>
>>  static uint16_t sp_device_serbuf_size = 16;
>>  static uint16_t sp_device_opbuf_size = 300;
>> @@ -185,7 +185,7 @@
>>        {0, 0}                  /* Terminator */
>>  };
>>
>> -static int sp_openserport(char *dev, unsigned int baud)
>> +int sp_openserport(char *dev, unsigned int baud)
>>  {
>>        struct termios options;
>>        int fd, i;
>> @@ -208,20 +208,16 @@
>>                        break;
>>                }
>>        }
>> -       options.c_cflag &= ~PARENB;
>> -       options.c_cflag &= ~CSTOPB;
>> -       options.c_cflag &= ~CSIZE;
>> -       options.c_cflag |= CS8;
>> -       options.c_cflag &= ~CRTSCTS;
>> +       options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
>> +       options.c_cflag |= (CS8 | CLOCAL | CREAD);
>>        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
>>        options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
>>        options.c_oflag &= ~OPOST;
>> -       options.c_cflag |= (CLOCAL | CREAD);
>>        tcsetattr(fd, TCSANOW, &options);
>>        return fd;
>>  }
>>
>> -static void sp_flush_incoming(void)
>> +void sp_flush_incoming(void)
>>  {
>>        int i;
>>        for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */
>> Index: flashrom-buspiratespi/spi.c
>> ===================================================================
>> --- flashrom-buspiratespi/spi.c (Revision 767)
>> +++ flashrom-buspiratespi/spi.c (Arbeitskopie)
>> @@ -100,6 +100,15 @@
>>        },
>>  #endif
>>
>> +#if BUSPIRATE_SPI_SUPPORT == 1
>> +       { /* SPI_CONTROLLER_BUSPIRATE */
>> +               .command = buspirate_spi_send_command,
>> +               .multicommand = default_spi_send_multicommand,
>> +               .read = buspirate_spi_read,
>> +               .write_256 = spi_chip_write_1,
>> +       },
>> +#endif
>> +
>>        {}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
>>  };
>>
>> Index: flashrom-buspiratespi/Makefile
>> ===================================================================
>> --- flashrom-buspiratespi/Makefile      (Revision 767)
>> +++ flashrom-buspiratespi/Makefile      (Arbeitskopie)
>> @@ -89,6 +89,9 @@
>>  # Always enable Dr. Kaiser for now.
>>  CONFIG_DRKAISER ?= yes
>>
>> +# Always enable Bus Pirate SPI for now.
>> +CONFIG_BUSPIRATESPI ?= yes
>> +
>>  # Disable wiki printing by default. It is only useful if you have wiki access.
>>  CONFIG_PRINT_WIKI ?= no
>>
>> @@ -138,6 +141,11 @@
>>  OBJS += drkaiser.o
>>  endif
>>
>> +ifeq ($(CONFIG_BUSPIRATESPI), yes)
>> +FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1'
>> +OBJS += buspirate_spi.o
>> +endif
>> +
>>  ifeq ($(CONFIG_PRINT_WIKI), yes)
>>  FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1'
>>  OBJS += print_wiki.o
>> Index: flashrom-buspiratespi/spi.h
>> ===================================================================
>> --- flashrom-buspiratespi/spi.h (Revision 767)
>> +++ flashrom-buspiratespi/spi.h (Arbeitskopie)
>> @@ -106,6 +106,7 @@
>>  #define JEDEC_BYTE_PROGRAM_INSIZE      0x00
>>
>>  /* Error codes */
>> +#define SPI_GENERIC_ERROR      -1
>>  #define SPI_INVALID_OPCODE     -2
>>  #define SPI_INVALID_ADDRESS    -3
>>  #define SPI_INVALID_LENGTH     -4
>> Index: flashrom-buspiratespi/flashrom.c
>> ===================================================================
>> --- flashrom-buspiratespi/flashrom.c    (Revision 767)
>> +++ flashrom-buspiratespi/flashrom.c    (Arbeitskopie)
>> @@ -204,6 +204,25 @@
>>        },
>>  #endif
>>
>> +#if BUSPIRATE_SPI_SUPPORT == 1
>> +       {
>> +               .name                   = "buspiratespi",
>> +               .init                   = buspirate_spi_init,
>> +               .shutdown               = buspirate_spi_shutdown,
>> +               .map_flash_region       = fallback_map,
>> +               .unmap_flash_region     = fallback_unmap,
>> +               .chip_readb             = noop_chip_readb,
>> +               .chip_readw             = fallback_chip_readw,
>> +               .chip_readl             = fallback_chip_readl,
>> +               .chip_readn             = fallback_chip_readn,
>> +               .chip_writeb            = noop_chip_writeb,
>> +               .chip_writew            = fallback_chip_writew,
>> +               .chip_writel            = fallback_chip_writel,
>> +               .chip_writen            = fallback_chip_writen,
>> +               .delay                  = internal_delay,
>> +       },
>> +#endif
>> +
>>        {}, /* This entry corresponds to PROGRAMMER_INVALID. */
>>  };
>>
>>
>>
>> --
>> Developer quote of the month:
>> "We are juggling too many chainsaws and flaming arrows and tigers."
>>
>>
>

Patch

Index: flashrom-buspiratespi/flash.h
===================================================================
--- flashrom-buspiratespi/flash.h	(Revision 767)
+++ flashrom-buspiratespi/flash.h	(Arbeitskopie)
@@ -104,6 +104,9 @@ 
 #if SERPROG_SUPPORT == 1
 	PROGRAMMER_SERPROG,
 #endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+	PROGRAMMER_BUSPIRATESPI,
+#endif
 	PROGRAMMER_INVALID /* This must always be the last entry. */
 };
 
@@ -484,6 +487,12 @@ 
 int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
 int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
 
+/* buspirate_spi.c */
+int buspirate_spi_init(void);
+int buspirate_spi_shutdown(void);
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+
 /* flashrom.c */
 extern char *programmer_param;
 extern int verbose;
@@ -527,6 +536,9 @@ 
 #if DUMMY_SUPPORT == 1
 	SPI_CONTROLLER_DUMMY,
 #endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+	SPI_CONTROLLER_BUSPIRATE,
+#endif
 	SPI_CONTROLLER_INVALID /* This must always be the last entry. */
 };
 extern const int spi_programmer_count;
@@ -736,5 +748,8 @@ 
 uint8_t serprog_chip_readb(const chipaddr addr);
 void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
 void serprog_delay(int delay);
+void sp_flush_incoming(void);
+int sp_openserport(char *dev, unsigned int baud);
+extern int sp_fd;
 
 #endif				/* !__FLASH_H__ */
Index: flashrom-buspiratespi/buspirate_spi.c
===================================================================
--- flashrom-buspiratespi/buspirate_spi.c	(Revision 0)
+++ flashrom-buspiratespi/buspirate_spi.c	(Revision 0)
@@ -0,0 +1,317 @@ 
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include "flash.h"
+#include "spi.h"
+
+int buspirate_serialport_setup(char *dev)
+{
+	/* 115200bps, 8 databits, no parity, 1 stopbit */
+	sp_fd = sp_openserport(dev, 115200);
+	return 0;
+}
+
+int buspirate_serialport_shutdown(void)
+{
+	close(sp_fd);
+	return 0;
+}
+
+int serialport_write(unsigned char *buf, unsigned int writecnt)
+{
+	int tmp = 0;
+
+	while (tmp != writecnt) {
+		tmp = write(sp_fd, buf + tmp, writecnt - tmp);
+		if (tmp == -1)
+			return 1;
+		if (!tmp)
+			printf_debug("Empty write\n");
+	}
+
+	return 0;
+}
+
+int serialport_read(unsigned char *buf, unsigned int readcnt)
+{
+	int tmp = 0;
+
+	while (tmp != readcnt) {
+		tmp = read(sp_fd, buf + tmp, readcnt - tmp);
+		if (tmp == -1)
+			return 1;
+		if (!tmp)
+			printf_debug("Empty read\n");
+	}
+
+	return 0;
+}
+
+int buspirate_discard_read(void)
+{
+	int flags;
+
+	printf_debug("%s\n", __func__);
+	flags = fcntl(sp_fd, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(sp_fd, F_SETFL, flags);
+	sp_flush_incoming();
+	flags &= ~O_NONBLOCK;
+	fcntl(sp_fd, F_SETFL, flags);
+
+	return 0;
+}
+
+#undef FAKE_COMMUNICATION
+int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
+{
+	int i, ret = 0;
+
+	printf_debug("%s: write %i, read %i\n", __func__, writecnt, readcnt);
+	if (!writecnt && !readcnt) {
+		fprintf(stderr, "Zero length command!\n");
+		return 1;
+	}
+	printf_debug("Sending");
+	for (i = 0; i < writecnt; i++)
+		printf_debug(" 0x%02x", buf[i]);
+#ifdef FAKE_COMMUNICATION
+	/* Placate the caller for now. */
+	buf[0] = 0x01;
+	memset(buf + 1, 0xff, readcnt - 1);
+	ret = 0;
+#else
+	if (writecnt)
+		ret = serialport_write(buf, writecnt);
+	if (ret)
+		return ret;
+	if (readcnt)
+		ret = serialport_read(buf, readcnt);
+	if (ret)
+		return ret;
+#endif
+	printf_debug(", receiving");
+	for (i = 0; i < readcnt; i++)
+		printf_debug(" 0x%02x", buf[i]);
+	printf_debug("\n");
+	return 0;
+}
+
+int buspirate_spi_init(void)
+{
+	unsigned char buf[512];
+	int ret = 0;
+	int i;
+	char *devpos = NULL;
+	char *dev = NULL;
+	int devlen;
+
+	if (programmer_param && !strlen(programmer_param)) {
+		free(programmer_param);
+		programmer_param = NULL;
+	}
+	if (programmer_param) {
+		devpos = strstr(programmer_param, "dev=");
+		if (devpos) {
+			devpos += 4;
+			devlen = strcspn(devpos, ",:");
+			if (devlen) {
+				dev = malloc(devlen + 1);
+				if (!dev) {
+					fprintf(stderr, "Out of memory!\n");
+					exit(1);
+				}
+				strncpy(dev, devpos, devlen);
+				dev[devlen] = '\0';
+			}
+		}
+		free(programmer_param);
+		programmer_param = NULL;
+	}
+	if (!dev) {
+		fprintf(stderr, "No serial device given. Use flashrom -p "
+			"buspiratespi:dev=/dev/ttyUSB0\n");
+		return 1;
+	}
+
+	ret = buspirate_serialport_setup(dev);
+	if (ret)
+		return ret;
+
+	/* This is the brute force version, but it should work. */
+	for (i = 0; i < 19; i++) {
+		/* Enter raw bitbang mode */
+		buf[0] = 0x00;
+		/* Send the command, don't read the response. */
+		ret = buspirate_sendrecv(buf, 1, 0);
+		if (ret)
+			return ret;
+		/* Read any response and discard it. */
+		ret = buspirate_discard_read();
+		if (ret)
+			return ret;
+	}
+	/* Enter raw bitbang mode */
+	buf[0] = 0x00;
+	ret = buspirate_sendrecv(buf, 1, 5);
+	if (ret)
+		return ret;
+	if (memcmp(buf, "BBIO", 4)) {
+		fprintf(stderr, "Entering raw bitbang mode failed!\n");
+		return 1;
+	}
+	printf_debug("Raw bitbang mode version %c\n", buf[4]);
+	if (buf[4] != '1') {
+		fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
+			buf[4]);
+		return 1;
+	}
+	/* Enter raw SPI mode */
+	buf[0] = 0x01;
+	ret = buspirate_sendrecv(buf, 1, 4);
+	if (memcmp(buf, "SPI", 3)) {
+		fprintf(stderr, "Entering raw SPI mode failed!\n");
+		return 1;
+	}
+	printf_debug("Raw SPI mode version %c\n", buf[3]);
+	if (buf[3] != '1') {
+		fprintf(stderr, "Can't handle raw SPI mode version %c!\n",
+			buf[3]);
+		return 1;
+	}
+
+	/* Initial setup: Enable power, */
+	/* De-assert CS# */
+	buf[0] = 0x03;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return 1;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error!\n");
+		return 1;
+	}
+
+	buses_supported = CHIP_BUSTYPE_SPI;
+	spi_controller = SPI_CONTROLLER_BUSPIRATE;
+
+	return 0;
+}
+
+int buspirate_spi_shutdown(void)
+{
+	unsigned char buf[5];
+	int ret = 0;
+
+	/* Exit raw SPI mode (enter raw bitbang mode) */
+	buf[0] = 0x00;
+	ret = buspirate_sendrecv(buf, 1, 5);
+	if (ret)
+		return ret;
+	if (memcmp(buf, "BBIO", 4)) {
+		fprintf(stderr, "Entering raw bitbang mode failed!\n");
+		return 1;
+	}
+	printf_debug("Raw bitbang mode version %c\n", buf[4]);
+	if (buf[4] != '1') {
+		fprintf(stderr, "Can't handle raw bitbang mode version %c!\n",
+			buf[4]);
+		return 1;
+	}
+	/* Reset Bus Pirate (return to user terminal) */
+	buf[0] = 0x0f;
+	ret = buspirate_sendrecv(buf, 1, 0);
+	if (ret)
+		return ret;
+
+	/* Shut down serial port communication */
+	ret = buspirate_serialport_shutdown();
+	if (ret)
+		return ret;
+	printf_debug("Bus Pirate shutdown completed.\n");
+
+	return 0;
+}
+
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	static unsigned char *buf = NULL;
+	int i = 0, ret = 0;
+
+	if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
+		return SPI_INVALID_LENGTH;
+
+	/* +2 is pretty arbitrary. */
+	buf = realloc(buf, writecnt + readcnt + 2);
+	if (!buf) {
+		fprintf(stderr, "Out of memory!\n");
+		exit(1); // -1
+	}
+
+	/* Assert CS# */
+	buf[i++] = 0x02;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return SPI_GENERIC_ERROR;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error!\n");
+		return SPI_GENERIC_ERROR;
+	}
+
+	i = 0;
+	buf[i++] = 0x10 | (writecnt + readcnt - 1);
+	memcpy(buf + i, writearr, writecnt);
+	i += writecnt;
+	memset(buf + i, 0, readcnt);
+	ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt);
+	if (ret)
+		return SPI_GENERIC_ERROR;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error!\n");
+		return SPI_GENERIC_ERROR;
+	}
+	memcpy(readarr, buf + i, readcnt);
+
+	i = 0;
+	/* De-assert CS# */
+	buf[i++] = 0x03;
+	ret = buspirate_sendrecv(buf, 1, 1);
+	if (ret)
+		return SPI_GENERIC_ERROR;
+	if (buf[0] != 0x01) {
+		fprintf(stderr, "Protocol error!\n");
+		return SPI_GENERIC_ERROR;
+	}
+
+	return ret;
+}
+
+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	/* Maximum read length is 12 bytes, use 8 for now. */
+	return spi_read_chunked(flash, buf, start, len, 8);
+}
+
+/* We could do 12-byte writes, but for now we use the generic 1-byte code. */
Index: flashrom-buspiratespi/serprog.c
===================================================================
--- flashrom-buspiratespi/serprog.c	(Revision 767)
+++ flashrom-buspiratespi/serprog.c	(Arbeitskopie)
@@ -61,7 +61,7 @@ 
 #define S_CMD_Q_RDNMAXLEN	0x11	/* Query read-n maximum length			*/
 #define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
 
-static int sp_fd;
+int sp_fd;
 
 static uint16_t sp_device_serbuf_size = 16;
 static uint16_t sp_device_opbuf_size = 300;
@@ -185,7 +185,7 @@ 
 	{0, 0}			/* Terminator */
 };
 
-static int sp_openserport(char *dev, unsigned int baud)
+int sp_openserport(char *dev, unsigned int baud)
 {
 	struct termios options;
 	int fd, i;
@@ -208,20 +208,16 @@ 
 			break;
 		}
 	}
-	options.c_cflag &= ~PARENB;
-	options.c_cflag &= ~CSTOPB;
-	options.c_cflag &= ~CSIZE;
-	options.c_cflag |= CS8;
-	options.c_cflag &= ~CRTSCTS;
+	options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
+	options.c_cflag |= (CS8 | CLOCAL | CREAD);
 	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
 	options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
 	options.c_oflag &= ~OPOST;
-	options.c_cflag |= (CLOCAL | CREAD);
 	tcsetattr(fd, TCSANOW, &options);
 	return fd;
 }
 
-static void sp_flush_incoming(void)
+void sp_flush_incoming(void)
 {
 	int i;
 	for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */
Index: flashrom-buspiratespi/spi.c
===================================================================
--- flashrom-buspiratespi/spi.c	(Revision 767)
+++ flashrom-buspiratespi/spi.c	(Arbeitskopie)
@@ -100,6 +100,15 @@ 
 	},
 #endif
 
+#if BUSPIRATE_SPI_SUPPORT == 1
+	{ /* SPI_CONTROLLER_BUSPIRATE */
+		.command = buspirate_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = buspirate_spi_read,
+		.write_256 = spi_chip_write_1,
+	},
+#endif
+
 	{}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */
 };
 
Index: flashrom-buspiratespi/Makefile
===================================================================
--- flashrom-buspiratespi/Makefile	(Revision 767)
+++ flashrom-buspiratespi/Makefile	(Arbeitskopie)
@@ -89,6 +89,9 @@ 
 # Always enable Dr. Kaiser for now.
 CONFIG_DRKAISER ?= yes
 
+# Always enable Bus Pirate SPI for now.
+CONFIG_BUSPIRATESPI ?= yes
+
 # Disable wiki printing by default. It is only useful if you have wiki access.
 CONFIG_PRINT_WIKI ?= no
 
@@ -138,6 +141,11 @@ 
 OBJS += drkaiser.o
 endif
 
+ifeq ($(CONFIG_BUSPIRATESPI), yes)
+FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1'
+OBJS += buspirate_spi.o
+endif
+
 ifeq ($(CONFIG_PRINT_WIKI), yes)
 FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1'
 OBJS += print_wiki.o
Index: flashrom-buspiratespi/spi.h
===================================================================
--- flashrom-buspiratespi/spi.h	(Revision 767)
+++ flashrom-buspiratespi/spi.h	(Arbeitskopie)
@@ -106,6 +106,7 @@ 
 #define JEDEC_BYTE_PROGRAM_INSIZE	0x00
 
 /* Error codes */
+#define SPI_GENERIC_ERROR	-1
 #define SPI_INVALID_OPCODE	-2
 #define SPI_INVALID_ADDRESS	-3
 #define SPI_INVALID_LENGTH	-4
Index: flashrom-buspiratespi/flashrom.c
===================================================================
--- flashrom-buspiratespi/flashrom.c	(Revision 767)
+++ flashrom-buspiratespi/flashrom.c	(Arbeitskopie)
@@ -204,6 +204,25 @@ 
 	},
 #endif
 
+#if BUSPIRATE_SPI_SUPPORT == 1
+	{
+		.name			= "buspiratespi",
+		.init			= buspirate_spi_init,
+		.shutdown		= buspirate_spi_shutdown,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.chip_readb		= noop_chip_readb,
+		.chip_readw		= fallback_chip_readw,
+		.chip_readl		= fallback_chip_readl,
+		.chip_readn		= fallback_chip_readn,
+		.chip_writeb		= noop_chip_writeb,
+		.chip_writew		= fallback_chip_writew,
+		.chip_writel		= fallback_chip_writel,
+		.chip_writen		= fallback_chip_writen,
+		.delay			= internal_delay,
+	},
+#endif
+
 	{}, /* This entry corresponds to PROGRAMMER_INVALID. */
 };