Index: serprog-protocol.txt
===================================================================
--- serprog-protocol.txt	(revision 1299)
+++ serprog-protocol.txt	(working copy)
@@ -31,6 +31,8 @@
 0x10	Sync NOP			none				NAK + ACK (for synchronization)
 0x11	Query maximum read-n length	none				ACK + 24-bit length (0==2^24) / NAK
 0x12	Set used bustype		8-bit flags (as with 0x05)	ACK / NAK
+0x13	Perform SPI operation		24-bit slen + 24-bit rlen	ACK + rlen bytes of data / NAK
+					 + slen bytes of data
 0x??	unimplemented command - invalid.
 
 
@@ -50,7 +52,7 @@
 		it should return a big bogus value - eg 0xFFFF.
 	0x05 (Q_BUSTYPE):
 		The bit's are defined as follows:
-		bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported).
+		bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI.
 	0x06 (Q_CHIPSIZE):
 		Only applicable to parallel programmers.
 		An LPC/FWH/SPI-programmer can report this as not supported in the command bitmap.
@@ -66,6 +68,10 @@
 		Set's the used bustype if the programmer can support more than one flash protocol.
 		Sending a byte with more than 1 bit set will make the programmer decide among them
 		on it's own. Bit values as with Q_BUSTYPE.
+	0x13 (O_SPIOP):
+		Maximum slen is Q_WRNMAXLEN result after Q_BUSTYPE returns
+		only SPI or S_BUSTYPE == SPI is used. Same for rlen and Q_RDNMAXLEN.
+		This operation is immediate, meaning it doesnt use the operation buffer.
 	About mandatory commands:
 		The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10,
 		but one can't really do anything with these commands.
@@ -99,3 +105,4 @@
 #define S_CMD_SYNCNOP		0x10		/* Special no-operation that returns NAK+ACK	*/
 #define S_CMD_Q_RDNMAXLEN	0x11		/* Query read-n maximum length			*/
 #define S_CMD_S_BUSTYPE		0x12		/* Set used bustype(s).				*/
+#define S_CMD_O_SPIOP		0x13		/* Perform SPI operation.			*/
Index: serprog.c
===================================================================
--- serprog.c	(revision 1299)
+++ serprog.c	(working copy)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the flashrom project.
  *
- * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.com>
+ * Copyright (C) 2009,2011 Urja Rannikko <urjaman@gmail.com>
  * Copyright (C) 2009 Carl-Daniel Hailfinger
  *
  * This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,7 @@
 #define S_CMD_SYNCNOP		0x10	/* Special no-operation that returns NAK+ACK    */
 #define S_CMD_Q_RDNMAXLEN	0x11	/* Query read-n maximum length			*/
 #define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
+#define S_CMD_O_SPIOP		0x13	/* Perform SPI operation.			*/
 
 static uint16_t sp_device_serbuf_size = 16;
 static uint16_t sp_device_opbuf_size = 300;
@@ -295,6 +296,19 @@
 	return 0;
 }
 
+static const struct spi_programmer spi_programmer_serprog = {
+	.type = SPI_CONTROLLER_SERPROG,
+	.max_data_read = MAX_DATA_READ_UNLIMITED,
+	.max_data_write = MAX_DATA_WRITE_UNLIMITED,
+	.command = serprog_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = default_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
+/* TODO: Support SPI max read & write data length reporting by the programmer,
+  currently we cannot do that because we dont have access to curent flashchip data. */
+
 int serprog_init(void)
 {
 	uint16_t iface;
@@ -318,7 +332,7 @@
 			msg_perr("Error: No baudrate specified.\n"
 				 "Use flashrom -p serprog:dev=/dev/device:baud\n");
 			free(device);
-			return 1;		
+			return 1;
 		}
 		if (strlen(device)) {
 			sp_fd = sp_openserport(device, atoi(baudport));
@@ -351,7 +365,7 @@
 			msg_perr("Error: No port specified.\n"
 				 "Use flashrom -p serprog:ip=ipaddr:port\n");
 			free(device);
-			return 1;		
+			return 1;
 		}
 		if (strlen(device)) {
 			sp_fd = sp_opensocket(device, atoi(baudport));
@@ -400,37 +414,58 @@
 
 	sp_check_avail_automatic = 1;
 
+
+	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
+		msg_perr("Warning: NAK to query supported buses\n");
+		c = CHIP_BUSTYPE_NONSPI;	/* A reasonable default for now. */
+	}
+	buses_supported = c;
+
 	/* Check for the minimum operational set of commands */
-	if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
-		msg_perr("Error: Single byte read not supported\n");
-		exit(1);
-	}
-	/* This could be translated to single byte reads (if missing),	*
-	 * but now we dont support that.				*/
-	if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
-		msg_perr("Error: Read n bytes not supported\n");
-		exit(1);
-	}
+
 	/* In the future one could switch to read-only mode if these	*
 	 * are not available.						*/
 	if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
 		msg_perr("Error: Initialize operation buffer not supported\n");
 		exit(1);
 	}
