diff --git a/chipdrivers.h b/chipdrivers.h
index c5062ca..fb9b1e8 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -79,26 +79,29 @@ int write_en29f002a(struct flashchip *flash, uint8_t *buf);
 uint8_t oddparity(uint8_t val);
 void toggle_ready_jedec(chipaddr dst);
 void data_polling_jedec(chipaddr dst, uint8_t data);
 int write_byte_program_jedec(chipaddr bios, uint8_t *src,
 			     chipaddr dst);
 int probe_jedec(struct flashchip *flash);
 int erase_chip_jedec(struct flashchip *flash);
 int write_jedec(struct flashchip *flash, uint8_t *buf);
 int write_jedec_1(struct flashchip *flash, uint8_t *buf);
 int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize);
 int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize);
 int erase_chip_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize);
 int write_sector_jedec_common(struct flashchip *flash, uint8_t *src, chipaddr dst, unsigned int page_size, unsigned int mask);
+int lock_status_block_jedec(struct flashchip *flash, unsigned int blockaddr);
+int unlock_block_jedec(struct flashchip *flash, unsigned int blockaddr);
+int lock_block_jedec(struct flashchip *flash, unsigned int blockaddr);
 
 /* m29f002.c */
 int erase_m29f002(struct flashchip *flash);
 int write_m29f002t(struct flashchip *flash, uint8_t *buf);
 int write_m29f002b(struct flashchip *flash, uint8_t *buf);
 
 /* m29f400bt.c */
 int probe_m29f400bt(struct flashchip *flash);
 int erase_m29f400bt(struct flashchip *flash);
 int block_erase_m29f400bt(struct flashchip *flash, unsigned int start, unsigned int len);
 int block_erase_chip_m29f400bt(struct flashchip *flash, unsigned int start, unsigned int len);
 int write_m29f400bt(struct flashchip *flash, uint8_t *buf);
 int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf);
diff --git a/flash.h b/flash.h
index d8f02bb..cd27e60 100644
--- a/flash.h
+++ b/flash.h
@@ -142,26 +142,30 @@ enum chipbustype {
 };
 
 /*
  * How many different contiguous runs of erase blocks with one size each do
  * we have for a given erase function?
  */
 #define NUM_ERASEREGIONS 5
 
 /*
  * How many different erase functions do we have per chip?
  */
 #define NUM_ERASEFUNCTIONS 5
 
+/* How many different lock segments can a chip have? */
+#define NUM_LOCKREGIONS 4
+#define NUM_LOCKFUNCTIONS 2
+
 #define FEATURE_REGISTERMAP	(1 << 0)
 #define FEATURE_BYTEWRITES	(1 << 1)
 #define FEATURE_LONG_RESET	(0 << 4)
 #define FEATURE_SHORT_RESET	(1 << 4)
 #define FEATURE_EITHER_RESET	FEATURE_LONG_RESET
 #define FEATURE_ADDR_FULL	(0 << 2)
 #define FEATURE_ADDR_MASK	(3 << 2)
 #define FEATURE_ADDR_2AA	(1 << 2)
 #define FEATURE_ADDR_AAA	(2 << 2)
 #define FEATURE_ADDR_SHIFTED	0
 
 struct flashchip {
 	const char *vendor;
@@ -195,26 +199,41 @@ struct flashchip {
 
 	/*
 	 * Erase blocks and associated erase function. Any chip erase function
 	 * is stored as chip-sized virtual block together with said function.
 	 */
 	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];
 
+	/*
+	 * Lock blocks and associated locking related functions. Lock blocks
+	 * are usually uniform blocks with three functions for locking,
+	 * unlocking, and lock status.
+	 */
+	struct block_locker {
+		struct lockblock {
+			unsigned int size; /* Lock block size; 64k or 32k */
+			unsigned int count; /* Number of contiguous blocks */
+		} lockblocks[NUM_LOCKREGIONS];
+		int (*lock) (struct flashchip *flash, unsigned int block);
+		int (*unlock) (struct flashchip *flash, unsigned int block);
+		int (*lock_status) (struct flashchip *flash, unsigned int block);
+	} block_lockers[NUM_LOCKFUNCTIONS];
+
 	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
 
 #define TEST_OK_PROBE	(1 << 0)
 #define TEST_OK_READ	(1 << 1)
 #define TEST_OK_ERASE	(1 << 2)
@@ -516,26 +535,29 @@ int erase_flash(struct flashchip *flash);
 struct flashchip *probe_flash(struct flashchip *first_flash, int force);
 int read_flash(struct flashchip *flash, char *filename);
 void check_chip_supported(struct flashchip *flash);
 int check_max_decode(enum chipbustype buses, uint32_t size);
 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);
 void print_version(void);
 int selfcheck(void);
 int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it);
