Index: flash.h
===================================================================
--- flash.h	(revision 906)
+++ flash.h	(working copy)
@@ -200,18 +200,20 @@
 	 */
 	struct block_eraser {
 		struct eraseblock{
 			unsigned int size; /* Eraseblock size */
 			unsigned int count; /* Number of contiguous blocks with that size */
 		} eraseblocks[NUM_ERASEREGIONS];
 		int (*block_erase) (struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen);
 	} block_erasers[NUM_ERASEFUNCTIONS];
 
+	int (*printlock) (struct flashchip *flash);
+	int (*unlock) (struct flashchip *flash);
 	int (*write) (struct flashchip *flash, uint8_t *buf);
 	int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len);
 
 	/* Some flash devices have an additional register space. */
 	chipaddr virtual_memory;
 	chipaddr virtual_registers;
 };
 
 #define TEST_UNTESTED	0
Index: sst49lfxxxc.c
===================================================================
--- sst49lfxxxc.c	(revision 906)
+++ sst49lfxxxc.c	(working copy)
@@ -76,18 +76,23 @@
 	address += 8192;
 	printf_debug("lockbits at address=0x%08lx is 0x%01x\n",
 		     registers + address + 2,
 		     chip_readb(registers + address + 2));
 	chip_writeb(bits, registers + address + 2);
 
 	return 0;
 }
 