-	if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
-		msg_perr("Error: Write to opbuf: write byte not supported\n");
-		exit(1);
-	}
+
 	if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
 		msg_perr("Error: Write to opbuf: delay not supported\n");
 		exit(1);
 	}
+
 	if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
 		msg_perr(
 			"Error: Execute operation buffer not supported\n");
 		exit(1);
 	}
 
+	if (buses_supported & CHIP_BUSTYPE_SPI) {
+		if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
+			msg_perr("Error: SPI operation not supported while the SPI bustype is\n");
+			exit(1);
+		}
+		register_spi_programmer(&spi_programmer_serprog);
+	}
+
+	if (buses_supported & CHIP_BUSTYPE_NONSPI) {
+		if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
+			msg_perr("Error: Single byte read not supported\n");
+			exit(1);
+		}
+		/* This could be translated to single byte reads (if missing),	*
+		* but now we dont support that.				*/
+		if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
+			msg_perr("Error: Read n bytes not supported\n");
+			exit(1);
+		}
+		if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
+			msg_perr("Error: Write to opbuf: write byte not supported\n");
+			exit(1);
+		}
+	}
+
 	if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
 		msg_perr("Warning: NAK to query programmer name\n");
 		strcpy((char *)pgmname, "(unknown)");
@@ -450,12 +485,6 @@
 	msg_pdbg(MSGHEADER "operation buffer size %d\n",
 		     sp_device_opbuf_size);
 
-	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
-		msg_perr("Warning: NAK to query supported buses\n");
-		c = CHIP_BUSTYPE_NONSPI;	/* A reasonable default for now. */
-	}
-	buses_supported = c;
-
 	if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
 		msg_perr("Error: NAK to initialize operation buffer\n");
 		exit(1);
@@ -468,6 +497,7 @@
 		sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
 		sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
 		sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
+		if (!sp_max_write_n) sp_max_write_n = (1<<24);
 		msg_pdbg(MSGHEADER "Maximum write-n length %d\n",
 			     sp_max_write_n);
 		sp_write_n_buf = malloc(sp_max_write_n);
@@ -477,7 +507,7 @@
 		}
 		sp_write_n_bytes = 0;
 	}
-	
+
 	if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN))
 		&&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) {
 		sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
@@ -680,3 +710,25 @@
 	sp_opbuf_usage += 5;
 	sp_prev_was_write = 0;
 }
+
+int serprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+                        const unsigned char *writearr, unsigned char *readarr)
+{
+        unsigned char *parmbuf;
+	int ret;
+        msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
+	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+		sp_execute_opbuf();
+	parmbuf = malloc(writecnt+6);
+	if (!parmbuf) sp_die("Error: cannot malloc SPI send param buffer");
+	parmbuf[0] = (writecnt >> 0) & 0xFF;
+	parmbuf[1] = (writecnt >> 8) & 0xFF;
+	parmbuf[2] = (writecnt >> 16) & 0xFF;
+	parmbuf[3] = (readcnt >> 0) & 0xFF;
+	parmbuf[4] = (readcnt >> 8) & 0xFF;
+	parmbuf[5] = (readcnt >> 16) & 0xFF;
+	memcpy(&(parmbuf[6]),writearr,writecnt);
+	ret = sp_docommand(S_CMD_O_SPIOP, writecnt+6, parmbuf, readcnt, readarr);
+	free(parmbuf);
+	return ret;
+}
Index: programmer.h
===================================================================
--- programmer.h	(revision 1299)
+++ programmer.h	(working copy)
@@ -560,6 +560,9 @@
 #if CONFIG_OGP_SPI == 1 || CONFIG_NICINTEL_SPI == 1 || CONFIG_RAYER_SPI == 1 || (CONFIG_INTERNAL == 1 && (defined(__i386__) || defined(__x86_64__)))
 	SPI_CONTROLLER_BITBANG,
 #endif
+#if CONFIG_SERPROG == 1
+	SPI_CONTROLLER_SERPROG,
+#endif
 };
 extern const int spi_programmer_count;
 
@@ -622,6 +625,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);
+int serprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr);
 
 /* serial.c */
 #if _WIN32
