Add a bunch of new/tested stuff and various small changes 16

Tested Mainboards:
OK:
 - Acer V75-M (used in IBM Aptiva 2170-G
   http://www.flashrom.org/pipermail/flashrom/2012-December/010300.html
 - ASRock 4CoreDual-VSTA with W39V040FB
   http://paste.flashrom.org/view.php?id=1446
 - ASRock 775Dual-VSTA
   http://www.flashrom.org/pipermail/flashrom/2012-December/010294.html
 - ASRock E350M1/USB3
   http://paste.flashrom.org/view.php?id=1465
 - ASUS P5B-VM
   http://www.flashrom.org/pipermail/flashrom/2012-December/010351.html
 - ASUS SABERTOOTH 990FX R2.0
   http://www.flashrom.org/pipermail/flashrom/2012-December/010210.html
 - Elitegroup A928 (including a laptop whitelist board enable)
   http://www.flashrom.org/pipermail/flashrom/2012-November/010119.html
 - EVGA 122-CK-NF68
   Reported by Stephanie Daugherty on IRC
   http://paste.flashrom.org/view.php?id=1431
 - GIGABYTE GA-A75M-UD2H
   Reported by Soul_keeper on IRC
   http://paste.flashrom.org/view.php?id=1490
 - Intel D945GCNL
   Add board enable to override laptop detection too.
   http://www.flashrom.org/pipermail/flashrom/2012-December/010276.html
 - MSI G33M (MS-7357)
   http://www.flashrom.org/pipermail/flashrom/2012-October/010056.html
 - Shuttle FB61
   http://www.flashrom.org/pipermail/flashrom/2012-November/010105.html
 - Tyan S4882 (Thunder K8QS Pro)
   Reported on IRC
NOT OK:
   Alienware Aurora-R2
   http://www.flashrom.org/pipermail/flashrom/2012-December/010225.html
   Biostar H61MU3
   http://www.flashrom.org/pipermail/flashrom/2012-November/010144.html
   Dell OptiPlex 7010
   http://paste.flashrom.org/view.php?id=1481
   Intel DH67CL
   http://www.flashrom.org/pipermail/flashrom/2012-November/010112.html
   Supermicro X9DRT-HF+
   http://www.flashrom.org/pipermail/flashrom/2012-November/010155.html
   Supermicro X9DRW
   http://www.flashrom.org/pipermail/flashrom/2012-November/010150.html

Tested flash chips:
 - Atmel AT25FS010 to PREW (+PREW)
   http://paste.flashrom.org/view.php?id=1484
 - Eon EN25F64 to PREW (+EW)
   http://www.flashrom.org/pipermail/flashrom/2012-December/010210.html
 - Spansion S25FL032A/P to PREW (+EW)
   http://paste.flashrom.org/view.php?id=1510
 - ST M29F002T/NT to PREW (+PREW)
   http://www.flashrom.org/pipermail/flashrom/2012-December/010300.html
 - Winbond W25X10 to PREW (+PREW)
   http://paste.flashrom.org/view.php?id=1486

Tested chipsets:
 - NVIDIA MCP78S http://www.flashrom.org/pipermail/flashrom/2012-November/010176.html
 - SiS 650 http://www.flashrom.org/pipermail/flashrom/2012-November/010119.html

Miscellaneous:
- Typo in GA-X58A-UDR3 (correct is GA-X58A-UD3R).
- Force 2-digit hex numbers in prints were it makes sense.
- Share code between enable_flash_sis530() and enable_flash_sis540().
- Some SST 25 series chips support both WRSR enable commands...
- S25FL032A and S25FL064A share the IDs with their P versions, so rename them.
- Fix a few memleaks in serprog.
- Dediprog uses UINT_MAX so include limits.h (fixes the Windows build of dediprog)
- Add (another) hint regarding the mandatory -p parameter to the manpage
  to make Debian bug #690478 happy.
  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=690478
- Fix whitespace issues.
- On shutdown, reset count of registered programmers (by Nico Huber)
- Fix atahpt.c shutdown.
  The order of pcidev_init, register_shutdown and rpci_write_* is important!
  Thanks to Roy for reporting the problem and testing the fix.

Corresponding to flashrom svn r1640.

Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
diff --git a/Makefile b/Makefile
index 4249730..b948996 100644
--- a/Makefile
+++ b/Makefile
@@ -581,7 +581,7 @@
 else
 ifeq ($(TARGET_OS), Darwin)
 # DirectHW framework can be found in the DirectHW library.
-PCILIBS += -framework IOKit -framework DirectHW 
+PCILIBS += -framework IOKit -framework DirectHW
 else
 endif
 endif
diff --git a/atahpt.c b/atahpt.c
index 92f7deb..461191d 100644
--- a/atahpt.c
+++ b/atahpt.c
@@ -72,14 +72,14 @@
 
 	io_base_addr = pcidev_init(PCI_BASE_ADDRESS_4, ata_hpt);
 
+	if (register_shutdown(atahpt_shutdown, NULL))
+		return 1;
+
 	/* Enable flash access. */
 	reg32 = pci_read_long(pcidev_dev, REG_FLASH_ACCESS);
 	reg32 |= (1 << 24);
 	rpci_write_long(pcidev_dev, REG_FLASH_ACCESS, reg32);
 
-	if (register_shutdown(atahpt_shutdown, NULL))
-		return 1;
-
 	register_par_programmer(&par_programmer_atahpt, BUS_PARALLEL);
 
 	return 0;
diff --git a/board_enable.c b/board_enable.c
index d7d77ce..b6834e0 100644
--- a/board_enable.c
+++ b/board_enable.c
@@ -2378,6 +2378,7 @@
 	{0x10b7, 0x9055, 0x1028, 0x0082,  0x8086, 0x7190,      0,      0, NULL,         NULL, NULL,           P3, "Dell",        "OptiPlex GX1",          0,   OK, intel_piix4_gpo30_lower},
 	{0x8086, 0x3590, 0x1028, 0x016c,  0x1000, 0x0030, 0x1028, 0x016c, NULL,         NULL, NULL,           P3, "Dell",        "PowerEdge 1850",        0,   OK, intel_ich_gpio23_raise},
 	{0x1106, 0x3189, 0x1106, 0x3189,  0x1106, 0x3177, 0x1106, 0x3177, "^AD77",      "dfi", "ad77",        P3, "DFI",         "AD77",                  0,   NT, w836xx_memw_enable_2e},
+	{0x1039, 0x6325, 0x1019, 0x0f05,  0x1039, 0x0016,      0,      0, NULL,         NULL, NULL,           P2, "Elitegroup",  "A928",                  0,   OK, p2_whitelist_laptop},
 	{0x10de, 0x03ea, 0x1019, 0x2602,  0x10de, 0x03e0, 0x1019, 0x2602, NULL,         NULL, NULL,           P3, "Elitegroup",  "GeForce6100SM-M",       0,   OK, board_ecs_geforce6100sm_m},
 	{0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996, NULL,         NULL, NULL,           P3, "Elitegroup",  "K7VTA3",                256, OK, NULL},
 	{0x1106, 0x3177, 0x1106, 0x3177,  0x1106, 0x3059, 0x1695, 0x3005, NULL,         NULL, NULL,           P3, "EPoX",        "EP-8K5A2",              0,   OK, w836xx_memw_enable_2e},
@@ -2406,6 +2407,7 @@
 	{0x8086, 0x27A0,      0,      0,  0x8086, 0x27B9,      0,      0, NULL,         "ibase", "mb899",     P3, "IBASE",       "MB899",                 0,   OK, intel_ich_gpio26_raise},
 	{0x1166, 0x0205, 0x1014, 0x0347,  0x1002, 0x515E, 0x1014, 0x0325, NULL,         NULL, NULL,           P3, "IBM",         "x3455",                 0,   OK, board_ibm_x3455},
 	{0x1039, 0x5513, 0x8086, 0xd61f,  0x1039, 0x6330, 0x8086, 0xd61f, NULL,         NULL, NULL,           P3, "Intel",       "D201GLY",               0,   OK, wbsio_check_for_spi},
+	{0x8086, 0x27b8, 0x8086, 0xd606,  0x8086, 0x2770, 0x8086, 0xd606, "^D945GCNL$", NULL, NULL,           P2, "Intel",       "D945GCNL",              0,   OK, p2_not_a_laptop},
 	{0x8086, 0x7190,      0,      0,  0x8086, 0x7110,      0,      0, "^SE440BX-2$", NULL, NULL,          P3, "Intel",       "SE440BX-2",             0,   NT, intel_piix4_gpo27_lower},
 	{0x1022, 0x7468,      0,      0,  0x1022, 0x7460,      0,      0, NULL,         "iwill", "dk8_htx",   P3, "IWILL",       "DK8-HTX",               0,   OK, w83627hf_gpio24_raise_2e},
 	{0x8086, 0x27A0, 0x8086, 0x27a0,  0x8086, 0x27b8, 0x8086, 0x27b8, NULL,        "kontron", "986lcd-m", P3, "Kontron",     "986LCD-M",              0,   OK, board_kontron_986lcd_m},
diff --git a/chipset_enable.c b/chipset_enable.c
index 267008c..0dc1d7e 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -95,19 +95,20 @@
 
 static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name)
 {
+	#define SIS_MAPREG 0x40
 	uint8_t new, newer;
 
 	/* Extended BIOS enable = 1, Lower BIOS Enable = 1 */
 	/* This is 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */
-	new = pci_read_byte(dev, 0x40);
+	new = pci_read_byte(dev, SIS_MAPREG);
 	new &= (~0x04); /* No idea why we clear bit 2. */
 	new |= 0xb; /* 0x3 for some chipsets, bit 7 seems to be don't care. */
-	rpci_write_byte(dev, 0x40, new);
-	newer = pci_read_byte(dev, 0x40);
-	if (newer != new) {
-		msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-			  "(WARNING ONLY).\n", 0x40, new, name);
-		msg_pinfo("Stuck at 0x%x\n", newer);
+	rpci_write_byte(dev, SIS_MAPREG, new);
+	newer = pci_read_byte(dev, SIS_MAPREG);
+	if (newer != new) { /* FIXME: share this with other code? */
+		msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n",
+			  SIS_MAPREG, new, name);
+		msg_pinfo("Stuck at 0x%02x.\n", newer);
 		return -1;
 	}
 	return 0;