+int unlock_49lfxxxc(struct flashchip *flash)
+{
+	return write_lockbits_49lfxxxc(flash, 0);
+}
+
 int erase_sector_49lfxxxc(struct flashchip *flash, unsigned int address, unsigned int sector_size)
 {
 	unsigned char status;
 	chipaddr bios = flash->virtual_memory;
 
 	chip_writeb(SECTOR_ERASE, bios);
 	chip_writeb(ERASE, bios + address);
 
 	do {
Index: Makefile
===================================================================
--- Makefile	(revision 906)
+++ Makefile	(working copy)
@@ -35,19 +35,19 @@
 ifeq ($(OS_ARCH), Darwin)
 CPPFLAGS += -I/opt/local/include -I/usr/local/include
 LDFLAGS += -framework IOKit -framework DirectIO -L/opt/local/lib -L/usr/local/lib
 endif
 ifeq ($(OS_ARCH), FreeBSD)
 CPPFLAGS += -I/usr/local/include
 LDFLAGS += -L/usr/local/lib
 endif
 
-CHIP_OBJS = jedec.o stm50flw0x0x.o w39v080fa.o sharplhf00l04.o w29ee011.o \
+CHIP_OBJS = jedec.o stm50flw0x0x.o w39v040c.o w39v080fa.o sharplhf00l04.o w29ee011.o \
 	sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \
 	sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o
 
 LIB_OBJS = layout.o
 
 CLI_OBJS = flashrom.o cli_classic.o cli_output.o print.o
 
 PROGRAMMER_OBJS = udelay.o programmer.o
 
Index: w39v040c.c
===================================================================
--- w39v040c.c	(revision 906)
+++ w39v040c.c	(working copy)
@@ -44,18 +44,44 @@
 	programmer_delay(10);
 	chip_writeb(0xF0, bios + 0x5555);
 	programmer_delay(40);
 
 	printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n",
 		__func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un");
 	return 1;
 }
 
+int printlock_w39v040c(struct flashchip *flash)
+{
+	chipaddr bios = flash->virtual_memory;
+	uint8_t lock;
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0x90, bios + 0x5555);
+	programmer_delay(10);
+
+	lock = chip_readb(bios + 0xfff2);
+
+	chip_writeb(0xAA, bios + 0x5555);
+	programmer_delay(10);
+	chip_writeb(0x55, bios + 0x2AAA);
+	programmer_delay(10);
+	chip_writeb(0xF0, bios + 0x5555);
+	programmer_delay(40);
+
+	printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n",
+		__func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un");
+	return 0;
+}
+
 int erase_w39v040c(struct flashchip *flash)
 {
 	int i;
 	unsigned int total_size = flash->total_size * 1024;
 
 	for (i = 0; i < total_size; i += flash->page_size) {
 		if (erase_sector_jedec(flash, i, flash->page_size)) {
 			fprintf(stderr, "ERASE FAILED!\n");
 			return -1;
Index: pm49fl00x.c
===================================================================
--- pm49fl00x.c	(revision 906)
+++ pm49fl00x.c	(working copy)
@@ -30,18 +30,24 @@
 	for (i = 0; left >= block_size; i++, left -= block_size) {
 		/* pm49fl002 */
 		if (block_size == 16384 && i % 2)
 			continue;
 
 		chip_writeb(bits, bios + (i * block_size) + 2);
 	}
 }
 
+int unlock_49fl00x(struct flashchip *flash)
+{
+	write_lockbits_49fl00x(flash->virtual_registers, flash->total_size * 1024, 0, flash->page_size);
+	return 0;
+}
+
 int erase_49fl00x(struct flashchip *flash)
 {
 	int i;
 	int total_size = flash->total_size * 1024;
 	int page_size = flash->page_size;
 
 	/* unprotected */
 	write_lockbits_49fl00x(flash->virtual_registers,
 			       total_size, 0, page_size);
Index: flashchips.c
===================================================================
--- flashchips.c	(revision 906)
+++ flashchips.c	(working copy)
@@ -43,18 +43,20 @@
 	 * .page_size		= Page or eraseblock(?) size in bytes
 	 * .tested		= Test status
 	 * .probe		= Probe function
 	 * .probe_timing	= Probe function delay
 	 * .block_erasers[]	= Array of erase layouts and erase functions
 	 * {
 	 *	.eraseblocks[]	= Array of { blocksize, blockcount }
 	 *	.block_erase	= Block erase function
 	 * }
+	 * .printstatus		= Chip lock status function
+	 * .unlock		= Chip unlock function
 	 * .write		= Chip write function
 	 * .read		= Chip read function
 	 */
 
 	{
 		.vendor		= "AMD",
 		.name		= "Am29F010A/B",
 		.bustype	= CHIP_BUSTYPE_PARALLEL,
 		.manufacture_id	= AMD_ID,
@@ -3324,62 +3326,62 @@
 		.bustype	= CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, /* A/A Mux*/
 		.manufacture_id	= PMC_ID_NOPREFIX,
 		.model_id	= PMC_49FL002,
 		.total_size	= 256,
 		.page_size	= 16 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_jedec,
 		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
-		/* .erase	= NULL, Was: erase_49fl00x */
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {4 * 1024, 64} },
 				.block_erase = erase_sector_jedec,
 			}, {
 				.eraseblocks = { {16 * 1024, 16} },
 				.block_erase = erase_block_jedec,
 			}, {
 				.eraseblocks = { {256 * 1024, 1} },
 				.block_erase = erase_chip_block_jedec,
 			}
 		},
+		.unlock		= unlock_49fl00x,
 		.write		= write_49fl00x,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "PMC",
 		.name		= "Pm49FL004",
 		.bustype	= CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, /* A/A Mux*/
 		.manufacture_id	= PMC_ID_NOPREFIX,
 		.model_id	= PMC_49FL004,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_jedec,
 		.probe_timing	= TIMING_ZERO,	/* routine is wrapper to probe_jedec (pm49fl00x.c) */
-		/* .erase	= NULL, Was: erase_49fl00x */
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {4 * 1024, 128} },
 				.block_erase = erase_sector_jedec,
 			}, {
 				.eraseblocks = { {64 * 1024, 8} },
 				.block_erase = erase_block_jedec,
 			}, {
 				.eraseblocks = { {512 * 1024, 1} },
 				.block_erase = erase_chip_block_jedec,
 			}
 		},
+		.unlock		= unlock_49fl00x,
 		.write		= write_49fl00x,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "Sanyo",
 		.name		= "LF25FW203A",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= SANYO_ID,
