Patchwork Make struct flashchip a field in struct flashctx instead of a complete copy.

login
register
about
Submitter Carl-Daniel Hailfinger
Date 2012-08-18 23:51:16
Message ID <50302A74.8030906@gmx.net>
Download mbox | patch
Permalink /patch/3717/
State Superseded
Headers show

Comments

Carl-Daniel Hailfinger - 2012-08-18 23:51:16
Counter-proposal (conversion from scratch). AFAICS the only differences
to your version regarding code flow are in cli_classic.c and flashrom.c.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Stefan Tauner - 2012-08-19 01:29:22
On Sun, 19 Aug 2012 01:51:16 +0200
Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> wrote:

> Counter-proposal (conversion from scratch). AFAICS the only differences
> to your version regarding code flow are in cli_classic.c and flashrom.c.

this is not a full review, i just looked at flashrom.c and cli_classic.c

> Index: flashrom-flashctx_separate_struct_flashchip/cli_classic.c
> ===================================================================
> --- flashrom-flashctx_separate_struct_flashchip/cli_classic.c	(Revision 1576)
> +++ flashrom-flashctx_separate_struct_flashchip/cli_classic.c	(Arbeitskopie)
> @@ -109,8 +109,8 @@
>  {
>  	unsigned long size;
>  	/* Probe for up to three flash chips. */
> -	const struct flashchip *flash;
> -	struct flashctx flashes[3];
> +	const struct flashchip *chip;
> +	struct flashctx flashes[3] = {};

this is not standard C afaik, but gcc does not accept (the standard) {0}
without warning either, hence my {{0}} suggestion.
http://stackoverflow.com/questions/1352370/c-static-array-initialization-how-verbose-do-i-need-to-be/1352379#1352379

>  	struct flashctx *fill_flash;
>  	const char *name;
>  	int namelen, opt, i, j;
> @@ -389,17 +389,16 @@
>  	}
>  	/* Does a chip with the requested name exist in the flashchips array? */
>  	if (chip_to_probe) {
> -		for (flash = flashchips; flash && flash->name; flash++)
> -			if (!strcmp(flash->name, chip_to_probe))
> +		for (chip = flashchips; chip && chip->name; chip++)
> +			if (!strcmp(chip->name, chip_to_probe))
>  				break;
> -		if (!flash || !flash->name) {
> +		if (!chip || !chip->name) {
>  			msg_cerr("Error: Unknown chip '%s' specified.\n", chip_to_probe);
>  			msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n");
>  			ret = 1;
>  			goto out;
>  		}
> -		/* Clean up after the check. */
> -		flash = NULL;
> +		/* Keep chip around for later usage. */
>  	}

nasty hack for the evil hack named forced reads. :)

> @@ -456,9 +452,15 @@
>  			/* This loop just counts compatible controllers. */
>  			for (j = 0; j < registered_programmer_count; j++) {
>  				pgm = &registered_programmers[j];
> -				if (pgm->buses_supported & flashes[0].bustype)
> +				/* chip is still set from the chip_to_probe earlier in this function. */
> +				if (pgm->buses_supported & chip->bustype)
>  					compatible_programmers++;
>  			}
> +			if (!compatible_programmers) {
> +				msg_cinfo("No compatible controller found for the requested flash chip.\n");
> +				ret = 1;
> +				goto out_shutdown;
> +			}

good catch!

> Index: flashrom-flashctx_separate_struct_flashchip/flashrom.c
> ===================================================================
> --- flashrom-flashctx_separate_struct_flashchip/flashrom.c	(Revision 1576)
> +++ flashrom-flashctx_separate_struct_flashchip/flashrom.c	(Arbeitskopie)
> @@ -950,44 +950,52 @@
>  	return 1;
>  }
>  
> -int probe_flash(struct registered_programmer *pgm, int startchip,
> -		struct flashctx *fill_flash, int force)
> +int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *flash, int force)
>  {
> -	const struct flashchip *flash;
> +	const struct flashchip *chip;
>  	unsigned long base = 0;
>  	char location[64];
>  	uint32_t size;
>  	enum chipbustype buses_common;
>  	char *tmp;
>  
> -	for (flash = flashchips + startchip; flash && flash->name; flash++) {
> -		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
> +	for (chip = flashchips + startchip; chip && chip->name; chip++) {
> +		if (chip_to_probe && strcmp(chip->name, chip_to_probe) != 0)
>  			continue;
> -		buses_common = pgm->buses_supported & flash->bustype;
> +		buses_common = pgm->buses_supported & chip->bustype;
>  		if (!buses_common)
>  			continue;
>  		msg_gdbg("Probing for %s %s, %d kB: ",
> -			     flash->vendor, flash->name, flash->total_size);
> -		if (!flash->probe && !force) {
> +			     chip->vendor, chip->name, chip->total_size);

this can be combined with the line before easily.

> +		if (!chip->probe && !force) {
>  			msg_gdbg("failed! flashrom has no probe function for "
>  				 "this flash chip.\n");
>  			continue;
>  		}
>  
> -		size = flash->total_size * 1024;
> +		size = chip->total_size * 1024;
>  		check_max_decode(buses_common, size);

hm.. return value of check_max_decode is ignored here, and checked
later in main()... quite odd, but not related to flashctx.

>  
>  		/* Start filling in the dynamic data. */
> -		memcpy(fill_flash, flash, sizeof(struct flashchip));
> -		fill_flash->pgm = pgm;
> +		flash->chip = calloc(1, sizeof(struct flashchip));

right. my patch has the potential to explode spectacularly due to a
normal malloc here and the code expecting 0 to recognize end of lists
etc :/

> +		if (!flash->chip) {
> +			msg_gerr("Out of memory!\n");
> +			// FIXME: Is -1 the right return code?
> +			return -1;

hm... well it breaks the outer loop, but there is no real error handling
there. better add an exit(1) here (yes, really :) for now and fix it
when the error definitions are merged (which has rather high priority
for me). just returning with the current code would postpone the
explosion to doit(). NB: i havent checked that too thoroughly.

> +		}
> +		memcpy(flash->chip, chip, sizeof(struct flashchip));
> +		flash->pgm = pgm;
>  
>  		base = flashbase ? flashbase : (0xffffffff - size + 1);
> -		fill_flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
> +		flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
>  
> +		/* We handle a forced match like a real match, we just avoid probing. Note that probe_flash()
> +		 * is only called with force=1 after normal probing failed.
> +		 */

yay more comments in the hard parts of flashrom :)

>  		if (force)
>  			break;
>  
> -		if (fill_flash->probe(fill_flash) != 1)
> +		if (flash->chip->probe(flash) != 1)
>  			goto notfound;
>  
>  		/* If this is the first chip found, accept it.
> @@ -1022,15 +1030,18 @@
>  		}
>  
>  		if (startchip == 0 ||
> -		    ((fill_flash->model_id != GENERIC_DEVICE_ID) &&
> -		     (fill_flash->model_id != SFDP_DEVICE_ID)))
> +		    ((flash->chip->model_id != GENERIC_DEVICE_ID) &&
> +		     (flash->chip->model_id != SFDP_DEVICE_ID)))

i like that bit better in my patch, because it groups together what
belongs together.

>  			break;
>  
>  notfound:
> -		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
> +		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
> +		flash->virtual_memory = (chipaddr)NULL;
> +		free(flash->chip);
> +		flash->chip = NULL;

pretty clear indication that this function has issues imho :)
those lines are a candidate to form a function flashctx_init or
something like that, if we need this more often (i really hope we dont.)

>  	}
>  
> -	if (!flash || !flash->name)
> +	if (!flash->chip)
>  		return -1;

i wondered too why that ->name check was there, any ideas?
Carl-Daniel Hailfinger - 2012-08-19 22:39:19
Am 19.08.2012 03:29 schrieb Stefan Tauner:
> On Sun, 19 Aug 2012 01:51:16 +0200
> Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> wrote:
>
>> Counter-proposal (conversion from scratch). AFAICS the only differences
>> to your version regarding code flow are in cli_classic.c and flashrom.c.
> this is not a full review, i just looked at flashrom.c and cli_classic.c
>
>> Index: flashrom-flashctx_separate_struct_flashchip/cli_classic.c
>> ===================================================================
>> --- flashrom-flashctx_separate_struct_flashchip/cli_classic.c	(Revision 1576)
>> +++ flashrom-flashctx_separate_struct_flashchip/cli_classic.c	(Arbeitskopie)
>> @@ -109,8 +109,8 @@
>>  {
>>  	unsigned long size;
>>  	/* Probe for up to three flash chips. */
>> -	const struct flashchip *flash;
>> -	struct flashctx flashes[3];
>> +	const struct flashchip *chip;
>> +	struct flashctx flashes[3] = {};
> this is not standard C afaik, but gcc does not accept (the standard) {0}
> without warning either, hence my {{0}} suggestion.
> http://stackoverflow.com/questions/1352370/c-static-array-initialization-how-verbose-do-i-need-to-be/1352379#1352379

Thanks for the hint. We'll take your version.

 
>>  	struct flashctx *fill_flash;
>>  	const char *name;
>>  	int namelen, opt, i, j;
>> @@ -389,17 +389,16 @@
>>  	}
>>  	/* Does a chip with the requested name exist in the flashchips array? */
>>  	if (chip_to_probe) {
>> -		for (flash = flashchips; flash && flash->name; flash++)
>> -			if (!strcmp(flash->name, chip_to_probe))
>> +		for (chip = flashchips; chip && chip->name; chip++)
>> +			if (!strcmp(chip->name, chip_to_probe))
>>  				break;
>> -		if (!flash || !flash->name) {
>> +		if (!chip || !chip->name) {
>>  			msg_cerr("Error: Unknown chip '%s' specified.\n", chip_to_probe);
>>  			msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n");
>>  			ret = 1;
>>  			goto out;
>>  		}
>> -		/* Clean up after the check. */
>> -		flash = NULL;
>> +		/* Keep chip around for later usage. */
>>  	}
> nasty hack for the evil hack named forced reads. :)

Hm yes, I should have mentioned forced reads in that comment.

 
>> @@ -456,9 +452,15 @@
>>  			/* This loop just counts compatible controllers. */
>>  			for (j = 0; j < registered_programmer_count; j++) {
>>  				pgm = &registered_programmers[j];
>> -				if (pgm->buses_supported & flashes[0].bustype)
>> +				/* chip is still set from the chip_to_probe earlier in this function. */
>> +				if (pgm->buses_supported & chip->bustype)
>>  					compatible_programmers++;
>>  			}
>> +			if (!compatible_programmers) {
>> +				msg_cinfo("No compatible controller found for the requested flash chip.\n");
>> +				ret = 1;
>> +				goto out_shutdown;
>> +			}
> good catch!

Thanks!


>> Index: flashrom-flashctx_separate_struct_flashchip/flashrom.c
>> ===================================================================
>> --- flashrom-flashctx_separate_struct_flashchip/flashrom.c	(Revision 1576)
>> +++ flashrom-flashctx_separate_struct_flashchip/flashrom.c	(Arbeitskopie)
>> @@ -950,44 +950,52 @@
>>  	return 1;
>>  }
>>  
>> -int probe_flash(struct registered_programmer *pgm, int startchip,
>> -		struct flashctx *fill_flash, int force)
>> +int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *flash, int force)
>>  {
>> -	const struct flashchip *flash;
>> +	const struct flashchip *chip;
>>  	unsigned long base = 0;
>>  	char location[64];
>>  	uint32_t size;
>>  	enum chipbustype buses_common;
>>  	char *tmp;
>>  
>> -	for (flash = flashchips + startchip; flash && flash->name; flash++) {
>> -		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
>> +	for (chip = flashchips + startchip; chip && chip->name; chip++) {
>> +		if (chip_to_probe && strcmp(chip->name, chip_to_probe) != 0)
>>  			continue;
>> -		buses_common = pgm->buses_supported & flash->bustype;
>> +		buses_common = pgm->buses_supported & chip->bustype;
>>  		if (!buses_common)
>>  			continue;
>>  		msg_gdbg("Probing for %s %s, %d kB: ",
>> -			     flash->vendor, flash->name, flash->total_size);
>> -		if (!flash->probe && !force) {
>> +			     chip->vendor, chip->name, chip->total_size);
> this can be combined with the line before easily.

Right.

 
>> +		if (!flash->chip) {
>> +			msg_gerr("Out of memory!\n");
>> +			// FIXME: Is -1 the right return code?
>> +			return -1;
> hm... well it breaks the outer loop, but there is no real error handling
> there. better add an exit(1) here (yes, really :) for now and fix it
> when the error definitions are merged (which has rather high priority
> for me). just returning with the current code would postpone the
> explosion to doit(). NB: i havent checked that too thoroughly.

Hm... while I think that we shouldn't introduce new exit(1), I agree
that this case needs careful audit, and the patch is already complicated
enough as is.


>> @@ -1022,15 +1030,18 @@
>>  		}
>>  
>>  		if (startchip == 0 ||
>> -		    ((fill_flash->model_id != GENERIC_DEVICE_ID) &&
>> -		     (fill_flash->model_id != SFDP_DEVICE_ID)))
>> +		    ((flash->chip->model_id != GENERIC_DEVICE_ID) &&
>> +		     (flash->chip->model_id != SFDP_DEVICE_ID)))
> i like that bit better in my patch, because it groups together what
> belongs together.

You mean having both related checks on one line? Or do you mean using
chip-> instead of flash->chip-> ?

 
>>  			break;
>>  
>>  notfound:
>> -		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
>> +		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
>> +		flash->virtual_memory = (chipaddr)NULL;
>> +		free(flash->chip);
>> +		flash->chip = NULL;
> pretty clear indication that this function has issues imho :)

_Had_ issues. I really like the new code, because it not only
frees/unmaps stuff, it also leaves no dangling pointers around.


> those lines are a candidate to form a function flashctx_init or
> something like that, if we need this more often (i really hope we dont.)
>
>>  	}
>>  
>> -	if (!flash || !flash->name)
>> +	if (!flash->chip)
>>  		return -1;
> i wondered too why that ->name check was there, any ideas?