@@ -176,8 +177,9 @@
 	return ret;
 }
 
-static int enable_flash_sis530(struct pci_dev *dev, const char *name)
+static int enable_flash_sis5x0(struct pci_dev *dev, const char *name, uint8_t dis_mask, uint8_t en_mask)
 {
+	#define SIS_REG 0x45
 	uint8_t new, newer;
 	int ret = 0;
 	struct pci_dev *sbdev;
@@ -188,46 +190,28 @@
 
 	ret = enable_flash_sis_mapping(sbdev, name);
 
-	new = pci_read_byte(sbdev, 0x45);
-	new &= (~0x20);
-	new |= 0x4;
-	rpci_write_byte(sbdev, 0x45, new);
-	newer = pci_read_byte(sbdev, 0x45);
-	if (newer != new) {
-		msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-			  "(WARNING ONLY).\n", 0x45, new, name);
-		msg_pinfo("Stuck at 0x%x\n", newer);
+	new = pci_read_byte(sbdev, SIS_REG);
+	new &= (~dis_mask);
+	new |= en_mask;
+	rpci_write_byte(sbdev, SIS_REG, new);
+	newer = pci_read_byte(sbdev, SIS_REG);
+	if (newer != new) { /* FIXME: share this with other code? */
+		msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", SIS_REG, new, name);
+		msg_pinfo("Stuck at 0x%02x\n", newer);
 		ret = -1;
 	}
 
 	return ret;
 }
 