@@ -4400,34 +4402,34 @@
 		.bustype	= CHIP_BUSTYPE_LPC,
 		.manufacture_id	= SST_ID,
 		.model_id	= SST_49LF160C,
 		.total_size	= 2048,
 		.page_size	= 4 * 1024,
 		.feature_bits	= 0,
 		.tested		= TEST_OK_PRW,
 		.probe		= probe_49lfxxxc,
 		.probe_timing	= TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */
-		/* .erase	= NULL, Was: erase_49flxxxc */
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {4 * 1024, 512} },
 				.block_erase = erase_sector_49lfxxxc,
 			}, {
 				.eraseblocks = { 
 					{64 * 1024, 31},
 					{32 * 1024, 1},
 					{8 * 1024, 2},
 					{16 * 1024, 1},
 				},
 				.block_erase = erase_block_49lfxxxc,
 			}
 		},
+		.unlock		= unlock_49lfxxxc,
 		.write		= write_49lfxxxc,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "ST",
 		.name		= "M25P05-A",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= ST_ID,
@@ -5734,29 +5736,29 @@
 		.bustype	= CHIP_BUSTYPE_LPC,
 		.manufacture_id	= WINBOND_ID,
 		.model_id	= W_39V040C,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_jedec,
 		.probe_timing	= TIMING_FIXME,
-		/* .erase	= NULL, Was erase_w39v040c */
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {64 * 1024, 8} },
 				.block_erase = erase_sector_jedec,
 			}, {
 				.eraseblocks = { {512 * 1024, 1} },
 				.block_erase = erase_chip_block_jedec,
 			}
 		},
+		.printlock	= printlock_w39v040c,
 		.write		= write_jedec_1,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "Winbond",
 		.name		= "W39V040FA",
 		.bustype	= CHIP_BUSTYPE_FWH,
 		.manufacture_id	= WINBOND_ID,
@@ -5909,56 +5911,56 @@
 		.bustype	= CHIP_BUSTYPE_FWH,
 		.manufacture_id	= WINBOND_ID,
 		.model_id	= W_39V080FA,
 		.total_size	= 1024,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_jedec,
 		.probe_timing	= TIMING_FIXME,
-		/* .erase	= NULL, Was erase_winbond_fwhub */
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {64 * 1024, 16}, },
 				.block_erase = erase_sector_jedec,
 			}, {
 				.eraseblocks = { {1024 * 1024, 1} },
 				.block_erase = erase_chip_block_jedec,
 			}
 		},
+		.unlock		= unlock_winbond_fwhub,
 		.write		= write_jedec_1,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "Winbond",
 		.name		= "W39V080FA (dual mode)",
 		.bustype	= CHIP_BUSTYPE_FWH,
 		.manufacture_id	= WINBOND_ID,
 		.model_id	= W_39V080FA_DM,
 		.total_size	= 512,
 		.page_size	= 64 * 1024,
 		.feature_bits	= FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_jedec,
 		.probe_timing	= TIMING_FIXME,
-		/* .erase	= NULL, Was erase_winbond_fwhub */
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {64 * 1024, 8}, },
 				.block_erase = erase_sector_jedec,
 			}, {
 				.eraseblocks = { {512 * 1024, 1} },
 				.block_erase = erase_chip_block_jedec,
 			}
 		},
+		.unlock		= unlock_winbond_fwhub,
 		.write		= write_jedec_1,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "Atmel",
 		.name		= "unknown Atmel SPI chip",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= ATMEL_ID,
Index: flashrom.c
===================================================================
--- flashrom.c	(revision 906)
+++ flashrom.c	(working copy)
@@ -832,18 +832,19 @@
 	}
 
 	if (!flash || !flash->name)
 		return NULL;
 
 	printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n",
 	       flash->vendor, flash->name, flash->total_size,
 	       flashbuses_to_text(flash->bustype), base);
 
+	flash->printlock(flash);
 	return flash;
 }
 
 int verify_flash(struct flashchip *flash, uint8_t *buf)
 {
 	int ret;
 	int total_size = flash->total_size * 1024;
 
 	printf("Verifying flash... ");
@@ -1141,31 +1142,37 @@
 			fprintf(stderr, "Erase is not working on this chip. ");
 			if (!force) {
 				fprintf(stderr, "Aborting.\n");
 				programmer_shutdown();
 				return 1;
 			} else {
 				fprintf(stderr, "Continuing anyway.\n");
 			}
 		}