Yes. The old !flash check would only have triggered in very odd
circumstances (empty array in flashchips.c), and !flash->name was the
detection for end-of-array (last array member was zeroed).
The new !flash->chip check is way more readable and doesn't rely on
implicit properties of an array in another file.


How do we proceed? Should I repost a fixed version of my patch so you
can merge yours and mine? Can you do the missing dediprog conversion
locally or do you want to take mine?


Regards,
Carl-Daniel
Stefan Tauner - 2012-08-19 22:54:39
On Mon, 20 Aug 2012 00:39:19 +0200
Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> wrote:

> >>  notfound:
> >> -		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
> >> +		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
> >> +		flash->virtual_memory = (chipaddr)NULL;
> >> +		free(flash->chip);
> >> +		flash->chip = NULL;  
> > pretty clear indication that this function has issues imho :)  
> 
> _Had_ issues. I really like the new code, because it not only
> frees/unmaps stuff, it also leaves no dangling pointers around.

in a function that should actually just probe for a chip. my definition
of code issues seems to be different. :)

but it got better, and it is certainly ready for merge.

i would prefer if you would take the bits of my patch that you like, add
them to your patch and then repost or commit right away.

Patch

Index: flashrom-flashctx_separate_struct_flashchip/flash.h
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/flash.h	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/flash.h	(Arbeitskopie)
@@ -148,27 +148,8 @@ 
 	} voltage;
 };
 
-/* struct flashctx must always contain struct flashchip at the beginning. */
 struct flashctx {
-	const char *vendor;
-	const char *name;
-	enum chipbustype bustype;
-	uint32_t manufacture_id;
-	uint32_t model_id;
-	int total_size;
-	int page_size;
-	int feature_bits;
-	uint32_t tested;
-	int (*probe) (struct flashctx *flash);
-	int probe_timing;
-	struct block_eraser block_erasers[NUM_ERASEFUNCTIONS];
-	int (*printlock) (struct flashctx *flash);
-	int (*unlock) (struct flashctx *flash);
-	int (*write) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
-	int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
-	struct voltage voltage;
-	/* struct flashchip ends here. */
-	
+	struct flashchip *chip;
 	chipaddr virtual_memory;
 	/* Some flash devices have an additional register space. */
 	chipaddr virtual_registers;
Index: flashrom-flashctx_separate_struct_flashchip/it87spi.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/it87spi.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/it87spi.c	(Arbeitskopie)
@@ -331,7 +331,7 @@ 
 	/* FIXME: The command below seems to be redundant or wrong. */
 	OUTB(0x06, it8716f_flashport + 1);
 	OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport);
-	for (i = 0; i < flash->page_size; i++)
+	for (i = 0; i < flash->chip->page_size; i++)
 		mmio_writeb(buf[i], (void *)(bios + start + i));
 	OUTB(0, it8716f_flashport);
 	/* Wait until the Write-In-Progress bit is cleared.
@@ -355,7 +355,7 @@ 
 	 * the mainboard does not use IT87 SPI translation. This should be done
 	 * via a programmer parameter for the internal programmer.
 	 */