+static int enable_flash_sis530(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_sis5x0(dev, name, 0x20, 0x04);
+}
+
 static int enable_flash_sis540(struct pci_dev *dev, const char *name)
 {
-	uint8_t new, newer;
-	int ret = 0;
-	struct pci_dev *sbdev;
-
-	sbdev = find_southbridge(dev->vendor_id, name);
-	if (!sbdev)
-		return -1;
-
-	ret = enable_flash_sis_mapping(sbdev, name);
-
-	new = pci_read_byte(sbdev, 0x45);
-	new &= (~0x80);
-	new |= 0x40;
-	rpci_write_byte(sbdev, 0x45, new);
-	newer = pci_read_byte(sbdev, 0x45);
-	if (newer != new) {
-		msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-			  "(WARNING ONLY).\n", 0x45, new, name);
-		msg_pinfo("Stuck at 0x%x\n", newer);
-		ret = -1;
-	}
-
-	return ret;
+	return enable_flash_sis5x0(dev, name, 0x80, 0x40);
 }
 
 /* Datasheet:
@@ -268,9 +252,8 @@
 
 	rpci_write_word(dev, xbcs, new);
 
-	if (pci_read_word(dev, xbcs) != new) {
-		msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-			  "(WARNING ONLY).\n", xbcs, new, name);
+	if (pci_read_word(dev, xbcs) != new) { /* FIXME: share this with other code? */
+		msg_pinfo("Setting register 0x%04x to 0x%04x on %s failed (WARNING ONLY).\n", xbcs, new, name);
 		return -1;
 	}
 
@@ -678,8 +661,7 @@
 	rpci_write_byte(dev, 0x40, val);
 
 	if (pci_read_byte(dev, 0x40) != val) {
-		msg_pinfo("\nWARNING: Failed to enable flash write on \"%s\"\n",
-			  name);
+		msg_pinfo("\nWARNING: Failed to enable flash write on \"%s\"\n", name);
 		return -1;
 	}
 