+		flash->unlock(flash);
+
 		if (erase_flash(flash)) {
 			emergency_help_message();
 			programmer_shutdown();
 			return 1;
 		}
 	} else if (read_it) {
+		flash->unlock(flash);
+
 		if (read_flash(flash, filename)) {
 			programmer_shutdown();
 			return 1;
 		}
 	} else {
 		struct stat image_stat;
 
+		flash->unlock(flash);
+
 		if (flash->tested & TEST_BAD_ERASE) {
 			fprintf(stderr, "Erase is not working on this chip "
 				"and erase is needed for write. ");
 			if (!force) {
 				fprintf(stderr, "Aborting.\n");
 				programmer_shutdown();
 				return 1;
 			} else {
 				fprintf(stderr, "Continuing anyway.\n");
Index: chipdrivers.h
===================================================================
--- chipdrivers.h	(revision 906)
+++ chipdrivers.h	(working copy)
@@ -111,18 +111,19 @@
 int erase_29f002(struct flashchip *flash);
 int erase_chip_29f002(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
 int erase_sector_29f002(struct flashchip *flash, unsigned int address, unsigned int blocklen);
 int write_29f002(struct flashchip *flash, uint8_t *buf);
 
 /* pm49fl00x.c */
 int probe_49fl00x(struct flashchip *flash);
 int erase_49fl00x(struct flashchip *flash);
 int write_49fl00x(struct flashchip *flash, uint8_t *buf);
+int unlock_49fl00x(struct flashchip *flash);
 
 /* sharplhf00l04.c */
 int probe_lhf00l04(struct flashchip *flash);
 int erase_lhf00l04_block(struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen);
 int write_lhf00l04(struct flashchip *flash, uint8_t *buf);
 void protect_lhf00l04(chipaddr bios);
 
 /* sst28sf040.c */
 int probe_28sf040(struct flashchip *flash);
@@ -139,35 +140,38 @@
 int write_49lf040(struct flashchip *flash, uint8_t *buf);
 
 /* sst49lfxxxc.c */
 int probe_49lfxxxc(struct flashchip *flash);
 int erase_49lfxxxc(struct flashchip *flash);
 int erase_sector_49lfxxxc(struct flashchip *flash, unsigned int address, unsigned int sector_size);
 int erase_block_49lfxxxc(struct flashchip *flash, unsigned int address, unsigned int sector_size);
 int erase_chip_49lfxxxc(struct flashchip *flash, unsigned int addr, unsigned int blocksize);
 int write_49lfxxxc(struct flashchip *flash, uint8_t *buf);
+int unlock_49lfxxxc(struct flashchip *flash);
 
 /* sst_fwhub.c */
 int probe_sst_fwhub(struct flashchip *flash);
 int erase_sst_fwhub(struct flashchip *flash);
 int erase_sst_fwhub_block(struct flashchip *flash, unsigned int offset, unsigned int page_size);
 int erase_sst_fwhub_sector(struct flashchip *flash, unsigned int offset, unsigned int page_size);
 int write_sst_fwhub(struct flashchip *flash, uint8_t *buf);
 
 /* w39v040c.c */
 int probe_w39v040c(struct flashchip *flash);
 int erase_w39v040c(struct flashchip *flash);
 int write_w39v040c(struct flashchip *flash, uint8_t *buf);
+int printlock_w39v040c(struct flashchip *flash);
 
 /* w39V080fa.c */
 int probe_winbond_fwhub(struct flashchip *flash);
 int erase_winbond_fwhub(struct flashchip *flash);
 int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf);
+int unlock_winbond_fwhub(struct flashchip *flash);
 
 /* w29ee011.c */
 int probe_w29ee011(struct flashchip *flash);
 
 /* w49f002u.c */
 int write_49f002(struct flashchip *flash, uint8_t *buf);
 
 /* stm50flw0x0x.c */
 int probe_stm50flw0x0x(struct flashchip *flash);