-	if ((flash->total_size * 1024 > 512 * 1024)) {
+	if ((flash->chip->total_size * 1024 > 512 * 1024)) {
 		spi_read_chunked(flash, buf, start, len, 3);
 	} else {
 		mmio_readn((void *)(flash->virtual_memory + start), buf, len);
@@ -377,28 +377,28 @@ 
 	 * the mainboard does not use IT87 SPI translation. This should be done
 	 * via a programmer parameter for the internal programmer.
 	 */
-	if ((flash->total_size * 1024 > 512 * 1024) ||
-	    (flash->page_size > 256)) {
+	if ((flash->chip->total_size * 1024 > 512 * 1024) ||
+	    (flash->chip->page_size > 256)) {
 		spi_chip_write_1(flash, buf, start, len);
 	} else {
 		unsigned int lenhere;
 
-		if (start % flash->page_size) {
+		if (start % flash->chip->page_size) {
 			/* start to the end of the page or to start + len,
 			 * whichever is smaller.
 			 */
-			lenhere = min(len, flash->page_size - start % flash->page_size);
+			lenhere = min(len, flash->chip->page_size - start % flash->chip->page_size);
 			spi_chip_write_1(flash, buf, start, lenhere);
 			start += lenhere;
 			len -= lenhere;
 			buf += lenhere;
 		}
 
-		while (len >= flash->page_size) {
+		while (len >= flash->chip->page_size) {
 			it8716f_spi_page_program(flash, buf, start);
-			start += flash->page_size;
-			len -= flash->page_size;
-			buf += flash->page_size;
+			start += flash->chip->page_size;
+			len -= flash->chip->page_size;
+			buf += flash->chip->page_size;
 		}
 		if (len)
 			spi_chip_write_1(flash, buf, start, len);
Index: flashrom-flashctx_separate_struct_flashchip/jedec.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/jedec.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/jedec.c	(Arbeitskopie)
@@ -93,9 +93,9 @@ 
 		msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
 }
 
-static unsigned int getaddrmask(struct flashctx *flash)
+static unsigned int getaddrmask(const struct flashchip *chip)
 {
-	switch (flash->feature_bits & FEATURE_ADDR_MASK) {
+	switch (chip->feature_bits & FEATURE_ADDR_MASK) {
 	case FEATURE_ADDR_FULL:
 		return MASK_FULL;
 		break;
@@ -129,11 +129,11 @@ 
 	uint32_t flashcontent1, flashcontent2;
 	int probe_timing_enter, probe_timing_exit;
 
-	if (flash->probe_timing > 0) 
-		probe_timing_enter = probe_timing_exit = flash->probe_timing;
-	else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */
+	if (flash->chip->probe_timing > 0) 
+		probe_timing_enter = probe_timing_exit = flash->chip->probe_timing;
+	else if (flash->chip->probe_timing == TIMING_ZERO) { /* No delay. */
 		probe_timing_enter = probe_timing_exit = 0;
-	} else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */
+	} else if (flash->chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
 		msg_cdbg("Chip lacks correct probe timing information, "
 			     "using default 10mS/40uS. ");
 		probe_timing_enter = 10000;
@@ -151,7 +151,7 @@ 
 	if (probe_timing_enter)
 		programmer_delay(probe_timing_enter);
 	/* Reset chip to a clean slate */
-	if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	if ((flash->chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
 	{
 		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
 		if (probe_timing_exit)
@@ -194,7 +194,7 @@ 
 	}
 
 	/* Issue JEDEC Product ID Exit command */
-	if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	if ((flash->chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
 	{
 		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
 		if (probe_timing_exit)
@@ -231,10 +231,10 @@ 
 		msg_cdbg(", id2 is normal flash content");
 
 	msg_cdbg("\n");
-	if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id)
+	if (largeid1 != flash->chip->manufacture_id || largeid2 != flash->chip->model_id)
 		return 0;
 
-	if (flash->feature_bits & FEATURE_REGISTERMAP)
+	if (flash->chip->feature_bits & FEATURE_REGISTERMAP)
 		map_flash_registers(flash);
 
 	return 1;
@@ -245,7 +245,7 @@ 
 {
 	chipaddr bios = flash->virtual_memory;
 	int delay_us = 0;
-	if(flash->probe_timing != TIMING_ZERO)
+	if(flash->chip->probe_timing != TIMING_ZERO)
 	        delay_us = 10;
 
 	/*  Issue the Sector Erase command   */
@@ -275,7 +275,7 @@ 
 {
 	chipaddr bios = flash->virtual_memory;
 	int delay_us = 0;
-	if(flash->probe_timing != TIMING_ZERO)
+	if(flash->chip->probe_timing != TIMING_ZERO)
 	        delay_us = 10;
 
 	/*  Issue the Sector Erase command   */
@@ -304,7 +304,7 @@ 
 {
 	chipaddr bios = flash->virtual_memory;
 	int delay_us = 0;
-	if(flash->probe_timing != TIMING_ZERO)
+	if(flash->chip->probe_timing != TIMING_ZERO)
 	        delay_us = 10;
 
 	/*  Issue the JEDEC Chip Erase command   */
@@ -366,7 +366,7 @@ 
 	chipaddr olddst;
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 
 	olddst = dst;
 	for (i = 0; i < len; i++) {
@@ -390,7 +390,7 @@ 
 	chipaddr d = dst;
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 
 retry:
 	/* Issue JEDEC Start Program command */
@@ -438,7 +438,7 @@ 
 	 * write_jedec have page_size set to max_writechunk_size, so
 	 * we're OK for now.
 	 */
-	unsigned int page_size = flash->page_size;
+	unsigned int page_size = flash->chip->page_size;
 
 	/* Warning: This loop has a very unusual condition and body.
 	 * The loop needs to go through each page with at least one affected
@@ -469,8 +469,8 @@ 
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
-	if ((addr != 0) || (blocksize != flash->total_size * 1024)) {
+	mask = getaddrmask(flash->chip);
+	if ((addr != 0) || (blocksize != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n",
 			__func__);
 		return -1;
@@ -482,7 +482,7 @@ 
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return probe_jedec_common(flash, mask);
 }
 
@@ -491,7 +491,7 @@ 
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return erase_sector_jedec_common(flash, page, size, mask);
 }
 
@@ -500,7 +500,7 @@ 
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return erase_block_jedec_common(flash, page, size, mask);
 }
 
@@ -508,6 +508,6 @@ 
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return erase_chip_jedec_common(flash, mask);
 }
Index: flashrom-flashctx_separate_struct_flashchip/w39.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/w39.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/w39.c	(Arbeitskopie)
@@ -138,11 +138,11 @@ 
 
 static int printlock_w39_fwh(struct flashctx *flash)
 {
-	unsigned int i, total_size = flash->total_size * 1024;
+	unsigned int i, total_size = flash->chip->total_size * 1024;
 	int ret = 0;
 	
 	/* Print lock status of the complete chip */
-	for (i = 0; i < total_size; i += flash->page_size)
+	for (i = 0; i < total_size; i += flash->chip->page_size)
 		ret |= printlock_w39_fwh_block(flash, i);
 
 	return ret;
@@ -150,10 +150,10 @@ 
 
 static int unlock_w39_fwh(struct flashctx *flash)
 {
-	unsigned int i, total_size = flash->total_size * 1024;
+	unsigned int i, total_size = flash->chip->total_size * 1024;
 	
 	/* Unlock the complete chip */
-	for (i = 0; i < total_size; i += flash->page_size)
+	for (i = 0; i < total_size; i += flash->chip->page_size)
 		if (unlock_w39_fwh_block(flash, i))
 			return -1;
 
Index: flashrom-flashctx_separate_struct_flashchip/sst49lfxxxc.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/sst49lfxxxc.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/sst49lfxxxc.c	(Arbeitskopie)
@@ -38,7 +38,7 @@ 
 static int write_lockbits_49lfxxxc(struct flashctx *flash, unsigned char bits)
 {
 	chipaddr registers = flash->virtual_registers;
-	unsigned int i, left = flash->total_size * 1024;
+	unsigned int i, left = flash->chip->total_size * 1024;
 	unsigned long address;
 
 	msg_cdbg("\nbios=0x%08lx\n", registers);
Index: flashrom-flashctx_separate_struct_flashchip/sst_fwhub.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/sst_fwhub.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/sst_fwhub.c	(Arbeitskopie)
@@ -31,7 +31,7 @@ 
 
 	blockstatus = chip_readb(flash, registers + offset + 2);
 	msg_cdbg("Lock status for 0x%06x (size 0x%06x) is %02x, ",
-		     offset, flash->page_size, blockstatus);
+		     offset, flash->chip->page_size, blockstatus);
 	switch (blockstatus & 0x3) {
 	case 0x0:
 		msg_cdbg("full access\n");
@@ -72,7 +72,7 @@ 
 {
 	int i;
 
-	for (i = 0; i < flash->total_size * 1024; i += flash->page_size)
+	for (i = 0; i < flash->chip->total_size * 1024; i += flash->chip->page_size)
 		check_sst_fwhub_block_lock(flash, i);
 
 	return 0;
@@ -82,7 +82,7 @@ 
 {
 	int i, ret=0;
 
-	for (i = 0; i < flash->total_size * 1024; i += flash->page_size)
+	for (i = 0; i < flash->chip->total_size * 1024; i += flash->chip->page_size)
 	{
 		if (clear_sst_fwhub_block_lock(flash, i))
 		{
Index: flashrom-flashctx_separate_struct_flashchip/cli_classic.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/cli_classic.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/cli_classic.c	(Arbeitskopie)
@@ -109,8 +109,8 @@ 
 {
 	unsigned long size;
 	/* Probe for up to three flash chips. */
-	const struct flashchip *flash;
-	struct flashctx flashes[3];
+	const struct flashchip *chip;
+	struct flashctx flashes[3] = {};
 	struct flashctx *fill_flash;
 	const char *name;
 	int namelen, opt, i, j;
@@ -389,17 +389,16 @@ 
 	}
 	/* Does a chip with the requested name exist in the flashchips array? */
 	if (chip_to_probe) {
-		for (flash = flashchips; flash && flash->name; flash++)
-			if (!strcmp(flash->name, chip_to_probe))
+		for (chip = flashchips; chip && chip->name; chip++)
+			if (!strcmp(chip->name, chip_to_probe))
 				break;
-		if (!flash || !flash->name) {
+		if (!chip || !chip->name) {
 			msg_cerr("Error: Unknown chip '%s' specified.\n", chip_to_probe);
 			msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n");
 			ret = 1;
 			goto out;
 		}
-		/* Clean up after the check. */
-		flash = NULL;
+		/* Keep chip around for later usage. */
 	}
 
 	if (prog == PROGRAMMER_INVALID) {
@@ -419,16 +418,13 @@ 
 		goto out_shutdown;
 	}
 	tempstr = flashbuses_to_text(get_buses_supported());
-	msg_pdbg("The following protocols are supported: %s.\n",
-		 tempstr);
+	msg_pdbg("The following protocols are supported: %s.\n", tempstr);
 	free(tempstr);
 
 	for (j = 0; j < registered_programmer_count; j++) {
 		startchip = 0;
 		while (chipcount < ARRAY_SIZE(flashes)) {
-			startchip = probe_flash(&registered_programmers[j],
-						startchip, 
-						&flashes[chipcount], 0);
+			startchip = probe_flash(&registered_programmers[j], startchip, &flashes[chipcount], 0);
 			if (startchip == -1)
 				break;
 			chipcount++;
@@ -437,9 +433,9 @@ 
 	}
 
 	if (chipcount > 1) {
-		msg_cinfo("Multiple flash chips were detected: \"%s\"", flashes[0].name);
+		msg_cinfo("Multiple flash chips were detected: \"%s\"", flashes[0].chip->name);
 		for (i = 1; i < chipcount; i++)
-			msg_cinfo(", \"%s\"", flashes[i].name);
+			msg_cinfo(", \"%s\"", flashes[i].chip->name);
 		msg_cinfo("\nPlease specify which chip to use with the -c <chipname> option.\n");
 		ret = 1;
 		goto out_shutdown;
@@ -456,9 +452,15 @@ 
 			/* This loop just counts compatible controllers. */
 			for (j = 0; j < registered_programmer_count; j++) {
 				pgm = &registered_programmers[j];
-				if (pgm->buses_supported & flashes[0].bustype)
+				/* chip is still set from the chip_to_probe earlier in this function. */
+				if (pgm->buses_supported & chip->bustype)
 					compatible_programmers++;
 			}
+			if (!compatible_programmers) {
+				msg_cinfo("No compatible controller found for the requested flash chip.\n");
+				ret = 1;
+				goto out_shutdown;
+			}
 			if (compatible_programmers > 1)
 				msg_cinfo("More than one compatible controller found for the requested flash "
 					  "chip, using the first one.\n");
@@ -469,6 +471,7 @@ 
 					break;
 			}
 			if (startchip == -1) {
+				// FIXME: This should never happen! Ask for a bug report?
 				msg_cinfo("Probing for flash chip '%s' failed.\n", chip_to_probe);
 				ret = 1;
 				goto out_shutdown;
@@ -481,19 +484,18 @@ 
 		goto out_shutdown;
 	} else if (!chip_to_probe) {
 		/* repeat for convenience when looking at foreign logs */
-		tempstr = flashbuses_to_text(flashes[0].bustype);
+		tempstr = flashbuses_to_text(flashes[0].chip->bustype);
 		msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
-			 flashes[0].vendor, flashes[0].name,
-			 flashes[0].total_size, tempstr);
+			 flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size, tempstr);
 		free(tempstr);
 	}
 
 	fill_flash = &flashes[0];
 
-	check_chip_supported(fill_flash);
+	check_chip_supported(fill_flash->chip);
 
-	size = fill_flash->total_size * 1024;
-	if (check_max_decode(fill_flash->pgm->buses_supported & fill_flash->bustype, size) && (!force)) {
+	size = fill_flash->chip->total_size * 1024;
+	if (check_max_decode(fill_flash->pgm->buses_supported & fill_flash->chip->bustype, size) && (!force)) {
 		msg_cerr("Chip is too big for this programmer (-V gives details). Use --force to override.\n");
 		ret = 1;
 		goto out_shutdown;
Index: flashrom-flashctx_separate_struct_flashchip/layout.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/layout.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/layout.c	(Arbeitskopie)
@@ -221,7 +221,7 @@ 
 {
 	unsigned int start = 0;
 	romlayout_t *entry;
-	unsigned int size = flash->total_size * 1024;
+	unsigned int size = flash->chip->total_size * 1024;
 
 	/* If no regions were specified for inclusion, assume
 	 * that the user wants to write the complete new image.
Index: flashrom-flashctx_separate_struct_flashchip/ichspi.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/ichspi.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/ichspi.c	(Arbeitskopie)
@@ -1193,9 +1193,9 @@ 
 	else
 		msg_cdbg(" with a");
 	msg_cdbg(" density of %d kB.\n", total_size / 1024);
-	flash->total_size = total_size / 1024;
+	flash->chip->total_size = total_size / 1024;
 
-	eraser = &(flash->block_erasers[0]);
+	eraser = &(flash->chip->block_erasers[0]);
 	boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12;
 	size_high = total_size - boundary;
 	erase_size_high = ich_hwseq_get_erase_block_size(boundary);
@@ -1228,7 +1228,7 @@ 
 		msg_cdbg("In that range are %d erase blocks with %d B each.\n",
 			 size_high / erase_size_high, erase_size_high);
 	}
-	flash->tested = TEST_OK_PREW;
+	flash->chip->tested = TEST_OK_PREW;
 	return 1;
 }
 
@@ -1256,7 +1256,7 @@ 
 		return -1;
 	}
 
-	if (addr + len > flash->total_size * 1024) {
+	if (addr + len > flash->chip->total_size * 1024) {
 		msg_perr("Request to erase some inaccessible memory address(es)"
 			 " (addr=0x%x, len=%d). "
 			 "Not erasing anything.\n", addr, len);
@@ -1288,7 +1288,7 @@ 
 	uint16_t timeout = 100 * 60;
 	uint8_t block_len;
 
-	if (addr + len > flash->total_size * 1024) {
+	if (addr + len > flash->chip->total_size * 1024) {
 		msg_perr("Request to read from an inaccessible memory address "
 			 "(addr=0x%x, len=%d).\n", addr, len);
 		return -1;
@@ -1326,7 +1326,7 @@ 
 	uint16_t timeout = 100 * 60;
 	uint8_t block_len;
 
-	if (addr + len > flash->total_size * 1024) {
+	if (addr + len > flash->chip->total_size * 1024) {
 		msg_perr("Request to write to an inaccessible memory address "
 			 "(addr=0x%x, len=%d).\n", addr, len);
 		return -1;
Index: flashrom-flashctx_separate_struct_flashchip/82802ab.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/82802ab.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/82802ab.c	(Arbeitskopie)
@@ -44,7 +44,7 @@ 
 {
 	chipaddr bios = flash->virtual_memory;
 	uint8_t id1, id2, flashcontent1, flashcontent2;
-	int shifted = (flash->feature_bits & FEATURE_ADDR_SHIFTED) != 0;
+	int shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED) != 0;
 
 	/* Reset to get a clean state */
 	chip_writeb(flash, 0xFF, bios);
@@ -80,10 +80,10 @@ 
 		msg_cdbg(", id2 is normal flash content");
 
 	msg_cdbg("\n");
-	if (id1 != flash->manufacture_id || id2 != flash->model_id)
+	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
 		return 0;
 
-	if (flash->feature_bits & FEATURE_REGISTERMAP)
+	if (flash->chip->feature_bits & FEATURE_REGISTERMAP)
 		map_flash_registers(flash);
 
 	return 1;
@@ -112,7 +112,7 @@ 
 	int i;
 	//chipaddr wrprotect = flash->virtual_registers + page + 2;
 
-	for (i = 0; i < flash->total_size * 1024; i+= flash->page_size)
+	for (i = 0; i < flash->chip->total_size * 1024; i+= flash->chip->page_size)
 		chip_writeb(flash, 0, flash->virtual_registers + i + 2);
 
 	return 0;
@@ -181,7 +181,7 @@ 
 	}
 
 	/* Read block lock-bits */
-	for (i = 0; i < flash->total_size * 1024; i+= (64 * 1024)) {
+	for (i = 0; i < flash->chip->total_size * 1024; i+= (64 * 1024)) {
 		bcfg = chip_readb(flash, bios + i + 2); // read block lock config
 		msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un");
 		if (bcfg) {
@@ -234,7 +234,7 @@ 
 	}
 
 	/* Read block lock-bits, 8 * 8 KB + 15 * 64 KB */
-	for (i = 0; i < flash->total_size * 1024;
+	for (i = 0; i < flash->chip->total_size * 1024;
 	     i += (i >= (64 * 1024) ? 64 * 1024 : 8 * 1024)) {
 		bcfg = chip_readb(flash, bios + i + 2); /* read block lock config */
 		msg_cdbg("block lock at %06x is %slocked!\n", i,
Index: flashrom-flashctx_separate_struct_flashchip/dediprog.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/dediprog.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/dediprog.c	(Arbeitskopie)
@@ -381,7 +381,7 @@ 
 			      unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
 {
 	int ret;
-	const unsigned int chunksize = flash->page_size;
+	const unsigned int chunksize = flash->chip->page_size;
 	unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
 	unsigned int bulklen;
 
Index: flashrom-flashctx_separate_struct_flashchip/spi25.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/spi25.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/spi25.c	(Arbeitskopie)
@@ -147,7 +147,7 @@ 
 
 	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
+	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id) {
 		/* Print the status register to tell the
 		 * user about possible write protection.
 		 */
@@ -157,12 +157,12 @@ 
 	}
 
 	/* Test if this is a pure vendor match. */
-	if (id1 == flash->manufacture_id &&
-	    GENERIC_DEVICE_ID == flash->model_id)
+	if (id1 == flash->chip->manufacture_id &&
+	    GENERIC_DEVICE_ID == flash->chip->model_id)
 		return 1;
 
 	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == flash->manufacture_id &&
+	if (GENERIC_MANUF_ID == flash->chip->manufacture_id &&
 	    id1 != 0xff)
 		return 1;
 
@@ -210,7 +210,7 @@ 
 
 	msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
+	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id) {
 		/* Print the status register to tell the
 		 * user about possible write protection.
 		 */
@@ -220,12 +220,12 @@ 
 	}
 
 	/* Test if this is a pure vendor match. */
-	if (id1 == flash->manufacture_id &&
-	    GENERIC_DEVICE_ID == flash->model_id)
+	if (id1 == flash->chip->manufacture_id &&
+	    GENERIC_DEVICE_ID == flash->chip->model_id)
 		return 1;
 
 	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == flash->manufacture_id &&
+	if (GENERIC_MANUF_ID == flash->chip->manufacture_id &&
 	    id1 != 0xff)
 		return 1;
 
@@ -267,7 +267,7 @@ 
 
 	msg_cdbg("%s: id 0x%x\n", __func__, id2);
 
-	if (id2 != flash->model_id)
+	if (id2 != flash->chip->model_id)
 		return 0;
 
 	/* Print the status register to tell the
@@ -291,7 +291,7 @@ 
 
 	msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
 
-	if (id1 != flash->manufacture_id || id2 != flash->model_id)
+	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
 		return 0;
 
 	/* Print the status register to tell the
@@ -423,18 +423,18 @@ 
 
 	status = spi_read_status_register(flash);
 	msg_cdbg("Chip status register is %02x\n", status);
-	switch (flash->manufacture_id) {
+	switch (flash->chip->manufacture_id) {
 	case ST_ID:
-		if (((flash->model_id & 0xff00) == 0x2000) ||
-		    ((flash->model_id & 0xff00) == 0x2500))
+		if (((flash->chip->model_id & 0xff00) == 0x2000) ||
+		    ((flash->chip->model_id & 0xff00) == 0x2500))
 			spi_prettyprint_status_register_st_m25p(status);
 		break;
 	case MACRONIX_ID:
-		if ((flash->model_id & 0xff00) == 0x2000)
+		if ((flash->chip->model_id & 0xff00) == 0x2000)
 			spi_prettyprint_status_register_st_m25p(status);
 		break;
 	case SST_ID:
-		switch (flash->model_id) {
+		switch (flash->chip->model_id) {
 		case 0x2541:
 			spi_prettyprint_status_register_sst25vf016(status);
 			break;
@@ -704,7 +704,7 @@ 
 int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
 		       unsigned int blocklen)
 {
-	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+	if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n",
 			__func__);
 		return -1;
@@ -715,7 +715,7 @@ 
 int spi_block_erase_c7(struct flashctx *flash, unsigned int addr,
 		       unsigned int blocklen)
 {
-	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+	if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n",
 			__func__);
 		return -1;
@@ -820,7 +820,7 @@ 
 
 int spi_write_status_register(struct flashctx *flash, int status)
 {
-	int feature_bits = flash->feature_bits;
+	int feature_bits = flash->chip->feature_bits;
 	int ret = 1;
 
 	if (!(feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
@@ -972,7 +972,7 @@ 
 {
 	int rc = 0;
 	unsigned int i, j, starthere, lenhere, toread;
-	unsigned int page_size = flash->page_size;
+	unsigned int page_size = flash->chip->page_size;
 
 	/* Warning: This loop has a very unusual condition and body.
 	 * The loop needs to go through each page with at least one affected
@@ -1017,7 +1017,7 @@ 
 	 * spi_chip_write_256 have page_size set to max_writechunk_size, so
 	 * we're OK for now.
 	 */
-	unsigned int page_size = flash->page_size;
+	unsigned int page_size = flash->chip->page_size;
 
 	/* Warning: This loop has a very unusual condition and body.
 	 * The loop needs to go through each page with at least one affected
Index: flashrom-flashctx_separate_struct_flashchip/pm49fl00x.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/pm49fl00x.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/pm49fl00x.c	(Arbeitskopie)
@@ -40,14 +40,14 @@ 
 
 int unlock_49fl00x(struct flashctx *flash)
 {
-	write_lockbits_49fl00x(flash, flash->total_size * 1024, 0,
-			       flash->page_size);
+	write_lockbits_49fl00x(flash, flash->chip->total_size * 1024, 0,
+			       flash->chip->page_size);
 	return 0;
 }
 
 int lock_49fl00x(struct flashctx *flash)
 {
-	write_lockbits_49fl00x(flash, flash->total_size * 1024, 1,
-			       flash->page_size);
+	write_lockbits_49fl00x(flash, flash->chip->total_size * 1024, 1,
+			       flash->chip->page_size);
 	return 0;
 }
Index: flashrom-flashctx_separate_struct_flashchip/en29lv640b.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/en29lv640b.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/en29lv640b.c	(Arbeitskopie)
@@ -81,7 +81,7 @@ 
 
 	msg_cdbg("%s: id1 0x%04x, id2 0x%04x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
 		return 1;
 
 	return 0;
@@ -130,7 +130,7 @@ 
 int block_erase_chip_en29lv640b(struct flashctx *flash, unsigned int address,
 			        unsigned int blocklen)
 {
-	if ((address != 0) || (blocklen != flash->total_size * 1024)) {
+	if ((address != 0) || (blocklen != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n", __func__);
 		return -1;
 	}
Index: flashrom-flashctx_separate_struct_flashchip/w29ee011.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/w29ee011.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/w29ee011.c	(Arbeitskopie)
@@ -29,11 +29,11 @@ 
 	chipaddr bios = flash->virtual_memory;
 	uint8_t id1, id2;
 
-	if (!chip_to_probe || strcmp(chip_to_probe, flash->name)) {
+	if (!chip_to_probe || strcmp(chip_to_probe, flash->chip->name)) {
 		msg_cdbg("Old Winbond W29* probe method disabled because "
 			 "the probing sequence puts the AMIC A49LF040A in "
 			 "a funky state. Use 'flashrom -c %s' if you "
-			 "have a board with such a chip.\n", flash->name);
+			 "have a board with such a chip.\n", flash->chip->name);
 		return 0;
 	}
 
@@ -65,7 +65,7 @@ 
 
 	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
 		return 1;
 
 	return 0;
Index: flashrom-flashctx_separate_struct_flashchip/spi.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/spi.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/spi.c	(Arbeitskopie)
@@ -111,16 +111,16 @@ 
 	 * means 0xffffff, the highest unsigned 24bit number.
 	 */
 	addrbase = spi_get_valid_read_addr(flash);
-	if (addrbase + flash->total_size * 1024 > (1 << 24)) {
+	if (addrbase + flash->chip->total_size * 1024 > (1 << 24)) {
 		msg_perr("Flash chip size exceeds the allowed access window. ");
 		msg_perr("Read will probably fail.\n");
 		/* Try to get the best alignment subject to constraints. */
-		addrbase = (1 << 24) - flash->total_size * 1024;
+		addrbase = (1 << 24) - flash->chip->total_size * 1024;
 	}
 	/* Check if alignment is native (at least the largest power of two which
 	 * is a factor of the mapped size of the chip).
 	 */
-	if (ffs(flash->total_size * 1024) > (ffs(addrbase) ? : 33)) {
+	if (ffs(flash->chip->total_size * 1024) > (ffs(addrbase) ? : 33)) {
 		msg_perr("Flash chip is not aligned natively in the allowed "
 			 "access window.\n");
 		msg_perr("Read will probably return garbage.\n");
Index: flashrom-flashctx_separate_struct_flashchip/sfdp.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/sfdp.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/sfdp.c	(Arbeitskopie)
@@ -84,7 +84,7 @@ 
 static int sfdp_add_uniform_eraser(struct flashctx *flash, uint8_t opcode, uint32_t block_size)
 {
 	int i;
-	uint32_t total_size = flash->total_size * 1024;
+	uint32_t total_size = flash->chip->total_size * 1024;
 	erasefunc_t *erasefn = spi_get_erasefn_from_opcode(opcode);
 
 	if (erasefn == NULL || total_size == 0 || block_size == 0 ||
@@ -95,7 +95,7 @@ 
 	}
 
 	for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
-		struct block_eraser *eraser = &flash->block_erasers[i];
+		struct block_eraser *eraser = &flash->chip->block_erasers[i];
 		/* Check for duplicates (including (some) non-uniform ones). */
 		if (eraser->eraseblocks[0].size == block_size &&
 		    eraser->block_erase == erasefn) {
@@ -170,28 +170,28 @@ 
 		msg_cdbg2("volatile and writes to the status register have to "
 			  "be enabled with ");
 		if (tmp32 & (1 << 4)) {
-			flash->feature_bits = FEATURE_WRSR_WREN;
+			flash->chip->feature_bits = FEATURE_WRSR_WREN;
 			msg_cdbg2("WREN (0x06).\n");
 		} else {
-			flash->feature_bits = FEATURE_WRSR_EWSR;
+			flash->chip->feature_bits = FEATURE_WRSR_EWSR;
 			msg_cdbg2("EWSR (0x50).\n");
 		}
 	} else {
 		msg_cdbg2("non-volatile and the standard does not allow "
 			  "vendors to tell us whether EWSR/WREN is needed for "
 			  "status register writes - assuming EWSR.\n");
-			flash->feature_bits = FEATURE_WRSR_EWSR;
+			flash->chip->feature_bits = FEATURE_WRSR_EWSR;
 		}
 
 	msg_cdbg2("  Write chunk size is ");
 	if (tmp32 & (1 << 2)) {
 		msg_cdbg2("at least 64 B.\n");
-		flash->page_size = 64;
-		flash->write = spi_chip_write_256;
+		flash->chip->page_size = 64;
+		flash->chip->write = spi_chip_write_256;
 	} else {
 		msg_cdbg2("1 B only.\n");
-		flash->page_size = 256;
-		flash->write = spi_chip_write_1;
+		flash->chip->page_size = 256;
+		flash->chip->write = spi_chip_write_1;
 	}
 
 	if ((tmp32 & 0x3) == 0x1) {
@@ -212,8 +212,8 @@ 
 		return 1;
 	}
 	total_size = ((tmp32 & 0x7FFFFFFF) + 1) / 8;
-	flash->total_size = total_size / 1024;
-	msg_cdbg2("  Flash chip size is %d kB.\n", flash->total_size);
+	flash->chip->total_size = total_size / 1024;
+	msg_cdbg2("  Flash chip size is %d kB.\n", flash->chip->total_size);
 	if (total_size > (1 << 24)) {
 		msg_cdbg("Flash chip size is bigger than what 3-Byte addressing "
 			 "can access.\n");
Index: flashrom-flashctx_separate_struct_flashchip/sst28sf040.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/sst28sf040.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/sst28sf040.c	(Arbeitskopie)
@@ -119,7 +119,7 @@ 
 int erase_chip_28sf040(struct flashctx *flash, unsigned int addr,
 		       unsigned int blocklen)
 {
-	if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+	if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n",
 			__func__);
 		return -1;
Index: flashrom-flashctx_separate_struct_flashchip/stm50flw0x0x.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/stm50flw0x0x.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/stm50flw0x0x.c	(Arbeitskopie)
@@ -54,7 +54,7 @@ 
 	/* Check, if it's is a top/bottom-block with 4k-sectors. */
 	/* TODO: What about the other types? */
 	if ((offset == 0) ||
-	    (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
+	    (offset == (flash->chip->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
 	    || (offset == 0xF0000)) {
 
 		// unlock each 4k-sector
@@ -85,7 +85,7 @@ 
 {
 	int i;
 
-	for (i = 0; i < flash->total_size * 1024; i+= flash->page_size) {
+	for (i = 0; i < flash->chip->total_size * 1024; i+= flash->chip->page_size) {
 		if(unlock_block_stm50flw0x0x(flash, i)) {
 			msg_cerr("UNLOCK FAILED!\n");
 			return -1;
Index: flashrom-flashctx_separate_struct_flashchip/flashrom.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/flashrom.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/flashrom.c	(Arbeitskopie)
@@ -416,7 +416,7 @@ 
 
 void map_flash_registers(struct flashctx *flash)
 {
-	size_t size = flash->total_size * 1024;
+	size_t size = flash->chip->total_size * 1024;
 	/* Flash registers live 4 MByte below the flash. */
 	/* FIXME: This is incorrect for nonstandard flashbase. */
 	flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
@@ -580,7 +580,7 @@ 
 	if (!len)
 		goto out_free;
 
-	if (!flash->read) {
+	if (!flash->chip->read) {
 		msg_cerr("ERROR: flashrom has no read function for this flash chip.\n");
 		return 1;
 	}
@@ -589,17 +589,17 @@ 
 		exit(1);
 	}
 
-	if (start + len > flash->total_size * 1024) {
+	if (start + len > flash->chip->total_size * 1024) {
 		msg_gerr("Error: %s called with start 0x%x + len 0x%x >"
 			" total_size 0x%x\n", __func__, start, len,
-			flash->total_size * 1024);
+			flash->chip->total_size * 1024);
 		ret = -1;
 		goto out_free;
 	}
 	if (!message)
 		message = "VERIFY";
 
-	ret = flash->read(flash, readbuf, start, len);
+	ret = flash->chip->read(flash, readbuf, start, len);
 	if (ret) {
 		msg_gerr("Verification impossible because read failed "
 			 "at 0x%x (len 0x%x)\n", start, len);
@@ -950,44 +950,52 @@ 
 	return 1;
 }
 
-int probe_flash(struct registered_programmer *pgm, int startchip,
-		struct flashctx *fill_flash, int force)
+int probe_flash(struct registered_programmer *pgm, int startchip, struct flashctx *flash, int force)
 {
-	const struct flashchip *flash;
+	const struct flashchip *chip;
 	unsigned long base = 0;
 	char location[64];
 	uint32_t size;
 	enum chipbustype buses_common;
 	char *tmp;
 
-	for (flash = flashchips + startchip; flash && flash->name; flash++) {
-		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
+	for (chip = flashchips + startchip; chip && chip->name; chip++) {
+		if (chip_to_probe && strcmp(chip->name, chip_to_probe) != 0)
 			continue;
-		buses_common = pgm->buses_supported & flash->bustype;
+		buses_common = pgm->buses_supported & chip->bustype;
 		if (!buses_common)
 			continue;
 		msg_gdbg("Probing for %s %s, %d kB: ",
-			     flash->vendor, flash->name, flash->total_size);
-		if (!flash->probe && !force) {
+			     chip->vendor, chip->name, chip->total_size);
+		if (!chip->probe && !force) {
 			msg_gdbg("failed! flashrom has no probe function for "
 				 "this flash chip.\n");
 			continue;
 		}
 
-		size = flash->total_size * 1024;
+		size = chip->total_size * 1024;
 		check_max_decode(buses_common, size);
 
 		/* Start filling in the dynamic data. */
-		memcpy(fill_flash, flash, sizeof(struct flashchip));
-		fill_flash->pgm = pgm;
+		flash->chip = calloc(1, sizeof(struct flashchip));
+		if (!flash->chip) {
+			msg_gerr("Out of memory!\n");
+			// FIXME: Is -1 the right return code?
+			return -1;
+		}
+		memcpy(flash->chip, chip, sizeof(struct flashchip));
+		flash->pgm = pgm;
 
 		base = flashbase ? flashbase : (0xffffffff - size + 1);
-		fill_flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
+		flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
 
+		/* We handle a forced match like a real match, we just avoid probing. Note that probe_flash()
+		 * is only called with force=1 after normal probing failed.
+		 */
 		if (force)
 			break;
 
-		if (fill_flash->probe(fill_flash) != 1)
+		if (flash->chip->probe(flash) != 1)
 			goto notfound;
 
 		/* If this is the first chip found, accept it.
@@ -997,11 +1005,11 @@ 
 		 * one for this programmer interface and thus no other chip has
 		 * been found on this interface.
 		 */
-		if (startchip == 0 && fill_flash->model_id == SFDP_DEVICE_ID) {
+		if (startchip == 0 && flash->chip->model_id == SFDP_DEVICE_ID) {
 			msg_cinfo("===\n"
 				  "SFDP has autodetected a flash chip which is "
 				  "not natively supported by flashrom yet.\n");
-			if (count_usable_erasers(fill_flash) == 0)
+			if (count_usable_erasers(flash) == 0)
 				msg_cinfo("The standard operations read and "
 					  "verify should work, but to support "
 					  "erase, write and all other "
@@ -1022,15 +1030,18 @@ 
 		}
 
 		if (startchip == 0 ||
-		    ((fill_flash->model_id != GENERIC_DEVICE_ID) &&
-		     (fill_flash->model_id != SFDP_DEVICE_ID)))
+		    ((flash->chip->model_id != GENERIC_DEVICE_ID) &&
+		     (flash->chip->model_id != SFDP_DEVICE_ID)))
 			break;
 
 notfound:
-		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
+		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
+		flash->virtual_memory = (chipaddr)NULL;
+		free(flash->chip);
+		flash->chip = NULL;
 	}
 
-	if (!flash || !flash->name)
+	if (!flash->chip)
 		return -1;
 
 #if CONFIG_INTERNAL == 1
@@ -1040,27 +1051,26 @@ 
 #endif
 		snprintf(location, sizeof(location), "on %s", programmer_table[programmer].name);
 
-	tmp = flashbuses_to_text(flash->bustype);
-	msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) %s.\n",
-		  force ? "Assuming" : "Found", fill_flash->vendor,
-		  fill_flash->name, fill_flash->total_size, tmp, location);
+	tmp = flashbuses_to_text(flash->chip->bustype);
+	msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) %s.\n", force ? "Assuming" : "Found",
+		  flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp, location);
 	free(tmp);
 
 	/* Flash registers will not be mapped if the chip was forced. Lock info
 	 * may be stored in registers, so avoid lock info printing.
 	 */
 	if (!force)
-		if (fill_flash->printlock)
-			fill_flash->printlock(fill_flash);
+		if (flash->chip->printlock)
+			flash->chip->printlock(flash);
 
 	/* Return position of matching chip. */
-	return flash - flashchips;
+	return chip - flashchips;
 }
 
 int verify_flash(struct flashctx *flash, uint8_t *buf)
 {
 	int ret;
-	unsigned int total_size = flash->total_size * 1024;
+	unsigned int total_size = flash->chip->total_size * 1024;
 
 	msg_cinfo("Verifying flash... ");
 
@@ -1133,7 +1143,7 @@ 
 
 int read_flash_to_file(struct flashctx *flash, const char *filename)
 {
-	unsigned long size = flash->total_size * 1024;
+	unsigned long size = flash->chip->total_size * 1024;
 	unsigned char *buf = calloc(size, sizeof(char));
 	int ret = 0;
 
@@ -1143,12 +1153,12 @@ 
 		msg_cinfo("FAILED.\n");
 		return 1;
 	}
-	if (!flash->read) {
+	if (!flash->chip->read) {
 		msg_cerr("No read function available for this flash chip.\n");
 		ret = 1;
 		goto out_free;
 	}
-	if (flash->read(flash, buf, 0, size)) {
+	if (flash->chip->read(flash, buf, 0, size)) {
 		msg_cerr("Read operation failed!\n");
 		ret = 1;
 		goto out_free;
@@ -1165,14 +1175,14 @@ 
  * walk_eraseregions().
  * Even if an error is found, the function will keep going and check the rest.
  */
-static int selfcheck_eraseblocks(const struct flashchip *flash)
+static int selfcheck_eraseblocks(const struct flashchip *chip)
 {
 	int i, j, k;
 	int ret = 0;
 
 	for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
 		unsigned int done = 0;
-		struct block_eraser eraser = flash->block_erasers[k];
+		struct block_eraser eraser = chip->block_erasers[k];
 
 		for (i = 0; i < NUM_ERASEREGIONS; i++) {
 			/* Blocks with zero size are bugs in flashchips.c. */
@@ -1181,7 +1191,7 @@ 
 				msg_gerr("ERROR: Flash chip %s erase function "
 					"%i region %i has size 0. Please report"
 					" a bug at flashrom@flashrom.org\n",
-					flash->name, k, i);
+					chip->name, k, i);
 				ret = 1;
 			}
 			/* Blocks with zero count are bugs in flashchips.c. */
@@ -1190,7 +1200,7 @@ 
 				msg_gerr("ERROR: Flash chip %s erase function "
 					"%i region %i has count 0. Please report"
 					" a bug at flashrom@flashrom.org\n",
-					flash->name, k, i);
+					chip->name, k, i);
 				ret = 1;
 			}
 			done += eraser.eraseblocks[i].count *
@@ -1202,12 +1212,12 @@ 
 				  "non-empty erase function. Not an error.\n");
 		if (!done)
 			continue;
-		if (done != flash->total_size * 1024) {
+		if (done != chip->total_size * 1024) {
 			msg_gerr("ERROR: Flash chip %s erase function %i "
 				"region walking resulted in 0x%06x bytes total,"
 				" expected 0x%06x bytes. Please report a bug at"
-				" flashrom@flashrom.org\n", flash->name, k,
-				done, flash->total_size * 1024);
+				" flashrom@flashrom.org\n", chip->name, k,
+				done, chip->total_size * 1024);
 			ret = 1;
 		}
 		if (!eraser.block_erase)
@@ -1218,11 +1228,11 @@ 
 		 */
 		for (j = k + 1; j < NUM_ERASEFUNCTIONS; j++) {
 			if (eraser.block_erase ==
-			    flash->block_erasers[j].block_erase) {
+			    chip->block_erasers[j].block_erase) {
 				msg_gerr("ERROR: Flash chip %s erase function "
 					"%i and %i are identical. Please report"
 					" a bug at flashrom@flashrom.org\n",
-					flash->name, k, j);
+					chip->name, k, j);
 				ret = 1;
 			}
 		}
@@ -1269,7 +1279,7 @@ 
 		if (!writecount++)
 			msg_cdbg("W");
 		/* Needs the partial write function signature. */
-		ret = flash->write(flash, newcontents + starthere,
+		ret = flash->chip->write(flash, newcontents + starthere,
 				   start + starthere, lenhere);
 		if (ret)
 			return ret;
@@ -1296,7 +1306,7 @@ 
 	int i, j;
 	unsigned int start = 0;
 	unsigned int len;
-	struct block_eraser eraser = flash->block_erasers[erasefunction];
+	struct block_eraser eraser = flash->chip->block_erasers[erasefunction];
 
 	for (i = 0; i < NUM_ERASEREGIONS; i++) {
 		/* count==0 for all automatically initialized array
@@ -1322,7 +1332,7 @@ 
 
 static int check_block_eraser(const struct flashctx *flash, int k, int log)
 {
-	struct block_eraser eraser = flash->block_erasers[k];
+	struct block_eraser eraser = flash->chip->block_erasers[k];
 
 	if (!eraser.block_erase && !eraser.eraseblocks[0].count) {
 		if (log)
@@ -1341,6 +1351,7 @@ 
 				 "eraseblock layout is not defined. ");
 		return 1;
 	}
+	// TODO: Once erase functions are annotated with allowed buses, check that as well.
 	return 0;
 }
 
@@ -1349,7 +1360,7 @@ 
 {
 	int k, ret = 1;
 	uint8_t *curcontents;
-	unsigned long size = flash->total_size * 1024;
+	unsigned long size = flash->chip->total_size * 1024;
 	unsigned int usable_erasefunctions = count_usable_erasers(flash);
 
 	msg_cinfo("Erasing and writing flash chip... ");
@@ -1387,7 +1398,7 @@ 
 		 * in non-verbose mode.
 		 */
 		msg_cinfo("Reading current flash chip contents... ");
-		if (flash->read(flash, curcontents, 0, size)) {
+		if (flash->chip->read(flash, curcontents, 0, size)) {
 			/* Now we are truly screwed. Read failed as well. */
 			msg_cerr("Can't read anymore! Aborting.\n");
 			/* We have no idea about the flash chip contents, so
@@ -1576,7 +1587,7 @@ 
 int selfcheck(void)
 {
 	int ret = 0;
-	const struct flashchip *flash;
+	const struct flashchip *chip;
 
 	/* Safety check. Instead of aborting after the first error, check
 	 * if more errors exist.
@@ -1594,16 +1605,8 @@ 
 		msg_gerr("Flashchips table miscompilation!\n");
 		ret = 1;
 	}
-	/* Check that virtual_memory in struct flashctx is placed directly
-	 * after the members copied from struct flashchip.
-	 */
-	if (sizeof(struct flashchip) !=
-	    offsetof(struct flashctx, virtual_memory)) {
-		msg_gerr("struct flashctx broken!\n");
-		ret = 1;
-	}
-	for (flash = flashchips; flash && flash->name; flash++)
-		if (selfcheck_eraseblocks(flash))
+	for (chip = flashchips; chip && chip->name; chip++)
+		if (selfcheck_eraseblocks(chip))
 			ret = 1;
 
 #if CONFIG_INTERNAL == 1
@@ -1627,41 +1630,41 @@ 
 	return ret;
 }
 
-void check_chip_supported(const struct flashctx *flash)
+void check_chip_supported(const struct flashchip *chip)
 {
-	if (flash->feature_bits & FEATURE_OTP) {
+	if (chip->feature_bits & FEATURE_OTP) {
 		msg_cdbg("This chip may contain one-time programmable memory. "
 			 "flashrom cannot read\nand may never be able to write "
 			 "it, hence it may not be able to completely\n"
 			 "clone the contents of this chip (see man page for "
 			 "details).\n");
 	}
-	if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) {
+	if (TEST_OK_MASK != (chip->tested & TEST_OK_MASK)) {
 		msg_cinfo("===\n");
-		if (flash->tested & TEST_BAD_MASK) {
+		if (chip->tested & TEST_BAD_MASK) {
 			msg_cinfo("This flash part has status NOT WORKING for operations:");
-			if (flash->tested & TEST_BAD_PROBE)
+			if (chip->tested & TEST_BAD_PROBE)
 				msg_cinfo(" PROBE");
-			if (flash->tested & TEST_BAD_READ)
+			if (chip->tested & TEST_BAD_READ)
 				msg_cinfo(" READ");
-			if (flash->tested & TEST_BAD_ERASE)
+			if (chip->tested & TEST_BAD_ERASE)
 				msg_cinfo(" ERASE");
-			if (flash->tested & TEST_BAD_WRITE)
+			if (chip->tested & TEST_BAD_WRITE)
 				msg_cinfo(" WRITE");
 			msg_cinfo("\n");
 		}
-		if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) ||
-		    (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) ||
-		    (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) ||
-		    (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) {
+		if ((!(chip->tested & TEST_BAD_PROBE) && !(chip->tested & TEST_OK_PROBE)) ||
+		    (!(chip->tested & TEST_BAD_READ) && !(chip->tested & TEST_OK_READ)) ||
+		    (!(chip->tested & TEST_BAD_ERASE) && !(chip->tested & TEST_OK_ERASE)) ||
+		    (!(chip->tested & TEST_BAD_WRITE) && !(chip->tested & TEST_OK_WRITE))) {
 			msg_cinfo("This flash part has status UNTESTED for operations:");
-			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
+			if (!(chip->tested & TEST_BAD_PROBE) && !(chip->tested & TEST_OK_PROBE))
 				msg_cinfo(" PROBE");
-			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
+			if (!(chip->tested & TEST_BAD_READ) && !(chip->tested & TEST_OK_READ))
 				msg_cinfo(" READ");
-			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
+			if (!(chip->tested & TEST_BAD_ERASE) && !(chip->tested & TEST_OK_ERASE))
 				msg_cinfo(" ERASE");
-			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
+			if (!(chip->tested & TEST_BAD_WRITE) && !(chip->tested & TEST_OK_WRITE))
 				msg_cinfo(" WRITE");
 			msg_cinfo("\n");
 		}
@@ -1702,13 +1705,13 @@ 
 
 	if (read_it || erase_it || write_it || verify_it) {
 		/* Everything needs read. */
-		if (flash->tested & TEST_BAD_READ) {
+		if (flash->chip->tested & TEST_BAD_READ) {
 			msg_cerr("Read is not working on this chip. ");
 			if (!force)
 				return 1;
 			msg_cerr("Continuing anyway.\n");
 		}
-		if (!flash->read) {
+		if (!flash->chip->read) {
 			msg_cerr("flashrom has no read function for this "
 				 "flash chip.\n");
 			return 1;
@@ -1716,7 +1719,7 @@ 
 	}
 	if (erase_it || write_it) {
 		/* Write needs erase. */
-		if (flash->tested & TEST_BAD_ERASE) {
+		if (flash->chip->tested & TEST_BAD_ERASE) {
 			msg_cerr("Erase is not working on this chip. ");
 			if (!force)
 				return 1;
@@ -1729,13 +1732,13 @@ 
 		}
 	}
 	if (write_it) {
-		if (flash->tested & TEST_BAD_WRITE) {
+		if (flash->chip->tested & TEST_BAD_WRITE) {
 			msg_cerr("Write is not working on this chip. ");
 			if (!force)
 				return 1;
 			msg_cerr("Continuing anyway.\n");
 		}
-		if (!flash->write) {
+		if (!flash->chip->write) {
 			msg_cerr("flashrom has no write function for this "
 				 "flash chip.\n");
 			return 1;
@@ -1754,7 +1757,7 @@ 
 	uint8_t *oldcontents;
 	uint8_t *newcontents;
 	int ret = 0;
-	unsigned long size = flash->total_size * 1024;
+	unsigned long size = flash->chip->total_size * 1024;
 
 	if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) {
 		msg_cerr("Aborting.\n");
@@ -1765,8 +1768,8 @@ 
 	/* Given the existence of read locks, we want to unlock for read,
 	 * erase and write.
 	 */
-	if (flash->unlock)
-		flash->unlock(flash);
+	if (flash->chip->unlock)
+		flash->chip->unlock(flash);
 
 	if (read_it) {
 		ret = read_flash_to_file(flash, filename);
@@ -1829,7 +1832,7 @@ 
 	 * takes time as well.
 	 */
 	msg_cinfo("Reading old flash chip contents... ");
-	if (flash->read(flash, oldcontents, 0, size)) {
+	if (flash->chip->read(flash, oldcontents, 0, size)) {
 		ret = 1;
 		msg_cinfo("FAILED.\n");
 		goto out;
@@ -1846,7 +1849,7 @@ 
 		if (erase_and_write_flash(flash, oldcontents, newcontents)) {
 			msg_cerr("Uh oh. Erase/write failed. Checking if "
 				 "anything changed.\n");
-			if (!flash->read(flash, newcontents, 0, size)) {
+			if (!flash->chip->read(flash, newcontents, 0, size)) {
 				if (!memcmp(oldcontents, newcontents, size)) {
 					msg_cinfo("Good. It seems nothing was "
 						  "changed.\n");
Index: flashrom-flashctx_separate_struct_flashchip/programmer.h
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/programmer.h	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/programmer.h	(Arbeitskopie)
@@ -475,7 +475,7 @@ 
 extern struct decode_sizes max_rom_decode;
 extern int programmer_may_write;
 extern unsigned long flashbase;
-void check_chip_supported(const struct flashctx *flash);
+void check_chip_supported(const struct flashchip *chip);
 int check_max_decode(enum chipbustype buses, uint32_t size);
 char *extract_programmer_param(const char *param_name);
 
Index: flashrom-flashctx_separate_struct_flashchip/m29f400bt.c
===================================================================
--- flashrom-flashctx_separate_struct_flashchip/m29f400bt.c	(Revision 1576)
+++ flashrom-flashctx_separate_struct_flashchip/m29f400bt.c	(Arbeitskopie)
@@ -81,7 +81,7 @@ 
 
 	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
 		return 1;
 
 	return 0;
@@ -130,7 +130,7 @@ 
 int block_erase_chip_m29f400bt(struct flashctx *flash, unsigned int address,
 			       unsigned int blocklen)
 {
-	if ((address != 0) || (blocklen != flash->total_size * 1024)) {
+	if ((address != 0) || (blocklen != flash->chip->total_size * 1024)) {
 		msg_cerr("%s called with incorrect arguments\n",
 			__func__);
 		return -1;