Add the ability to set Bus Pirate SPI speed via the command line

Example usage:
flashrom -p buspiratespi:spispeed=2.6MHz,dev=/dev/foo
flashrom -p buspiratespi:dev=/dev/foo,spispeed=2.6M

Refactor programmer option parsing (this allows cleanups in other
programmers as well).

Increase SPI read size from 8 to 12 bytes (current single-transaction
limit of the Bus Pirate raw SPI protocol).

Add Bus Pirate to the list of programmers supporting 4 byte RDID.

Add Bus Pirate syntax to the man page.

Tested-by: Sean Nelson <audiohacked@gmail.com>

Corresponding to flashrom svn r776.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Sean Nelson <audiohacked@gmail.com>
diff --git a/buspirate_spi.c b/buspirate_spi.c
index 259e434..a1c8265 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -131,34 +131,37 @@
 	return 0;
 }
 
+static const struct buspirate_spispeeds spispeeds[] = {
+	{"30k",		0x0},
+	{"125k",	0x1},
+	{"250k",	0x2},
+	{"1M",		0x3},
+	{"2M",		0x4},
+	{"2.6M",	0x5},
+	{"4M",		0x6},
+	{"8M",		0x7},
+	{NULL,		0x0}
+};
+
 int buspirate_spi_init(void)
 {
 	unsigned char buf[512];
 	int ret = 0;
 	int i;
-	char *devpos = NULL;
 	char *dev = NULL;
-	int devlen;
+	char *speed = NULL;
+	int spispeed = 0x7;
 
 	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';
-			}
-		}
+		dev = extract_param(&programmer_param, "dev=", ",:");
+		speed = extract_param(&programmer_param, "spispeed=", ",:");
+		if (strlen(programmer_param))
+			fprintf(stderr, "Unhandled programmer parameters: %s\n",
+				programmer_param);
 		free(programmer_param);
 		programmer_param = NULL;
 	}
@@ -167,6 +170,18 @@
 			"buspiratespi:dev=/dev/ttyUSB0\n");
 		return 1;
 	}
+	if (speed) {
+		for (i = 0; spispeeds[i].name; i++)
+			if (!strncasecmp(spispeeds[i].name, speed,
+			    strlen(spispeeds[i].name))) {
+				spispeed = spispeeds[i].speed;
+				break;
+			}
+		if (!spispeeds[i].name)
+			fprintf(stderr, "Invalid SPI speed, using default.\n");
+	}
+	/* This works because speeds numbering starts at 0 and is contiguous. */
+	printf_debug("SPI speed is %sHz\n", spispeeds[spispeed].name);
 
 	ret = buspirate_serialport_setup(dev);
 	if (ret)
@@ -224,8 +239,8 @@
 		return 1;
 	}
 
-	/* Set speed to 8 MHz */
-	buf[0] = 0x60 | 0x7;
+	/* Set SPI speed */
+	buf[0] = 0x60 | spispeed;
 	ret = buspirate_sendrecv(buf, 1, 1);
 	if (ret)
 		return 1;
@@ -351,8 +366,7 @@
 
 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);
+	return spi_read_chunked(flash, buf, start, len, 12);
 }
 
 /* We could do 12-byte writes, but for now we use the generic 1-byte code. */
diff --git a/flash.h b/flash.h
index b271b8a..008af28 100644
--- a/flash.h
+++ b/flash.h
@@ -488,6 +488,10 @@
 int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
 
 /* buspirate_spi.c */
+struct buspirate_spispeeds {
+	const char *name;
+	const int speed;
+};
 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);
@@ -503,6 +507,7 @@
 int erase_flash(struct flashchip *flash);
 int min(int a, int b);
 int max(int a, int b);
+char *extract_param(char **haystack, char *needle, char *delim);
 int check_erased_range(struct flashchip *flash, int start, int len);
 int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message);
 char *strcat_realloc(char *dest, const char *src);
diff --git a/flashrom.8 b/flashrom.8
index 3986f75..011840c 100644
--- a/flashrom.8
+++ b/flashrom.8
@@ -152,6 +152,8 @@
 .sp
 .BR "* serprog" " (for flash ROMs attached to Urja's AVR programmer)"
 .sp
+.BR "* buspiratespi" " (for flash ROMs attached to a Bus Pirate)"
+.sp
 The dummy programmer has an optional parameter specifying the bus types it
 should support. For that you have to use the
 .B "flashrom -p dummy:type"
@@ -219,6 +221,16 @@
 instead. More information about serprog is available in serprog-protocol.txt in
 the source distribution.
 .sp
+The buspiratespi programmer has a required dev parameter specifying the Bus
+Pirate device node and an optional spispeed parameter specifying the frequency
+of the SPI bus. The parameter delimiter is a comma. Syntax is
+.B "flashrom -p buspiratespi:dev=/dev/device,spispeed=frequency"
+where
+.B frequency
+can be any of
+.B 30k 125k 250k 1M 2M 2.6M 4M 8M
+(in Hz).
+.sp
 Support for some programmers can be disabled at compile time.
 .B "flashrom -h"
 lists all supported programmers.
diff --git a/flashrom.c b/flashrom.c
index 7e681cc..fffedd6 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -336,6 +336,60 @@
 	return dest;
 }
 
+/* This is a somewhat hacked function similar in some ways to strtok().
+ * It will look for needle in haystack, return a copy of needle and remove
+ * everything from the first occurrence of needle to the next delimiter
+ * from haystack.
+ */
+char *extract_param(char **haystack, char *needle, char *delim)
+{
+	char *param_pos, *rest, *tmp;
+	char *dev = NULL;
+	int devlen;
+
+	param_pos = strstr(*haystack, needle);
+	do {
+		if (!param_pos)
+			return NULL;
+		/* Beginning of the string? */
+		if (param_pos == *haystack)
+			break;
+		/* After a delimiter? */
+		if (strchr(delim, *(param_pos - 1)))
+			break;
+		/* Continue searching. */
+		param_pos++;
+		param_pos = strstr(param_pos, needle);
+	} while (1);
+		
+	if (param_pos) {
+		param_pos += strlen(needle);
+		devlen = strcspn(param_pos, delim);
+		if (devlen) {
+			dev = malloc(devlen + 1);
+			if (!dev) {
+				fprintf(stderr, "Out of memory!\n");
+				exit(1);
+			}
+			strncpy(dev, param_pos, devlen);
+			dev[devlen] = '\0';
+		}
+		rest = param_pos + devlen;
+		rest += strspn(rest, delim);
+		param_pos -= strlen(needle);
+		memmove(param_pos, rest, strlen(rest) + 1);
+		tmp = realloc(*haystack, strlen(*haystack) + 1);
+		if (!tmp) {
+			fprintf(stderr, "Out of memory!\n");
+			exit(1);
+		}
+		*haystack = tmp;
+	}
+	
+
+	return dev;
+}
+
 /* start is an offset to the base address of the flash chip */
 int check_erased_range(struct flashchip *flash, int start, int len)
 {
diff --git a/spi.c b/spi.c
index f117c8f..14beed7 100644
--- a/spi.c
+++ b/spi.c
@@ -319,6 +319,9 @@
 #if DUMMY_SUPPORT == 1
 	case SPI_CONTROLLER_DUMMY:
 #endif
+#if BUSPIRATE_SPI_SUPPORT == 1
+	case SPI_CONTROLLER_BUSPIRATE:
+#endif
 		return probe_spi_rdid_generic(flash, 4);
 	default:
 		printf_debug("4b ID not supported on this SPI controller\n");