Add support for Xilinx parallel III (DLC5) programing cable

The rayer_spi driver defaults to the RayeR cable, but selecting other
predefined pin layouts with the type= parameter is possible:
flashrom -p rayer_spi:type=xilinx

Corresponding to flashrom svn r1437.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
diff --git a/flashrom.8 b/flashrom.8
index 1b9bf60..76f25bd 100644
--- a/flashrom.8
+++ b/flashrom.8
@@ -210,8 +210,8 @@
 .sp
 .BR "* dediprog" " (for SPI flash ROMs attached to a Dediprog SF100)"
 .sp
-.BR "* rayer_spi" " (for SPI flash ROMs attached to a RayeR parport \
-based programmer)"
+.BR "* rayer_spi" " (for SPI flash ROMs attached to a RayeR parport "
+or Xilinx DLC5 compatible cable)
 .sp
 .BR "* nicintel_spi" " (for SPI flash ROMs on Intel Gigabit network cards)"
 .sp
@@ -512,8 +512,22 @@
 is base I/O port address of the parallel port, which must be a multiple of
 four. Make sure to not forget the "0x" prefix for hexadecimal port addresses.
 .sp
-More information about the hardware is available at
-.BR http://rayer.ic.cz/elektro/spipgm.htm .
+The default cable type is the RayeR cable. You can use the optional
+.B type
+parameter to specify the cable type with the
+.sp
+.B "  flashrom \-p rayer_spi:type=model"
+.sp
+syntax where
+.B model
+can be
+.BR rayer " for the RayeR cable or " xilinx " for the Xilinx Parallel Cable III
+(DLC 5).
+.sp
+More information about the RayeR hardware is available at
+.BR "http://rayer.ic.cz/elektro/spipgm.htm " .
+The schematic of the Xilinx DLC 5 was published at
+.BR "http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html " .
 .TP
 .BR "ogp_spi " programmer
 The flash ROM chip to access must be specified with the 
diff --git a/rayer_spi.c b/rayer_spi.c
index 0807487..7f9270a 100644
--- a/rayer_spi.c
+++ b/rayer_spi.c
@@ -31,18 +31,25 @@
 #if defined(__i386__) || defined(__x86_64__)
 
 #include <stdlib.h>
+#include <string.h>
 #include "flash.h"
 #include "programmer.h"
 
+enum rayer_type {
+	TYPE_RAYER,
+	TYPE_XILINX_DLC5,
+};
+
 /* We have two sets of pins, out and in. The numbers for both sets are
  * independent and are bitshift values, not real pin numbers.
+ * Default settings are for the the RayeR hardware.
  */
 /* Pins for master->slave direction */
-#define SPI_CS_PIN 5
-#define SPI_SCK_PIN 6
-#define SPI_MOSI_PIN 7
+static int rayer_cs_bit = 5;
+static int rayer_sck_bit = 6;
+static int rayer_mosi_bit = 7;
 /* Pins for slave->master direction */
-#define SPI_MISO_PIN 6
+static int rayer_miso_bit = 6;
 
 static uint16_t lpt_iobase;
 
@@ -51,22 +58,22 @@
 
 static void rayer_bitbang_set_cs(int val)
 {
-	lpt_outbyte &= ~(1 << SPI_CS_PIN);
-	lpt_outbyte |= (val << SPI_CS_PIN);
+	lpt_outbyte &= ~(1 << rayer_cs_bit);
+	lpt_outbyte |= (val << rayer_cs_bit);
 	OUTB(lpt_outbyte, lpt_iobase);
 }
 
 static void rayer_bitbang_set_sck(int val)
 {
-	lpt_outbyte &= ~(1 << SPI_SCK_PIN);
-	lpt_outbyte |= (val << SPI_SCK_PIN);
+	lpt_outbyte &= ~(1 << rayer_sck_bit);
+	lpt_outbyte |= (val << rayer_sck_bit);
 	OUTB(lpt_outbyte, lpt_iobase);
 }
 
 static void rayer_bitbang_set_mosi(int val)
 {
-	lpt_outbyte &= ~(1 << SPI_MOSI_PIN);
-	lpt_outbyte |= (val << SPI_MOSI_PIN);
+	lpt_outbyte &= ~(1 << rayer_mosi_bit);
+	lpt_outbyte |= (val << rayer_mosi_bit);
 	OUTB(lpt_outbyte, lpt_iobase);
 }
 
@@ -75,7 +82,7 @@
 	uint8_t tmp;
 
 	tmp = INB(lpt_iobase + 1);
-	tmp = (tmp >> SPI_MISO_PIN) & 0x1;
+	tmp = (tmp >> rayer_miso_bit) & 0x1;
 	return tmp;
 }
 
@@ -89,14 +96,15 @@
 
 int rayer_spi_init(void)
 {
-	char *portpos = NULL;
+	char *arg = NULL;
+	enum rayer_type rayer_type = TYPE_RAYER;
 
 	/* Non-default port requested? */
-	portpos = extract_programmer_param("iobase");
-	if (portpos) {
+	arg = extract_programmer_param("iobase");
+	if (arg) {
 		char *endptr = NULL;
 		unsigned long tmp;
-		tmp = strtoul(portpos, &endptr, 0);
+		tmp = strtoul(arg, &endptr, 0);
 		/* Port 0, port >0x10000, unaligned ports and garbage strings
 		 * are rejected.
 		 */
@@ -109,7 +117,7 @@
 			msg_perr("Error: iobase= specified, but the I/O base "
 				 "given was invalid.\nIt must be a multiple of "
 				 "0x4 and lie between 0x100 and 0xfffc.\n");
-			free(portpos);
+			free(arg);
 			return 1;
 		} else {
 			lpt_iobase = (uint16_t)tmp;
@@ -120,11 +128,44 @@
 		/* Pick a default value for the I/O base. */
 		lpt_iobase = 0x378;
 	}
-	free(portpos);
+	free(arg);
 	
 	msg_pdbg("Using address 0x%x as I/O base for parallel port access.\n",
 		 lpt_iobase);
 
+	arg = extract_programmer_param("type");
+	if (arg) {
+		if (!strcasecmp(arg, "rayer")) {
+			rayer_type = TYPE_RAYER;
+		} else if (!strcasecmp(arg, "xilinx")) {
+			rayer_type = TYPE_XILINX_DLC5;
+		} else {
+			msg_perr("Error: Invalid device type specified.\n");
+			free(arg);
+			return 1;
+		}
+	}
+	free(arg);
+	switch (rayer_type) {
+	case TYPE_RAYER:
+		msg_pdbg("Using RayeR SPIPGM pinout.\n");
+		/* Bits for master->slave direction */
+		rayer_cs_bit = 5;
+		rayer_sck_bit = 6;
+		rayer_mosi_bit = 7;
+		/* Bits for slave->master direction */
+		rayer_miso_bit = 6;
+		break;
+	case TYPE_XILINX_DLC5:
+		msg_pdbg("Using Xilinx Parallel Cable III (DLC 5) pinout.\n");
+		/* Bits for master->slave direction */
+		rayer_cs_bit = 2;
+		rayer_sck_bit = 1;
+		rayer_mosi_bit = 0;
+		/* Bits for slave->master direction */
+		rayer_miso_bit = 4;
+	}
+
 	get_io_perms();
 
 	/* Get the initial value before writing to any line. */