+int unlock_flash(struct flashchip *flash);
+int lock_flash(struct flashchip *flash);
+int print_lock_status_flash(struct flashchip *flash);
 
 #define OK 0
 #define NT 1    /* Not tested */
 
 /* cli_output.c */
 int print(int type, const char *fmt, ...);
 #define MSG_ERROR	0
 #define MSG_INFO	1
 #define MSG_DEBUG	2
 #define MSG_BARF	3
 #define msg_gerr(...)	print(MSG_ERROR, __VA_ARGS__)	/* general errors */
 #define msg_perr(...)	print(MSG_ERROR, __VA_ARGS__)	/* programmer errors */
 #define msg_cerr(...)	print(MSG_ERROR, __VA_ARGS__)	/* chip errors */
diff --git a/flashchips.c b/flashchips.c
index f66b95a..174dce6 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -3425,27 +3425,36 @@ struct flashchip flashchips[] = {
 		.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,
 			}
 		},
-		.write		= write_49fl00x,
+		.block_lockers =
+		{
+			{
+				.lockblocks = { {64 * 1024, 8} },
+				.lock = lock_block_jedec,
+				.unlock = unlock_block_jedec,
+				.lock_status = lock_status_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
 		.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,
@@ -3455,27 +3464,36 @@ struct flashchip flashchips[] = {
 		.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,
 			}
 		},
-		.write		= write_49fl00x,
+		.block_lockers =
+		{
+			{
+				.lockblocks = { {64 * 1024, 8} },
+				.lock = lock_block_jedec,
+				.unlock = unlock_block_jedec,
+				.lock_status = lock_status_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "Sanyo",
 		.name		= "LF25FW203A",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= SANYO_ID,
 		.model_id	= SANYO_LE25FW203A,
 		.total_size	= 2048,
 		.page_size	= 256,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
@@ -6120,26 +6138,40 @@ struct flashchip flashchips[] = {
 		.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,
 			}
 		},
+		.block_lockers =
+		{
+			{ /* block lock functions */
+				.lockblocks = { {64 * 1024, 16} },
+				.lock = lock_block_jedec,
+				.unlock = unlock_block_jedec,
+				.lock_status = lock_status_block_jedec,
+			}, { /* #TBL / #WP status */
+				.lockblocks = { {512 * 1024, 1} }, /* dummy block */
+				.lock = NULL,
+				.unlock = NULL,
+				.lock_status = lock_status_chip_jedec,
+			}
+		},
 		.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,
@@ -6147,26 +6179,40 @@ struct flashchip flashchips[] = {
 		.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,
 			}
 		},
+		.block_lockers =
+		{
+			{ /* block lock functions */
+				.lockblocks = { {64 * 1024, 8} },
+				.lock = lock_block_jedec,
+				.unlock = unlock_block_jedec,
+				.lock_status = lock_status_block_jedec,
+			}, { /* #TBL / #WP status */
+				.lockblocks = { {512 * 1024, 1} }, /* dummy block */
+				.lock = NULL,
+				.unlock = NULL,
+				.lock_status = lock_status_chip_jedec,
+			}
+		},
 		.write		= write_jedec_1,
 		.read		= read_memmapped,
 	},
 
 	{
 		.vendor		= "Atmel",
 		.name		= "unknown Atmel SPI chip",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= ATMEL_ID,
 		.model_id	= GENERIC_DEVICE_ID,
 		.total_size	= 0,
 		.page_size	= 256,
 		.tested		= TEST_BAD_PREW,
diff --git a/flashrom.c b/flashrom.c
index 326f725..1d5439a 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -795,26 +795,28 @@ struct flashchip *probe_flash(struct flashchip *first_flash, int force)
 			break;
 
 notfound:
 		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
 	}
 
 	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);
 