@@ -851,15 +833,15 @@
 
 static int enable_flash_sc1100(struct pci_dev *dev, const char *name)
 {
+	#define SC_REG 0x52
 	uint8_t new;
 
-	rpci_write_byte(dev, 0x52, 0xee);
+	rpci_write_byte(dev, SC_REG, 0xee);
 
-	new = pci_read_byte(dev, 0x52);
+	new = pci_read_byte(dev, SC_REG);
 
-	if (new != 0xee) {
-		msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-			  "(WARNING ONLY).\n", 0x52, new, name);
+	if (new != 0xee) { /* FIXME: share this with other code? */
+		msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", SC_REG, new, name);
 		return -1;
 	}
 
@@ -869,29 +851,31 @@
 /* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */
 static int enable_flash_amd8111(struct pci_dev *dev, const char *name)
 {
+	#define AMD_MAPREG 0x43
+	#define AMD_ENREG 0x40
 	uint8_t old, new;
 
 	/* Enable decoding at 0xffb00000 to 0xffffffff. */
-	old = pci_read_byte(dev, 0x43);
+	old = pci_read_byte(dev, AMD_MAPREG);
 	new = old | 0xC0;
 	if (new != old) {
-		rpci_write_byte(dev, 0x43, new);
-		if (pci_read_byte(dev, 0x43) != new) {
-			msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-				  "(WARNING ONLY).\n", 0x43, new, name);
+		rpci_write_byte(dev, AMD_MAPREG, new);
+		if (pci_read_byte(dev, AMD_MAPREG) != new) {
+			msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n",
+				  AMD_MAPREG, new, name);
 		}
 	}
 
 	/* Enable 'ROM write' bit. */
-	old = pci_read_byte(dev, 0x40);
+	old = pci_read_byte(dev, AMD_ENREG);
 	new = old | 0x01;
 	if (new == old)
 		return 0;
-	rpci_write_byte(dev, 0x40, new);
+	rpci_write_byte(dev, AMD_ENREG, new);
 
-	if (pci_read_byte(dev, 0x40) != new) {
-		msg_pinfo("Setting register 0x%x to 0x%x on %s failed "
-			  "(WARNING ONLY).\n", 0x40, new, name);
+	if (pci_read_byte(dev, AMD_ENREG) != new) {
+		msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n",
+			  AMD_ENREG, new, name);
 		return -1;
 	}
 
@@ -1055,8 +1039,8 @@
 	new = old | 0xC0;
 	if (new != old) {
 		rpci_write_byte(dev, reg, new);
-		if (pci_read_byte(dev, reg) != new) {
-			msg_pinfo("Setting register 0x%02x to 0x%x on %s failed.\n", reg, new, name);
+		if (pci_read_byte(dev, reg) != new) { /* FIXME: share this with other code? */
+			msg_pinfo("Setting register 0x%02x to 0x%02x on %s failed.\n", reg, new, name);
 			err++;
 		}
 	}
@@ -1298,7 +1282,7 @@
 	{0x1039, 0x0645, NT, "SiS", "645",		enable_flash_sis540},
 	{0x1039, 0x0646, OK, "SiS", "645DX",		enable_flash_sis540},
 	{0x1039, 0x0648, NT, "SiS", "648",		enable_flash_sis540},
-	{0x1039, 0x0650, NT, "SiS", "650",		enable_flash_sis540},
+	{0x1039, 0x0650, OK, "SiS", "650",		enable_flash_sis540},
 	{0x1039, 0x0651, OK, "SiS", "651",		enable_flash_sis540},
 	{0x1039, 0x0655, NT, "SiS", "655",		enable_flash_sis540},
 	{0x1039, 0x0661, OK, "SiS", "661",		enable_flash_sis540},
@@ -1355,7 +1339,7 @@
 	{0x10de, 0x0442, NT, "NVIDIA", "MCP65",		enable_flash_mcp6x_7x},
 	{0x10de, 0x0443, NT, "NVIDIA", "MCP65",		enable_flash_mcp6x_7x},
 	{0x10de, 0x0548, OK, "NVIDIA", "MCP67",		enable_flash_mcp6x_7x},
-	{0x10de, 0x075c, NT, "NVIDIA", "MCP78S",	enable_flash_mcp6x_7x},
+	{0x10de, 0x075c, OK, "NVIDIA", "MCP78S",	enable_flash_mcp6x_7x},
 	{0x10de, 0x075d, OK, "NVIDIA", "MCP78S",	enable_flash_mcp6x_7x},
 	{0x10de, 0x07d7, OK, "NVIDIA", "MCP73",		enable_flash_mcp6x_7x},
 	{0x10de, 0x0aac, OK, "NVIDIA", "MCP79",		enable_flash_mcp6x_7x},
diff --git a/dediprog.c b/dediprog.c
index c2b66cc..e68fdf9 100644
--- a/dediprog.c
+++ b/dediprog.c
@@ -19,6 +19,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 #include <errno.h>
 #include <usb.h>
 #include "flash.h"
diff --git a/flashchips.c b/flashchips.c
index 9767c00..1c86677 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -1864,7 +1864,7 @@
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
-		.tested		= TEST_UNTESTED,
+		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
@@ -3598,7 +3598,7 @@
 		.total_size	= 8192,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
-		.tested		= TEST_OK_PR,
+		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
@@ -6832,14 +6832,14 @@
 
 	{
 		.vendor		= "Spansion",
-		.name		= "S25FL032A",
+		.name		= "S25FL032A/P",
 		.bustype	= BUS_SPI,
 		.manufacture_id	= SPANSION_ID,
 		.model_id	= SPANSION_S25FL032A,
 		.total_size	= 4096,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
-		.tested		= TEST_OK_PR,
+		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
@@ -6861,7 +6861,7 @@
 
 	{
 		.vendor		= "Spansion",
-		.name		= "S25FL064A",
+		.name		= "S25FL064A/P",
 		.bustype	= BUS_SPI,
 		.manufacture_id	= SPANSION_ID,
 		.model_id	= SPANSION_S25FL064A,
@@ -6922,13 +6922,13 @@
 
 	{
 		.vendor		= "SST",
-		.name		= "SST25LF080A",
+		.name		= "SST25LF080(A)",
 		.bustype	= BUS_SPI,
 		.manufacture_id	= SST_ID,
 		.model_id	= SST_SST25VF080_REMS,
 		.total_size	= 1024,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_WRSR_EWSR,
+		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_res2,
 		.probe_timing	= TIMING_ZERO,
@@ -6992,7 +6992,7 @@
 		.model_id	= SST_SST25VF016B,
 		.total_size	= 2048,
 		.page_size	= 256,
-		.feature_bits	= FEATURE_WRSR_EWSR,
+		.feature_bits	= FEATURE_WRSR_EITHER,
 		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -8659,7 +8659,7 @@
 		.total_size	= 256,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
-		.tested		= TEST_UNTESTED,
+		.tested		= TEST_OK_PREW,
 		.probe		= probe_jedec,
 		.probe_timing	= TIMING_ZERO,	/* Datasheet has no timing info specified */
 		.block_erasers	=
@@ -9600,7 +9600,7 @@
 		.total_size	= 128,
 		.page_size	= 256,
 		.feature_bits	= FEATURE_WRSR_WREN,
-		.tested		= TEST_UNTESTED,
+		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
diff --git a/flashchips.h b/flashchips.h
index 82ed4a7..99e37d5 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -483,8 +483,8 @@
 #define SPANSION_S25FL004A	0x0212
 #define SPANSION_S25FL008A	0x0213
 #define SPANSION_S25FL016A	0x0214
-#define SPANSION_S25FL032A	0x0215
-#define SPANSION_S25FL064A	0x0216
+#define SPANSION_S25FL032A	0x0215	/* Same as S25FL032P, but the latter supports EDI and CFI */
+#define SPANSION_S25FL064A	0x0216	/* Same as S25FL064P, but the latter supports EDI and CFI */
 
 /*
  * SST25 chips are SPI, first byte of device ID is memory type, second
diff --git a/flashrom.8 b/flashrom.8
index bb481c7..102bd62 100644
--- a/flashrom.8
+++ b/flashrom.8
@@ -34,7 +34,9 @@
 in probe-only mode and check the output. Also you are advised to make a
 backup of your current ROM contents with
 .B \-r
-before you try to write a new image.
+before you try to write a new image. All operations involving any chip access (probe/read/write/...) require the
+.B -p/--programmer
+option to be used (please see below).
 .TP
 .B "\-r, \-\-read <file>"
 Read flash ROM contents and save them into the given
@@ -128,7 +130,7 @@
 .sp
 .B "  flashrom \-p prog \-\-layout rom.layout \-\-image normal \-w some.rom"
 .sp
-To update only the images named 
+To update only the images named
 .BR "normal " "and " "fallback" ", run:"
 .sp
 .B "  flashrom \-p prog \-l rom.layout \-i normal -i fallback \-w some.rom"
@@ -694,11 +696,11 @@
 .BR "pony_spi " programmer
 The serial port (like /dev/ttyS0, /dev/ttyUSB0 on Linux or COM3 on windows) is
 specified using the mandatory
-.B dev 
+.B dev
 parameter. The adapter type is selectable between SI-Prog (used for
 SPI devices with PonyProg 2000) or a custom made serial bitbanging programmer
 named "serbang". The optional
-.B type 
+.B type
 parameter accepts the values "si_prog" (default) or "serbang".
 .sp
 Information about the SI-Prog adapter can be found at
@@ -724,7 +726,7 @@
 .B cprom
 or
 .B s3
-for the configuration ROM and 
+for the configuration ROM and
 .B bprom
 or
 .B bios
@@ -733,7 +735,7 @@
 you want to use with the
 .B pci=
 parameter as explained in the
-.B nic3com et al.\& 
+.B nic3com et al.\&
 section above.
 .sp
 More information about the hardware is available at
diff --git a/flashrom.c b/flashrom.c
index fd438bb..d89860a 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -397,7 +397,10 @@
 		int i = --shutdown_fn_count;
 		ret |= shutdown_fn[i].func(shutdown_fn[i].data);
 	}
+
 	programmer_param = NULL;
+	registered_programmer_count = 0;
+
 	return ret;
 }
 
diff --git a/print.c b/print.c
index 85d5ab2..df3f17f 100644
--- a/print.c
+++ b/print.c
@@ -517,15 +517,19 @@
 	B("abit",	"NF7-S",		OK, NULL, NULL),
 	B("abit",	"VA6",			OK, NULL, NULL),
 	B("abit",	"VT6X4",		OK, NULL, NULL),
+	B("Acer",	"V75-M",		OK, NULL, "This is an OEM board used by IBM in e.g. Aptiva 2170-G"),
 	B("Acorp",	"6A815EPD",		OK, "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp", NULL),
 	B("Advantech",	"PCM-5820",		OK, "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm", NULL),
 	B("agami",	"Aruma",		OK, "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series", NULL),
 	B("Albatron",	"PM266A Pro",		OK, "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56", NULL), /* FIXME */
+	B("Alienware",	"Aurora-R2",		BAD, NULL, "Mainboard model is 0RV30W. Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("AOpen",	"i945GMx-VFX",		OK, NULL, "This is (also?) an OEM board from FSC (used in e.g. ESPRIMO Q5010 with designation D2544-B1)."),
 	B("AOpen",	"vKM400Am-S",		OK, "http://usa.aopen.com/products_detail.aspx?Auno=824", NULL),
 	B("Artec Group","DBE61",		OK, "http://wiki.thincan.org/DBE61", NULL),
 	B("Artec Group","DBE62",		OK, "http://wiki.thincan.org/DBE62", NULL),
 	B("ASI",	"MB-5BLMP",		OK, "http://www.hojerteknik.com/winnet.htm", "Used in the IGEL WinNET III thin client."),
+	B("ASRock",	"4CoreDual-VSTA",	OK, "http://www.asrock.com/mb/overview.asp?Model=4CoreDual-VSTA", "W39V040FB"),
+	B("ASRock",	"775Dual-VSTA",		OK, "http://www.asrock.com/mb/overview.asp?Model=775Dual-VSTA", NULL),
 	B("ASRock",	"775i65G",		OK, "http://www.asrock.com/mb/overview.asp?Model=775i65G", NULL),
 	B("ASRock",	"880G Pro3",		OK, "http://www.asrock.com/mb/overview.asp?Model=880G%20Pro3", NULL),
 	B("ASRock",	"890GX Extreme3",	OK, "http://www.asrock.com/mb/overview.asp?Model=890GX%20Extreme3", NULL),
@@ -535,6 +539,7 @@
 	B("ASRock",	"A780FullHD",		OK, "http://www.asrock.com/mb/overview.asp?Model=A780FullHD", "While flashrom is working correctly, there might be problems with the firmware images themselves. Please see http://www.flashrom.org/pipermail/flashrom/2012-July/009600.html for details."),
 	B("ASRock",	"ALiveNF6G-DVI",	OK, "http://www.asrock.com/mb/overview.asp?Model=ALiveNF6G-DVI", NULL),
 	B("ASRock",	"AM2NF6G-VSTA",		OK, "http://www.asrock.com/mb/overview.asp?Model=AM2NF6G-VSTA", NULL),
+	B("ASRock",	"E350M1/USB3",		OK, "http://www.asrock.com/mb/overview.asp?model=e350m1/usb3", NULL),
 	B("ASRock",	"ConRoeXFire-eSATA2",	OK, "http://www.asrock.com/mb/overview.asp?model=conroexfire-esata2", NULL),
 	B("ASRock",	"H61M-ITX",		BAD, "http://www.asrock.com/mb/overview.asp?Model=H61M-ITX", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("ASRock",	"H67M",			BAD, "http://www.asrock.com/mb/overview.asp?Model=H67M", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
@@ -636,6 +641,7 @@
 	B("ASUS",	"P5A",			OK, NULL, NULL),
 	B("ASUS",	"P5B",			OK, NULL, NULL),
 	B("ASUS",	"P5B-Deluxe",		OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5B_Deluxe/", NULL),
+	B("ASUS",	"P5B-VM",		OK, NULL, NULL),
 	B("ASUS",	"P5BV-M",		BAD, NULL, "Reported by Bernhard M. Wiedemann <bernhard@uml12d.zq1.de> to flashrom@coreboot.org, no public archive. Missing board enable and/or SST49LF008A unlocking. May work now."),
 	B("ASUS",	"P5BV-R",		OK, "http://www.asus.com/Server_Workstation/Servers/RS120E5PA2/", "Used in RS120-E5/PA2 servers."),
 	B("ASUS",	"P5GC-MX/1333",		OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5GCMX1333/", NULL),
@@ -684,6 +690,7 @@
 	B("ASUS",	"P8Z68-V PRO",		BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("ASUS",	"P8Z68-V PRO/GEN3",	OK, "http://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V_PROGEN3/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
 	B("ASUS",	"SABERTOOTH 990FX",	OK, "http://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX/", NULL),
+	B("ASUS",	"SABERTOOTH 990FX R2.0", OK, "http://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX_R20/", NULL),
 	B("ASUS",	"CUSL2-C",		OK, NULL, "The image provided by ASUS is only 256 kB big and has to be written to the upper 256 kB of the 512 kB chip."),
 	B("ASUS",	"TUSL2-C",		NT, "http://support.asus.com/download.aspx?SLanguage=en&p=1&s=4&m=TUSL2-C&os=&hashedid=n/a", "Untested board enable."),
 	B("ASUS",	"Z8NA-D6C",		OK, "http://www.asus.com/Server_Workstation/Server_Motherboards/Z8NAD6C/", NULL),
@@ -691,6 +698,7 @@
 	B("Bachmann",	"OT200",		OK, "http://www.bachmann.info/produkte/bedien-und-beobachtungsgeraete/operator-terminals/", NULL),
 	B("BCOM",	"WinNET100",		OK, "http://www.coreboot.org/BCOM_WINNET100", "Used in the IGEL-316 thin client."),
 	B("Bifferos",	"Bifferboard",		OK, "http://bifferos.co.uk/", NULL),
+	B("Biostar",	"H61MGC",		BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("Biostar",	"H61MU3",		BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("Biostar",	"M6TBA",		BAD, "ftp://ftp.biostar-usa.com/manuals/M6TBA/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
 	B("Biostar",	"M7NCD Pro",		OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=260", NULL),
@@ -703,6 +711,7 @@
 	B("Boser",	"HS-6637",		BAD, "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf", "Reported by Mark Robinson <mark@zl2tod.net> to flashrom@coreboot.org, no public archive. Missing board enable and/or F29C51002T unlocking. May work now."),
 	B("Congatec",	"conga-X852",		OK, "http://www.congatec.com/single_news+M57715f6263d.html?&L=1", NULL),
 	B("Dell",	"Inspiron 580",		BAD, "http://support.dell.com/support/edocs/systems/insp580/en/index.htm", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+	B("Dell",	"OptiPlex 7010",	BAD, NULL, "Mainboard model is 0KRC95. Probing works (Hardware Sequencing 4 + 8MB), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
 	B("Dell",	"OptiPlex GX1",		OK, "http://support.dell.com/support/edocs/systems/ban_gx1/en/index.htm", NULL),
 	B("Dell",	"PowerEdge 1850",	OK, "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm", NULL),
 	B("Dell",	"PowerEdge C6220",	BAD, NULL, "Mainboard model is 0HYFFG. Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and there are even overlapping PRs)."),
@@ -730,6 +739,7 @@
 	B("EPoX",	"EP-8RDA3+",		OK, "http://www.epox.com/product.asp?ID=EP-8RDA3plus", NULL),
 	B("EPoX",	"EP-9NPA7I",		OK, "http://www.epox.com/product.asp?ID=EP-9NPA7I", NULL),
 	B("EPoX",	"EP-BX3",		OK, "http://www.epox.com/product.asp?ID=EP-BX3", NULL),
+	B("EVGA",	"122-CK-NF68",		OK, NULL, NULL),
 	B("EVGA",	"132-CK-NF78",		OK, "http://www.evga.com/articles/385.asp", NULL),
 	B("EVGA",	"270-WS-W555-A2 (Classified SR-2)", OK, "http://www.evga.com/products/moreInfo.asp?pn=270-WS-W555-A2", NULL),
 	B("FIC",	"VA-502",		BAD, "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. Seems the PCI subsystem IDs are identical with the Tekram P6Pro-A5. May work now."),
@@ -747,7 +757,6 @@
 	B("GIGABYTE",	"GA-6IEM",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1379", NULL),
 	B("GIGABYTE",	"GA-6VXE7+",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2410", NULL),
 	B("GIGABYTE",	"GA-6ZMA",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1541", NULL),
-	B("GIGABYTE",	"GA-MA785GMT-UD2H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3156", NULL),
 	B("GIGABYTE",	"GA-770TA-UD3",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3272", NULL),
 	B("GIGABYTE",	"GA-7DXR",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1302", NULL),
 	B("GIGABYTE",	"GA-7VT600",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1666", NULL),
@@ -761,6 +770,7 @@
 	B("GIGABYTE",	"GA-945PL-S3P (rev. 6.6)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2541", NULL),
 	B("GIGABYTE",	"GA-965GM-S2 (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2617", NULL),
 	B("GIGABYTE",	"GA-965P-DS4",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2288", NULL),
+	B("GIGABYTE",	"GA-A75M-UD2H",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3928", NULL),
 	B("GIGABYTE",	"GA-EP31-DS3L (rev. 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2964", NULL),
 	B("GIGABYTE",	"GA-EP35-DS3L",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2778", NULL),
 	B("GIGABYTE",	"GA-G41MT-S2PT",	OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3960", NULL),
@@ -780,6 +790,7 @@
 	B("GIGABYTE",	"GA-MA770-UD3 (rev. 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3302", NULL),
 	B("GIGABYTE",	"GA-MA770T-UD3P",	OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3096", NULL),
 	B("GIGABYTE",	"GA-MA780G-UD3H",	OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3004", NULL),
+	B("GIGABYTE",	"GA-MA785GMT-UD2H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3156", NULL),
 	B("GIGABYTE",	"GA-MA78G-DS3H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2800", NULL),
 	B("GIGABYTE",	"GA-MA78GM-S2H",	OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2758", NULL), /* TODO: Rev. 1.BAD, 1.OK, or 2.x? */
 	B("GIGABYTE",	"GA-MA78GPM-DS2H",	OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2859", NULL),
@@ -788,8 +799,8 @@
 	B("GIGABYTE",	"GA-MA790XT-UD4P (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3010", NULL),
 	B("GIGABYTE",	"GA-P55A-UD4 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3436", NULL),
 	B("GIGABYTE",	"GA-P67A-UD3P",		OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3649", NULL),
+	B("GIGABYTE",	"GA-X58A-UD3R (rev. 2.0)", OK, NULL, NULL),
 	B("GIGABYTE",	"GA-X58A-UD7 (rev. 2.0)", OK, NULL, NULL),
-	B("GIGABYTE",	"GA-X58A-UDR3 (rev. 2.0)", OK, NULL, NULL),
 	B("GIGABYTE",	"GA-X79-UD5", OK, NULL, NULL),
 	B("GIGABYTE",	"GA-Z68MX-UD2H-B (rev. 1.3)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3854", NULL),
 	B("GIGABYTE",	"GA-Z68XP-UD3 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3892", NULL),
@@ -813,11 +824,13 @@
 	B("Intel",	"D201GLY",		OK, "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm", NULL),
 	B("Intel",	"D425KT",		BAD, "http://www.intel.com/content/www/us/en/motherboards/desktop-motherboards/desktop-board-d425kt.html", "NM10 with SPI lock down, BIOS lock, see http://www.flashrom.org/pipermail/flashrom/2012-January/008600.html"),
 	B("Intel",	"D865GLC",		BAD, NULL, "ICH5 with BIOS lock enable, see http://paste.flashrom.org/view.php?id=775"),
+	B("Intel",	"D945GCNL",		OK, NULL, NULL),
 	B("Intel",	"DG45ID",		BAD, "http://www.intel.com/products/desktop/motherboards/dg45id/dg45id-overview.htm", "Probing works (Winbond W25x32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
 	B("Intel",	"DQ965GF",		BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF016B, 2048 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
 	B("Intel",	"DG965OT",		BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF080B, 1024 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
 	B("Intel",	"DH61AG ",		BAD, NULL, "H61 with BIOS lock enable and locked ME region, see http://www.flashrom.org/pipermail/flashrom/2012-June/009417.html"),
 	B("Intel",	"DH67CF",		BAD, NULL, "H67 with BIOS lock enable and locked ME region, see http://www.flashrom.org/pipermail/flashrom/2011-September/007789.html"),
+	B("Intel",	"DH67CL",		BAD, NULL, "H67 with BIOS lock enable and locked ME region, see http://www.flashrom.org/pipermail/flashrom/2012-November/010112.html"),
 	B("Intel",	"DN2800MT (Marshalltown)", BAD, NULL, "BIOS locked via BIOS_CNTL."),
 	B("Intel",	"EP80759",		OK, NULL, NULL),
 	B("Intel",	"Foxhollow",		OK, NULL, "Intel reference board."),
@@ -865,6 +878,7 @@
 	B("MSI",	"MS-7309 (K9N6PGM2-V2)", OK, "http://www.msi.com/product/mb/K9N6PGM2-V2.html", NULL),
 	B("MSI",	"MS-7312 (K9MM-V)",	OK, "http://www.msi.com/product/mb/K9MM-V.html", NULL),
 	B("MSI",	"MS-7345 (P35 Neo2-FIR)", OK, "http://www.msi.com/product/mb/P35-Neo2-FR---FIR.html", NULL),
+	B("MSI",	"MS-7357 (G33M)", 	OK, "http://www.msi.com/product/mb/G33M.html", NULL),
 	B("MSI",	"MS-7368 (K9AG Neo2-Digital)", OK, "http://www.msi.com/product/mb/K9AG-Neo2-Digital.html", NULL),
 	B("MSI",	"MS-7369 (K9N Neo V2)", OK, "http://www.msi.com/product/mb/K9N-Neo-V2.html", NULL),
 	B("MSI",	"MS-7376 (K9A2 Platinum V1)", OK, "http://www.msi.com/product/mb/K9A2-Platinum.html", NULL),
@@ -903,6 +917,7 @@
 	B("Shuttle",	"AK38N",		OK, "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/", NULL),
 	B("Shuttle",	"AV11V30",		OK, NULL, NULL),
 	B("Shuttle",	"AV18E2",		OK, "http://www.shuttle.eu/_archive/older/de/av18.htm", NULL),
+	B("Shuttle",	"FB61",			OK, "http://www.shuttle.eu/_archive/older/en/fb61.htm#mainboardfb6", "Used in SB61G2 systems."),
 	B("Shuttle",	"FD37",			OK, "http://www.shuttle.eu/products/discontinued/barebones/sd37p2/", NULL),
 	B("Shuttle",	"FH67",			OK, "http://www.shuttle.eu/products/mini-pc/sh67h3/specification/", NULL),
 	B("Shuttle",	"FN25",			OK, "http://www.shuttle.eu/products/discontinued/barebones/sn25p/?0=", NULL),
@@ -931,6 +946,8 @@
 	B("Supermicro",	"X8SIE(-F)",		BAD, "http://www.supermicro.com/products/motherboard/Xeon3000/3400/X8SIE.cfm?IPMI=N&TYP=LN2", "Requires unlocking the ME although the registers are set up correctly by the descriptor/BIOS already (tested with swseq and hwseq)."),
 	B("Supermicro",	"X8STi",		OK, "http://www.supermicro.com/products/motherboard/Xeon3000/X58/X8STi.cfm", NULL),
 	B("Supermicro",	"X9DR3-F",		BAD, "http://www.supermicro.com/products/motherboard/xeon/c600/x9dr3-f.cfm", "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+	B("Supermicro",	"X9DRT-HF+",		BAD, NULL, "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
+	B("Supermicro",	"X9DRW",		BAD, NULL, "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("Supermicro",	"X9QRi-F+",		BAD, "http://www.supermicro.com/products/motherboard/Xeon/C600/X9QRi-F_.cfm", "Probing works (Macronix MX25L12805, 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
 	B("Supermicro",	"X9SCA-F",		BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCA-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
 	B("Supermicro",	"X9SCL",		BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCL.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
@@ -957,6 +974,7 @@
 	B("Tyan",	"S2933 (Thunder n3600S)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=478&SKU=600000063", NULL),
 	B("Tyan",	"S3095 (Tomcat i945GM)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=181", NULL),
 	B("Tyan",	"S3992 (Thunder h2000M)", OK, "http://tyan.com/product_board_detail.aspx?pid=235", NULL),
+	B("Tyan",	"S4882 (Thunder K8QS Pro)", OK, "http://www.tyan.com/archive/products/html/thunderk8qspro.html", NULL),
 	B("Tyan",	"S5180 (Toledo i965R)",	OK, "http://www.tyan.com/product_board_detail.aspx?pid=456", NULL),
 	B("Tyan",	"S5191 (Toledo i3000R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=343", NULL),
 	B("Tyan",	"S5197 (Toledo i3010W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=349", NULL),
@@ -1008,6 +1026,8 @@
 	B("Dell",	"Latitude CPi A366XT",	BAD, "http://www.coreboot.org/Dell_Latitude_CPi_A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop."),
 	B("Dell",	"Vostro 3700",		BAD, NULL, "Locked ME, see http://www.flashrom.org/pipermail/flashrom/2012-May/009197.html."),
 	B("Dell",	"Latitude E6520",	BAD, NULL, "Locked ME, see http://www.flashrom.org/pipermail/flashrom/2012-June/009420.html."),
+	B("Elitegroup",	"A928",			OK, NULL, "Bootsector is locked and needs to be skipped with a layout file (writeable address range is 00000000:0003bfff"),
+	B("HP/Compaq",	"EliteBook 8560p",	BAD, NULL, "SPI lock down, SMM protection, PR in BIOS region, read-only descriptor, locked ME region."),
 	B("HP/Compaq",	"nx9005",		BAD, "http://h18000.www1.hp.com/products/quickspecs/11602_na/11602_na.HTML", "Shuts down when probing for a chip. http://www.flashrom.org/pipermail/flashrom/2010-May/003321.html"),
 	B("HP/Compaq",	"nx9010",		BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)."),
 	B("IBM/Lenovo",	"Thinkpad T40p",	BAD, "http://www.thinkwiki.org/wiki/Category:T40p", NULL),
diff --git a/serprog.c b/serprog.c
index 98c839e..e5ac62b 100644
--- a/serprog.c
+++ b/serprog.c
@@ -223,7 +223,7 @@
 {
 	if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) {
 		msg_pdbg("Warning: Automatic command availability check failed "
-			 "for cmd 0x%x - won't execute cmd\n", cmd);
+			 "for cmd 0x%02x - won't execute cmd\n", cmd);
 		return 1;
 		}
 	return 0;
@@ -522,6 +522,7 @@
 			f_spi_req = strtol(spispeed, &f_spi_suffix, 0);
 			if (errno != 0 || spispeed == f_spi_suffix) {
 				msg_perr("Error: Could not convert 'spispeed'.\n");
+				free(spispeed);
 				return 1;
 			}
 			if (strlen(f_spi_suffix) == 1) {
@@ -531,10 +532,12 @@
 					f_spi_req *= 1000;
 				else {
 					msg_perr("Error: Garbage following 'spispeed' value.\n");
+					free(spispeed);
 					return 1;
 				}
 			} else if (strlen(f_spi_suffix) > 1) {
 				msg_perr("Error: Garbage following 'spispeed' value.\n");
+				free(spispeed);
 				return 1;
 			}