+	print_lock_status_flash(flash);
+
 	return flash;
 }
 
 int verify_flash(struct flashchip *flash, uint8_t *buf)
 {
 	int ret;
 	int total_size = flash->total_size * 1024;
 
 	printf("Verifying flash... ");
 
 	ret = verify_range(flash, buf, 0, total_size, NULL);
 
 	if (!ret)
@@ -984,26 +986,213 @@ int erase_flash(struct flashchip *flash)
 	if (!found) {
 		fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
 		return 1;
 	}
 
 	if (ret) {
 		fprintf(stderr, "FAILED!\n");
 	} else {
 		printf("SUCCESS.\n");
 	}
 	return ret;
 }
 
+int unlock_flash(struct flashchip *flash)
+{
+	int i, j, k, ret = 0, found = 0;
+	unsigned int start;
+
+	printf("Unlocking flash chip... ");
+	for (k = 0; k < NUM_LOCKFUNCTIONS; k++) {
+		unsigned int done = 0;
+		struct block_locker locker = flash->block_lockers[k];
+
+		printf_debug("Looking at blockwise unlock function %i... ", k);
+		if (!locker.unlock && !locker.lockblocks[0].count) {
+			printf_debug("not defined. "
+				"Looking for another unlock function.\n");
+			continue;
+		}
+		if (!locker.unlock && locker.lockblocks[0].count) {
+			printf_debug("lockblock layout is known, but no "
+				"matching block unlock function found. "
+				"Looking for another unlock function.\n");
+			continue;
+		}
+		if (locker.unlock && !locker.lockblocks[0].count) {
+			printf_debug("block unlock function found, but "
+				"lockblock layout is unknown. "
+				"Looking for another unlock function.\n");
+			continue;
+		}
+		found = 1;
+		printf_debug("trying... ");
+		for (i = 0; i < NUM_LOCKREGIONS; i++) {
+			/* count==0 for all automatically initialized array
+			 * members so the loop below won't be executed for them.
+			 */
+			for (j = 0; j < locker.lockblocks[i].count; j++) {
+				start = done + locker.lockblocks[i].size * j;
+				ret = locker.unlock(flash, start);
+				printf_debug("0x%06x, ", start);
+				if (ret)
+					break;
+			}
+			if (ret)
+				break;
+			done += locker.lockblocks[i].count *
+				locker.lockblocks[i].size;
+		}
+		printf_debug("\n");
+		/* If everything is OK, don't try another unlock function. */
+		if (!ret)
+			break;
+	}
+	if (!found) {
+		fprintf(stderr, "ERROR: flashrom has no unlock function for this flash chip.\n");
+		return 1;
+	}
+
+	if (ret) {
+		fprintf(stderr, "FAILED!\n");
+	} else {
+		printf("SUCCESS.\n");
+	}
+	return ret;
+}
+
+int lock_flash(struct flashchip *flash)
+{
+	int i, j, k, ret = 0, found = 0;
+	unsigned int start;
+
+	printf("Locking flash chip... ");
+	for (k = 0; k < NUM_LOCKFUNCTIONS; k++) {
+		unsigned int done = 0;
+		struct block_locker locker = flash->block_lockers[k];
+
+		printf_debug("Looking at blockwise lock function %i... ", k);
+		if (!locker.lock && !locker.lockblocks[0].count) {
+			printf_debug("not defined. "
+				"Looking for another lock function.\n");
+			continue;
+		}
+		if (!locker.lock && locker.lockblocks[0].count) {
+			printf_debug("lockblock layout is known, but no "
+				"matching block lock function found. "
+				"Looking for another lock function.\n");
+			continue;
+		}
+		if (locker.lock && !locker.lockblocks[0].count) {
+			printf_debug("block lock function found, but "
+				"lockblock layout is unknown. "
+				"Looking for another lock function.\n");
+			continue;
+		}
+		found = 1;
+		printf_debug("trying... ");
+		for (i = 0; i < NUM_LOCKREGIONS; i++) {
+			/* count==0 for all automatically initialized array
+			 * members so the loop below won't be executed for them.
+			 */
+			for (j = 0; j < locker.lockblocks[i].count; j++) {
+				start = done + locker.lockblocks[i].size * j;
+				ret = locker.lock(flash, start);
+				printf_debug("0x%06x, ", start);
+				if (ret)
+					break;
+			}
+			if (ret)
+				break;
+			done += locker.lockblocks[i].count *
+				locker.lockblocks[i].size;
+		}
+		printf_debug("\n");
+		/* If everything is OK, don't try another lock function. */
+		if (!ret)
+			break;
+	}
+	if (!found) {
+		fprintf(stderr, "ERROR: flashrom has no lock function for this flash chip.\n");
+		return 1;
+	}
+
+	if (ret) {
+		fprintf(stderr, "FAILED!\n");
+	} else {
+		printf("SUCCESS.\n");
+	}
+	return ret;
+}
+
+int print_lock_status_flash(struct flashchip *flash)
+{
+	int i, j, k, ret = 0, found = 0;
+	unsigned int start, lock_stat = 0;
+
+	printf("Printing Lock Status for flash chip... ");
+	for (k = 0; k < NUM_LOCKFUNCTIONS; k++) {
+		unsigned int done = 0;
+		struct block_locker locker = flash->block_lockers[k];
+
+		printf_debug("Looking at blockwise lock_status function %i... ", k);
+		if (!locker.lock_status && !locker.lockblocks[0].count) {
+			printf_debug("not defined. "
+				"Looking for another lock_status function.\n");
+			continue;
+		}
+		if (!locker.lock_status && locker.lockblocks[0].count) {
+			printf_debug("lockblock layout is known, but no "
+				"matching block lock_status function found. "
+				"Looking for another lock_status function.\n");
+			continue;
+		}
+		if (locker.lock_status && !locker.lockblocks[0].count) {
+			printf_debug("block lock_status function found, but "
+				"lockblock layout is unknown. "
+				"Looking for another lock_status function.\n");
+			continue;
+		}
+		found = 1;
+		printf("trying... ");
+		for (i = 0; i < NUM_LOCKREGIONS; i++) {
+			/* count==0 for all automatically initialized array
+			 * members so the loop below won't be executed for them.
+			 */
+			for (j = 0; j < locker.lockblocks[i].count; j++) {
+				start = done + locker.lockblocks[i].size * j;
+				ret = locker.lock_status(flash, start);
+			}
+			done += locker.lockblocks[i].count *
+				locker.lockblocks[i].size;
+			if (ret) {
+				break;
+			}
+		}
+		printf("\n");
+	}
+	if (!found) {
+		fprintf(stderr, "WARNING: flashrom has no lock_status function for this flash chip.\n");
+		return 1;
+	}
+
+	if (ret) {
+		fprintf(stderr, "FAILED!\n");
+	} else {
+		printf("SUCCESS.\n");
+	}
+	return ret;
+}
+
 void emergency_help_message(void)
 {
 	fprintf(stderr, "Your flash chip is in an unknown state.\n"
 		"Get help on IRC at irc.freenode.net (channel #flashrom) or\n"
 		"mail flashrom@flashrom.org!\n--------------------"
 		"-----------------------------------------------------------\n"
 		"DO NOT REBOOT OR POWEROFF!\n");
 }
 
 /* The way to go if you want a delimited list of programmers*/
 void list_programmers(char *delim)
 {
 	enum programmer p;
@@ -1099,26 +1288,28 @@ int main(int argc, char *argv[])
  * but right now it allows us to split off the CLI code.
  */
 int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it)
 {
 	uint8_t *buf;
 	unsigned long numbytes;
 	FILE *image;
 	int ret = 0;
 	unsigned long size;
 
 	size = flash->total_size * 1024;
 	buf = (uint8_t *) calloc(size, sizeof(char));
 
+	unlock_flash(flash);
+
 	if (erase_it) {
 		if (flash->tested & TEST_BAD_ERASE) {
 			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");
 			}
 		}
 		if (erase_flash(flash)) {
 			emergency_help_message();
diff --git a/jedec.c b/jedec.c
index 055e910..6b857bf 100644
--- a/jedec.c
+++ b/jedec.c
@@ -485,13 +485,113 @@ int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int s
 	int mask;
 
 	mask = getaddrmask(flash);
 	return erase_block_jedec_common(flash, page, size, mask);
 }
 
 int erase_chip_jedec(struct flashchip *flash)
 {
 	int mask;
 
 	mask = getaddrmask(flash);
 	return erase_chip_jedec_common(flash, mask);
 }
+
+int unlock_block_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+	chip_writeb(0, flash->virtual_registers + blockaddr + 2);
+	return 0;
+}
+
+int lock_block_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+	chip_writeb(1, flash->virtual_registers + blockaddr + 2);
+	return 0;
+}
+
+int lock_status_block_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+	chipaddr wrprotect = flash->virtual_registers + offset + 2;
+	uint8_t locking;
+
+	printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset,
+		     chip_readb(wrprotect));
+
+	locking = chip_readb(wrprotect);
+	switch (locking & 0x7) {
+	case 0:
+		printf_debug("Full Access.\n");
+		return 0;
+	case 1:
+		printf_debug("Write Lock (Default State).\n");
+		chip_writeb(0, wrprotect);
+		return 0;
+	case 2:
+		printf_debug("Locked Open (Full Access, Lock Down).\n");
+		return 0;
+	case 3:
+		fprintf(stderr, "Error: Write Lock, Locked Down.\n");
+		return -1;
+	case 4:
+		printf_debug("Read Lock.\n");
+		chip_writeb(0, wrprotect);
+		return 0;
+	case 5:
+		printf_debug("Read/Write Lock.\n");
+		chip_writeb(0, wrprotect);
+		return 0;
+	case 6:
+		fprintf(stderr, "Error: Read Lock, Locked Down.\n");
+		return -1;
+	case 7:
+		fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n");
+		return -1;
+	}
+
+	/* We will never reach this point, but GCC doesn't know */
+	return -1;
+}
+
+int lock_status_chip_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+	int i, total_size = flash->total_size * 1024;
+	chipaddr bios = flash->virtual_memory;
+	uint8_t locking;
+	int mask;
+	
+	mask = getaddrmask(flash);
+	/* Are there any hardware restrictions that we can't overcome? 
+	 * If flashrom fail here, someone's got to check all those GPIOs.
+	 */
+
+	/* Product Identification Entry */
+	chip_writeb(0xAA, bios + (0x5555 & mask));
+	chip_writeb(0x55, bios + (0x2AAA & mask));
+	chip_writeb(0x90, bios + (0x5555 & mask));
+	programmer_delay(10);
+
+	/* Read Hardware Lock Bits */
+	locking = chip_readb(bios + 0xffff2);
+
+	/* Product Identification Exit */
+	chip_writeb(0xAA, bios + (0x5555 & mask));
+	chip_writeb(0x55, bios + (0x2AAA & mask));
+	chip_writeb(0xF0, bios + (0x5555 & mask));
+	programmer_delay(10);
+
+	printf_debug("Lockout bits:\n");
+
+	if (locking & (1 << 2))
+		fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n");
+	else
+		printf_debug("No hardware bootblock locking (good!)\n");
+
+	if (locking & (1 << 3))
+		fprintf(stderr, "Error: hardware block locking (#WP).\n");
+	else
+		printf_debug("No hardware block locking (good!)\n");
+
+	if (locking & ((1 << 2) | (1 << 3)))
+		return -1;
+
+	return 0;
+}

