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

login
register
about
Submitter Stefan Tauner
Date 2012-02-26 01:05:52
Message ID <1330218352-32388-1-git-send-email-stefan.tauner@student.tuwien.ac.at>
Download mbox | patch
Permalink /patch/3571/
State Superseded
Headers show

Comments

Stefan Tauner - 2012-02-26 01:05:52
---
This is not tested very thoroughly, but it compiles and writing the dummy works.
Most of the transformation is quite obvious and painless (well, it was no pleasure,
so i would rather not rebase this often. :)
I have introduced dedicated struct flashchip variables where the functions use the
chip field a lot and some of those (not) introduced variables may be debatable,
but one gets at least a feeling how the code would look like with this change.

One major FIXME is: the code allocates "the new field" while probing and copies
the data from the *const* struct flashchip in the flashchips.c array into it.
We need to free that sometime... it is probably obvious (scope of fill_flash), but i
have not looked into it yet and this is my reminder.

Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
---
 82802ab.c      |   12 +++---
 cli_classic.c  |   23 ++++++-----
 flash.h        |   28 ++------------
 flashrom.c     |  114 ++++++++++++++++++++++++++++---------------------------
 ichspi.c       |   12 +++---
 it87spi.c      |   20 +++++-----
 jedec.c        |   43 +++++++++++----------
 layout.c       |    2 +-
 m29f400bt.c    |    4 +-
 pm49fl00x.c    |    8 ++--
 programmer.h   |    2 +-
 sfdp.c         |    6 +-
 spi.c          |    6 +-
 spi25.c        |   48 ++++++++++++-----------
 sst28sf040.c   |    2 +-
 sst49lfxxxc.c  |    2 +-
 sst_fwhub.c    |    6 +-
 stm50flw0x0x.c |    4 +-
 w29ee011.c     |    6 +-
 w39.c          |    8 ++--
 20 files changed, 171 insertions(+), 185 deletions(-)
Carl-Daniel Hailfinger - 2012-03-11 22:11:20
Am 26.02.2012 02:05 schrieb Stefan Tauner:
> This is not tested very thoroughly, but it compiles and writing the dummy works.
> Most of the transformation is quite obvious and painless (well, it was no pleasure,
> so i would rather not rebase this often. :)
> I have introduced dedicated struct flashchip variables where the functions use the
> chip field a lot and some of those (not) introduced variables may be debatable,
> but one gets at least a feeling how the code would look like with this change.
>
> One major FIXME is: the code allocates "the new field" while probing and copies
> the data from the *const* struct flashchip in the flashchips.c array into it.
> We need to free that sometime... it is probably obvious (scope of fill_flash), but i
> have not looked into it yet and this is my reminder.

I have answered that in annotations.


> Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>

Good idea. It was too dangerous to do this directly before 0.9.5, but
now that the tree has reopened, I think we can merge such a patch early
in the cycle (now) and have enough time to get it tested.


> diff --git a/cli_classic.c b/cli_classic.c
> index 972043b..4bce7d7 100644
> --- a/cli_classic.c
> +++ b/cli_classic.c
> @@ -166,6 +166,7 @@ int main(int argc, char *argv[])
>  	const struct flashchip *flash;
>  	struct flashctx flashes[3];
>  	struct flashctx *fill_flash;
> +	const struct flashchip *chip;
>  	const char *name;
>  	int namelen, opt, i, j;
>  	int startchip = -1, chipcount = 0, option_index = 0, force = 0;
> @@ -441,11 +442,13 @@ int main(int argc, char *argv[])
>  		}
>  	}
>  
> +	fill_flash = &flashes[0];

Can you move this assignment back to where it was?


> +	chip = fill_flash->chip;

And move this assignment together with the other one?


>  	if (chipcount > 1) {
>  		printf("Multiple flash chips were detected: \"%s\"",
> -			flashes[0].name);
> +			chip->name);

Can you please use flashes[0].chip->name here to keep the code
consistent? Besides that, do you have any idea why the current code is
so screwed up? Moving a printf for flashes[0] outside a perfectly
working for loop seems odd to me. It would be nice if you could just let
the loop below start at i=0 and remove the chip name part from the
printf above.


>  		for (i = 1; i < chipcount; i++)
> -			printf(", \"%s\"", flashes[i].name);
> +			printf(", \"%s\"", flashes[i].chip->name);
>  		printf("\nPlease specify which chip to use with the "
>  		       "-c <chipname> option.\n");
>  		ret = 1;
> @@ -464,7 +467,7 @@ int main(int argc, char *argv[])
>  			/* 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)
> +				if (pgm->buses_supported & chip->bustype)

flashes[0].chip->bustype please.
Note to self: This code needs to be audited again if it should really
run against flashes[0] here. It looks odd, at least when looking only at
the patch.


>  					compatible_programmers++;
>  			}
>  			if (compatible_programmers > 1)
> @@ -491,19 +494,17 @@ int main(int argc, char *argv[])
>  		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(chip->bustype);
>  		msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
> -			 flashes[0].vendor, flashes[0].name,
> -			 flashes[0].total_size, tempstr);
> +			 chip->vendor, chip->name,
> +			 chip->total_size, tempstr);

And the flashes[0].chip dance again.


>  		free(tempstr);
>  	}
>  
> -	fill_flash = &flashes[0];
> -
> -	check_chip_supported(fill_flash);
> +	check_chip_supported(chip);
>  
> -	size = fill_flash->total_size * 1024;
> -	if (check_max_decode(fill_flash->pgm->buses_supported & fill_flash->bustype, size) &&
> +	size = chip->total_size * 1024;
> +	if (check_max_decode(fill_flash->pgm->buses_supported & chip->bustype, size) &&
>  	    (!force)) {
>  		fprintf(stderr, "Chip is too big for this programmer "
>  			"(-V gives details). Use --force to override.\n");
> diff --git a/flash.h b/flash.h
> index 0dac13d..ed64512 100644
> --- a/flash.h
> +++ b/flash.h
> @@ -87,6 +87,7 @@ enum chipbustype {
>  #define FEATURE_WRSR_EITHER	(FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
>  
>  struct flashctx;
> +typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
>  
>  struct flashchip {
>  	const char *vendor;
> @@ -135,7 +136,7 @@ struct flashchip {
>  		} eraseblocks[NUM_ERASEREGIONS];
>  		/* a block_erase function should try to erase one block of size
>  		 * 'blocklen' at address 'blockaddr' and return 0 on success. */
> -		int (*block_erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
> +		erasefunc_t *block_erase;

I really really hate that typedef. I wonder if we could keep the code
here and use typeof() instead of the typedef elsewhere.


>  	} block_erasers[NUM_ERASEFUNCTIONS];
>  
>  	int (*printlock) (struct flashctx *flash);
> @@ -148,35 +149,14 @@ struct flashchip {
>  	} 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;

Yay!


>  	chipaddr virtual_memory;
>  	/* Some flash devices have an additional register space. */
>  	chipaddr virtual_registers;
>  	struct registered_programmer *pgm;
>  };
>  
> -typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
> -
>  #define TEST_UNTESTED	0
>  
>  #define TEST_OK_PROBE	(1 << 0)
> diff --git a/flashrom.c b/flashrom.c
> index cad043b..0b6cca3 100644
> --- a/flashrom.c
> +++ b/flashrom.c
> @@ -522,7 +522,7 @@ char *extract_programmer_param(const char *param_name)
>  }
>  
>  /* Returns the number of well-defined erasers for a chip. */
> -static unsigned int count_usable_erasers(const struct flashctx *flash)
> +static unsigned int count_usable_erasers(const struct flashchip *flash)

Do we want to count usable erasers for the current programmer (for chips
with erase functions limited to certain buses)? If yes, please keep
struct flashctx.


>  {
>  	unsigned int usable_erasefunctions = 0;
>  	int k;
> @@ -941,32 +942,38 @@ int check_max_decode(enum chipbustype buses, uint32_t size)
>  int probe_flash(struct registered_programmer *pgm, int startchip,
>  		struct flashctx *fill_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));
> +		/* FIXME: when to free? */

Tricky, but I think we are lucky here because there is only one path
which returns a non-match and that's the only path where we want to
free. I have annotated that place a few hunks below.


> +		fill_flash->chip = malloc(sizeof(struct flashchip));
> +		if (fill_flash->chip == NULL) {
> +			msg_gerr("%s: out of memory.\n", __func__);
> +			return -1;

Can we return an explicit code for OOM here or would that screw up the
caller?


> +		}
> +		memcpy(fill_flash->chip, chip, sizeof(struct flashchip));
>  		fill_flash->pgm = pgm;
>  
>  		base = flashbase ? flashbase : (0xffffffff - size + 1);
> @@ -985,11 +992,11 @@ int probe_flash(struct registered_programmer *pgm, int startchip,
>  		 * 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 && chip->model_id == SFDP_DEVICE_ID) {

We used fill_flash for consistency (i.e. only use the rw copy of the
flashchip entry) here, and if we want to keep that consistency, it's
fill_flash->chip->model_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(chip) == 0)

See the count_usable_erasers comment a few hunks above.


>  				msg_cinfo("The standard operations read and "
>  					  "verify should work, but to support "
>  					  "erase, write and all other "
> @@ -1010,15 +1017,15 @@ int probe_flash(struct registered_programmer *pgm, int startchip,
>  		}
>  
>  		if (startchip == 0 ||
> -		    ((fill_flash->model_id != GENERIC_DEVICE_ID) &&
> -		     (fill_flash->model_id != SFDP_DEVICE_ID)))
> +		    ((chip->model_id != GENERIC_DEVICE_ID) &&
> +		     (chip->model_id != SFDP_DEVICE_ID)))

See above for fill_flash->chip->model_id.


>  			break;
>  
>  notfound:
>  		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
>  	}
>  
> -	if (!flash || !flash->name)
> +	if (!chip || !chip->name)

Here you have to free flash->chip. No other freeing is needed AFAICS.


>  		return -1;
>  
>  #if CONFIG_INTERNAL == 1
> @@ -1028,27 +1035,27 @@ notfound:
>  #endif
>  		snprintf(location, sizeof(location), "on %s", programmer_table[programmer].name);
>  
> -	tmp = flashbuses_to_text(flash->bustype);
> +	tmp = flashbuses_to_text(chip->bustype);

fill_flash->chip->...


>  	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);
> +		  force ? "Assuming" : "Found", chip->vendor,
> +		  chip->name, chip->total_size, tmp, location);

dito


>  	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 (chip->printlock)

dito


> +			chip->printlock(fill_flash);

dito


>  
>  	/* Return position of matching chip. */
> -	return flash - flashchips;
> +	return chip - flashchips;
>  }
>  
>  int verify_flash(struct flashctx *flash, uint8_t *buf)
> @@ -1308,7 +1315,7 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction,
>  	return 0;
>  }
>  
> -static int check_block_eraser(const struct flashctx *flash, int k, int log)
> +static int check_block_eraser(const struct flashchip *flash, int k, int log)

No conversion, please. See below.


>  {
>  	struct block_eraser eraser = flash->block_erasers[k];
>  
> @@ -1357,7 +1366,7 @@ int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents,
>  			break;
>  		}
>  		msg_cdbg("Trying erase function %i... ", k);
> -		if (check_block_eraser(flash, k, 1))
> +		if (check_block_eraser(chip, k, 1))

This one is debatable. We know that some chips support certain erase
functions only on some buses, e.g. Sharp LHF00L04 which can do a
full-chip erase only if it is accesses in A/A Mux mode, not in FWH mode.
My mid-term plan is to augment erase functions (and possibly also
read/write/probe) with a list of valid buses for any given function.


>  			continue;
>  		usable_erasefunctions--;
>  		ret = walk_eraseregions(flash, k, &erase_and_write_block_helper,
> @@ -1550,14 +1559,6 @@ int selfcheck(void)
>  		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;
> -	}

Glad to lose this hunk!


>  	for (flash = flashchips; flash && flash->name; flash++)
>  		if (selfcheck_eraseblocks(flash))
>  			ret = 1;
> @@ -1642,7 +1643,7 @@ void check_chip_supported(const struct flashctx *flash)
>  /* FIXME: This function signature needs to be improved once doit() has a better
>   * function signature.
>   */
> -int chip_safety_check(struct flashctx *flash, int force, int read_it,
> +int chip_safety_check(const struct flashchip *flash, int force, int read_it,

Can you please make sure that all pointers to struct flashchip are
called "chip"? Otherwise grepping for "chip->" won't return all accesses
to struct flashchip. The same comment applies to other hunks of the
patch as well.

However, chip_safety_check can not be converted to a different calling
convention because we need struct flashctx here. Admittedly we don't
need it right now, but we will need it once programmer_may_write is part
of the programmer struct in struct flashctx.


>  		      int write_it, int erase_it, int verify_it)
>  {
>  	if (!programmer_may_write && (write_it || erase_it)) {
> @@ -1710,9 +1711,10 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
>  	uint8_t *oldcontents;
>  	uint8_t *newcontents;
>  	int ret = 0;
> -	unsigned long size = flash->total_size * 1024;
> +	const struct flashchip *chip = flash->chip;
> +	unsigned long size = chip->total_size * 1024;
>  
> -	if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) {
> +	if (chip_safety_check(chip, force, read_it, write_it, erase_it, verify_it)) {

No conversion, please. See above.


>  		msg_cerr("Aborting.\n");
>  		ret = 1;
>  		goto out_nofree;
> @@ -1791,7 +1793,7 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
>  
>  	// This should be moved into each flash part's code to do it 
>  	// cleanly. This does the job.
> -	handle_romentries(flash, oldcontents, newcontents);
> +	handle_romentries(chip, oldcontents, newcontents);

No conversion, please. See two hunks below.


>  
>  	// ////////////////////////////////////////////////////////////
>  
> diff --git a/jedec.c b/jedec.c
> index 69c0c0c..5c549a2 100644
> --- a/jedec.c
> +++ b/jedec.c
> @@ -93,7 +93,7 @@ void data_polling_jedec(const struct flashctx *flash, chipaddr dst,
>  		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 *flash)

Hm yes, const makes sense. In fact, const makes sense in many more places.


>  {
>  	switch (flash->feature_bits & FEATURE_ADDR_MASK) {
>  	case FEATURE_ADDR_FULL:
> diff --git a/layout.c b/layout.c
> index 90d3cce..f0f7a6f 100644
> --- a/layout.c
> +++ b/layout.c
> @@ -302,7 +302,7 @@ romlayout_t *get_next_included_romentry(unsigned int start)
>  	return best_entry;
>  }
>  
> -int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
> +int handle_romentries(const struct flashchip *flash, uint8_t *oldcontents, uint8_t *newcontents)

Will we have to change this back once we try to merge the layout
patches? In that case, we need some way to get permissible regions from
the programmer, and that would probably be done via the programmer struct.


>  {
>  	unsigned int start = 0;
>  	romlayout_t *entry;
> diff --git a/spi25.c b/spi25.c
> index b7e8189..2accb6d 100644
> --- a/spi25.c
> +++ b/spi25.c
> @@ -416,22 +416,23 @@ void spi_prettyprint_status_register_sst25vf040b(uint8_t status)
>  
>  int spi_prettyprint_status_register(struct flashctx *flash)
>  {
> +	const struct flashchip *chip = flash->chip;

const struct flashchip here, but just struct flashchip in the next hunk.
What's the reason? Same question applies to other hunks of the patch as
well.


>  	uint8_t status;
>  
>  	status = spi_read_status_register(flash);
>  	msg_cdbg("Chip status register is %02x\n", status);
> -	switch (flash->manufacture_id) {
> +	switch (chip->manufacture_id) {
>  	case ST_ID:
> -		if (((flash->model_id & 0xff00) == 0x2000) ||
> -		    ((flash->model_id & 0xff00) == 0x2500))
> +		if (((chip->model_id & 0xff00) == 0x2000) ||
> +		    ((chip->model_id & 0xff00) == 0x2500))
>  			spi_prettyprint_status_register_st_m25p(status);
>  		break;
>  	case MACRONIX_ID:
> -		if ((flash->model_id & 0xff00) == 0x2000)
> +		if ((chip->model_id & 0xff00) == 0x2000)
>  			spi_prettyprint_status_register_st_m25p(status);
>  		break;
>  	case SST_ID:
> -		switch (flash->model_id) {
> +		switch (chip->model_id) {
>  		case 0x2541:
>  			spi_prettyprint_status_register_sst25vf016(status);
>  			break;
> @@ -862,16 +863,17 @@ static int spi_write_status_register_wren(struct flashctx *flash, int status)
>  
>  int spi_write_status_register(struct flashctx *flash, int status)
>  {
> +	struct flashchip *chip = flash->chip;
>  	int ret = 1;
>  
> -	if (!(flash->feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
> +	if (!(chip->feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
>  		msg_cdbg("Missing status register write definition, assuming "
>  			 "EWSR is needed\n");
> -		flash->feature_bits |= FEATURE_WRSR_EWSR;
> +		chip->feature_bits |= FEATURE_WRSR_EWSR;
>  	}
> -	if (flash->feature_bits & FEATURE_WRSR_WREN)
> +	if (chip->feature_bits & FEATURE_WRSR_WREN)
>  		ret = spi_write_status_register_wren(flash, status);
> -	if (ret && (flash->feature_bits & FEATURE_WRSR_EWSR))
> +	if (ret && (chip->feature_bits & FEATURE_WRSR_EWSR))
>  		ret = spi_write_status_register_ewsr(flash, status);
>  	return ret;
>  }


I think the next iteration of this patch can go in.

Regards,
Carl-Daniel

Patch

diff --git a/82802ab.c b/82802ab.c
index 79e157a..608995d 100644
--- a/82802ab.c
+++ b/82802ab.c
@@ -44,7 +44,7 @@  int probe_82802ab(struct flashctx *flash)
 {
 	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 @@  int probe_82802ab(struct flashctx *flash)
 		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 unlock_82802ab(struct flashctx *flash)
 	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 @@  int unlock_28f004s5(struct flashctx *flash)
 	}
 
 	/* 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 @@  int unlock_lh28f008bjt(struct flashctx *flash)
 	}
 
 	/* 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,
diff --git a/cli_classic.c b/cli_classic.c
index 972043b..4bce7d7 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -166,6 +166,7 @@  int main(int argc, char *argv[])
 	const struct flashchip *flash;
 	struct flashctx flashes[3];
 	struct flashctx *fill_flash;
+	const struct flashchip *chip;
 	const char *name;
 	int namelen, opt, i, j;
 	int startchip = -1, chipcount = 0, option_index = 0, force = 0;
@@ -441,11 +442,13 @@  int main(int argc, char *argv[])
 		}
 	}
 
+	fill_flash = &flashes[0];
+	chip = fill_flash->chip;
 	if (chipcount > 1) {
 		printf("Multiple flash chips were detected: \"%s\"",
-			flashes[0].name);
+			chip->name);
 		for (i = 1; i < chipcount; i++)
-			printf(", \"%s\"", flashes[i].name);
+			printf(", \"%s\"", flashes[i].chip->name);
 		printf("\nPlease specify which chip to use with the "
 		       "-c <chipname> option.\n");
 		ret = 1;
@@ -464,7 +467,7 @@  int main(int argc, char *argv[])
 			/* 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)
+				if (pgm->buses_supported & chip->bustype)
 					compatible_programmers++;
 			}
 			if (compatible_programmers > 1)
@@ -491,19 +494,17 @@  int main(int argc, char *argv[])
 		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(chip->bustype);
 		msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
-			 flashes[0].vendor, flashes[0].name,
-			 flashes[0].total_size, tempstr);
+			 chip->vendor, chip->name,
+			 chip->total_size, tempstr);
 		free(tempstr);
 	}
 
-	fill_flash = &flashes[0];
-
-	check_chip_supported(fill_flash);
+	check_chip_supported(chip);
 
-	size = fill_flash->total_size * 1024;
-	if (check_max_decode(fill_flash->pgm->buses_supported & fill_flash->bustype, size) &&
+	size = chip->total_size * 1024;
+	if (check_max_decode(fill_flash->pgm->buses_supported & chip->bustype, size) &&
 	    (!force)) {
 		fprintf(stderr, "Chip is too big for this programmer "
 			"(-V gives details). Use --force to override.\n");
diff --git a/flash.h b/flash.h
index 0dac13d..ed64512 100644
--- a/flash.h
+++ b/flash.h
@@ -87,6 +87,7 @@  enum chipbustype {
 #define FEATURE_WRSR_EITHER	(FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
 
 struct flashctx;
+typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 
 struct flashchip {
 	const char *vendor;
@@ -135,7 +136,7 @@  struct flashchip {
 		} eraseblocks[NUM_ERASEREGIONS];
 		/* a block_erase function should try to erase one block of size
 		 * 'blocklen' at address 'blockaddr' and return 0 on success. */
-		int (*block_erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+		erasefunc_t *block_erase;
 	} block_erasers[NUM_ERASEFUNCTIONS];
 
 	int (*printlock) (struct flashctx *flash);
@@ -148,35 +149,14 @@  struct flashchip {
 	} 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;
 	struct registered_programmer *pgm;
 };
 
-typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-
 #define TEST_UNTESTED	0
 
 #define TEST_OK_PROBE	(1 << 0)
@@ -295,7 +275,7 @@  int print(int type, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
 int register_include_arg(char *name);
 int process_include_args(void);
 int read_romlayout(char *name);
-int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents);
+int handle_romentries(const struct flashchip *flash, uint8_t *oldcontents, uint8_t *newcontents);
 
 /* spi.c */
 struct spi_command {
diff --git a/flashrom.c b/flashrom.c
index cad043b..0b6cca3 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -265,7 +265,7 @@  struct shutdown_func_data {
  */
 static int may_register_shutdown = 0;
 
-static int check_block_eraser(const struct flashctx *flash, int k, int log);
+static int check_block_eraser(const struct flashchip *flash, int k, int log);
 
 /* Register a function to be executed on programmer shutdown.
  * The advantage over atexit() is that you can supply a void pointer which will
@@ -404,7 +404,7 @@  void programmer_delay(int usecs)
 
 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);
@@ -522,7 +522,7 @@  char *extract_programmer_param(const char *param_name)
 }
 
 /* Returns the number of well-defined erasers for a chip. */
-static unsigned int count_usable_erasers(const struct flashctx *flash)
+static unsigned int count_usable_erasers(const struct flashchip *flash)
 {
 	unsigned int usable_erasefunctions = 0;
 	int k;
@@ -561,6 +561,7 @@  int check_erased_range(struct flashctx *flash, unsigned int start,
 int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start,
 		 unsigned int len, const char *message)
 {
+	const struct flashchip *chip = flash->chip;
 	unsigned int i;
 	uint8_t *readbuf = malloc(len);
 	int ret = 0, failcount = 0;
@@ -568,7 +569,7 @@  int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start,
 	if (!len)
 		goto out_free;
 
-	if (!flash->read) {
+	if (!chip->read) {
 		msg_cerr("ERROR: flashrom has no read function for this flash chip.\n");
 		return 1;
 	}
@@ -577,17 +578,17 @@  int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start,
 		exit(1);
 	}
 
-	if (start + len > flash->total_size * 1024) {
+	if (start + len > 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);
+			chip->total_size * 1024);
 		ret = -1;
 		goto out_free;
 	}
 	if (!message)
 		message = "VERIFY";
 
-	ret = flash->read(flash, readbuf, start, len);
+	ret = chip->read(flash, readbuf, start, len);
 	if (ret) {
 		msg_gerr("Verification impossible because read failed "
 			 "at 0x%x (len 0x%x)\n", start, len);
@@ -941,32 +942,38 @@  int check_max_decode(enum chipbustype buses, uint32_t size)
 int probe_flash(struct registered_programmer *pgm, int startchip,
 		struct flashctx *fill_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));
+		/* FIXME: when to free? */
+		fill_flash->chip = malloc(sizeof(struct flashchip));
+		if (fill_flash->chip == NULL) {
+			msg_gerr("%s: out of memory.\n", __func__);
+			return -1;
+		}
+		memcpy(fill_flash->chip, chip, sizeof(struct flashchip));
 		fill_flash->pgm = pgm;
 
 		base = flashbase ? flashbase : (0xffffffff - size + 1);
@@ -975,7 +982,7 @@  int probe_flash(struct registered_programmer *pgm, int startchip,
 		if (force)
 			break;
 
-		if (fill_flash->probe(fill_flash) != 1)
+		if (chip->probe(fill_flash) != 1)
 			goto notfound;
 
 		/* If this is the first chip found, accept it.
@@ -985,11 +992,11 @@  int probe_flash(struct registered_programmer *pgm, int startchip,
 		 * 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 && 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(chip) == 0)
 				msg_cinfo("The standard operations read and "
 					  "verify should work, but to support "
 					  "erase, write and all other "
@@ -1010,15 +1017,15 @@  int probe_flash(struct registered_programmer *pgm, int startchip,
 		}
 
 		if (startchip == 0 ||
-		    ((fill_flash->model_id != GENERIC_DEVICE_ID) &&
-		     (fill_flash->model_id != SFDP_DEVICE_ID)))
+		    ((chip->model_id != GENERIC_DEVICE_ID) &&
+		     (chip->model_id != SFDP_DEVICE_ID)))
 			break;
 
 notfound:
 		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
 	}
 
-	if (!flash || !flash->name)
+	if (!chip || !chip->name)
 		return -1;
 
 #if CONFIG_INTERNAL == 1
@@ -1028,27 +1035,27 @@  notfound:
 #endif
 		snprintf(location, sizeof(location), "on %s", programmer_table[programmer].name);
 
-	tmp = flashbuses_to_text(flash->bustype);
+	tmp = flashbuses_to_text(chip->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);
+		  force ? "Assuming" : "Found", chip->vendor,
+		  chip->name, 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 (chip->printlock)
+			chip->printlock(fill_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... ");
 
@@ -1121,7 +1128,7 @@  int write_buf_to_file(unsigned char *buf, unsigned long size,
 
 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;
 
@@ -1131,12 +1138,12 @@  int read_flash_to_file(struct flashctx *flash, const char *filename)
 		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;
@@ -1257,7 +1264,7 @@  static int erase_and_write_block_helper(struct flashctx *flash,
 		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;
@@ -1284,7 +1291,7 @@  static int walk_eraseregions(struct flashctx *flash, int erasefunction,
 	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
@@ -1308,7 +1315,7 @@  static int walk_eraseregions(struct flashctx *flash, int erasefunction,
 	return 0;
 }
 
-static int check_block_eraser(const struct flashctx *flash, int k, int log)
+static int check_block_eraser(const struct flashchip *flash, int k, int log)
 {
 	struct block_eraser eraser = flash->block_erasers[k];
 
@@ -1335,10 +1342,12 @@  static int check_block_eraser(const struct flashctx *flash, int k, int log)
 int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents,
 			  uint8_t *newcontents)
 {
-	int k, ret = 1;
+	int ret = 1;
+	const struct flashchip *chip = flash->chip;
+	unsigned long size = chip->total_size * 1024;
+	unsigned int usable_erasefunctions = count_usable_erasers(chip);
+	int k;
 	uint8_t *curcontents;
-	unsigned long size = flash->total_size * 1024;
-	unsigned int usable_erasefunctions = count_usable_erasers(flash);
 
 	msg_cinfo("Erasing and writing flash chip... ");
 	curcontents = malloc(size);
@@ -1357,7 +1366,7 @@  int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents,
 			break;
 		}
 		msg_cdbg("Trying erase function %i... ", k);
-		if (check_block_eraser(flash, k, 1))
+		if (check_block_eraser(chip, k, 1))
 			continue;
 		usable_erasefunctions--;
 		ret = walk_eraseregions(flash, k, &erase_and_write_block_helper,
@@ -1375,7 +1384,7 @@  int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents,
 		 * in non-verbose mode.
 		 */
 		msg_cinfo("Reading current flash chip contents... ");
-		if (flash->read(flash, curcontents, 0, size)) {
+		if (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
@@ -1550,14 +1559,6 @@  int selfcheck(void)
 		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))
 			ret = 1;
@@ -1583,7 +1584,7 @@  int selfcheck(void)
 	return ret;
 }
 
-void check_chip_supported(const struct flashctx *flash)
+void check_chip_supported(const struct flashchip *flash)
 {
 	if (flash->feature_bits & FEATURE_OTP) {
 		msg_cdbg("This chip may contain one-time programmable memory. "
@@ -1642,7 +1643,7 @@  void check_chip_supported(const struct flashctx *flash)
 /* FIXME: This function signature needs to be improved once doit() has a better
  * function signature.
  */
-int chip_safety_check(struct flashctx *flash, int force, int read_it,
+int chip_safety_check(const struct flashchip *flash, int force, int read_it,
 		      int write_it, int erase_it, int verify_it)
 {
 	if (!programmer_may_write && (write_it || erase_it)) {
@@ -1710,9 +1711,10 @@  int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 	uint8_t *oldcontents;
 	uint8_t *newcontents;
 	int ret = 0;
-	unsigned long size = flash->total_size * 1024;
+	const struct flashchip *chip = flash->chip;
+	unsigned long size = chip->total_size * 1024;
 
-	if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) {
+	if (chip_safety_check(chip, force, read_it, write_it, erase_it, verify_it)) {
 		msg_cerr("Aborting.\n");
 		ret = 1;
 		goto out_nofree;
@@ -1721,8 +1723,8 @@  int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 	/* Given the existence of read locks, we want to unlock for read,
 	 * erase and write.
 	 */
-	if (flash->unlock)
-		flash->unlock(flash);
+	if (chip->unlock)
+		chip->unlock(flash);
 
 	if (read_it) {
 		ret = read_flash_to_file(flash, filename);
@@ -1782,7 +1784,7 @@  int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 	 * takes time as well.
 	 */
 	msg_cinfo("Reading old flash chip contents... ");
-	if (flash->read(flash, oldcontents, 0, size)) {
+	if (chip->read(flash, oldcontents, 0, size)) {
 		ret = 1;
 		msg_cinfo("FAILED.\n");
 		goto out;
@@ -1791,7 +1793,7 @@  int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 
 	// This should be moved into each flash part's code to do it 
 	// cleanly. This does the job.
-	handle_romentries(flash, oldcontents, newcontents);
+	handle_romentries(chip, oldcontents, newcontents);
 
 	// ////////////////////////////////////////////////////////////
 
@@ -1799,7 +1801,7 @@  int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 		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 (!chip->read(flash, newcontents, 0, size)) {
 				if (!memcmp(oldcontents, newcontents, size)) {
 					msg_cinfo("Good. It seems nothing was "
 						  "changed.\n");
diff --git a/ichspi.c b/ichspi.c
index 403d763..fd0c56f 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -1191,9 +1191,9 @@  static int ich_hwseq_probe(struct flashctx *flash)
 	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);
@@ -1226,7 +1226,7 @@  static int ich_hwseq_probe(struct flashctx *flash)
 		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;
 }
 
@@ -1254,7 +1254,7 @@  static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
 		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);
@@ -1286,7 +1286,7 @@  static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
 	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;
@@ -1324,7 +1324,7 @@  static int ich_hwseq_write(struct flashctx *flash, uint8_t *buf,
 	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;
diff --git a/it87spi.c b/it87spi.c
index f089d78..4abea02 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -329,7 +329,7 @@  static int it8716f_spi_page_program(struct flashctx *flash, uint8_t *buf,
 	/* 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++)
 		chip_writeb(flash, buf[i], bios + start + i);
 	OUTB(0, it8716f_flashport);
 	/* Wait until the Write-In-Progress bit is cleared.
@@ -353,7 +353,7 @@  static int it8716f_spi_chip_read(struct flashctx *flash, uint8_t *buf,
 	 * 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 {
 		read_memmapped(flash, buf, start, len);
@@ -365,6 +365,7 @@  static int it8716f_spi_chip_read(struct flashctx *flash, uint8_t *buf,
 static int it8716f_spi_chip_write_256(struct flashctx *flash, uint8_t *buf,
 				      unsigned int start, unsigned int len)
 {
+	const struct flashchip *chip = flash->chip;
 	/*
 	 * IT8716F only allows maximum of 512 kb SPI chip size for memory
 	 * mapped access. It also can't write more than 1+3+256 bytes at once,
@@ -375,28 +376,27 @@  static int it8716f_spi_chip_write_256(struct flashctx *flash, uint8_t *buf,
 	 * 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 ((chip->total_size * 1024 > 512 * 1024) || (chip->page_size > 256)) {
 		spi_chip_write_1(flash, buf, start, len);
 	} else {
 		unsigned int lenhere;
 
-		if (start % flash->page_size) {
+		if (start % 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, chip->page_size - start % chip->page_size);
 			spi_chip_write_1(flash, buf, start, lenhere);
 			start += lenhere;
 			len -= lenhere;
 			buf += lenhere;
 		}
 
-		while (len >= flash->page_size) {
+		while (len >= chip->page_size) {
 			it8716f_spi_page_program(flash, buf, start);
-			start += flash->page_size;
-			len -= flash->page_size;
-			buf += flash->page_size;
+			start += chip->page_size;
+			len -= chip->page_size;
+			buf += chip->page_size;
 		}
 		if (len)
 			spi_chip_write_1(flash, buf, start, len);
diff --git a/jedec.c b/jedec.c
index 69c0c0c..5c549a2 100644
--- a/jedec.c
+++ b/jedec.c
@@ -93,7 +93,7 @@  void data_polling_jedec(const struct flashctx *flash, chipaddr dst,
 		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 *flash)
 {
 	switch (flash->feature_bits & FEATURE_ADDR_MASK) {
 	case FEATURE_ADDR_FULL:
@@ -124,16 +124,17 @@  static void start_program_jedec_common(struct flashctx *flash,
 static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
 {
 	chipaddr bios = flash->virtual_memory;
+	const struct flashchip *chip = flash->chip;
 	uint8_t id1, id2;
 	uint32_t largeid1, largeid2;
 	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 (chip->probe_timing > 0)
+		probe_timing_enter = probe_timing_exit = chip->probe_timing;
+	else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
 		probe_timing_enter = probe_timing_exit = 0;
-	} else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */
+	} else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
 		msg_cdbg("Chip lacks correct probe timing information, "
 			     "using default 10mS/40uS. ");
 		probe_timing_enter = 10000;
@@ -151,7 +152,7 @@  static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
 	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 ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
 	{
 		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
 		if (probe_timing_exit)
@@ -194,7 +195,7 @@  static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
 	}
 
 	/* Issue JEDEC Product ID Exit command */
-	if ((flash->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
 	{
 		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
 		if (probe_timing_exit)
@@ -231,10 +232,10 @@  static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
 		msg_cdbg(", id2 is normal flash content");
 
 	msg_cdbg("\n");
-	if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id)
+	if (largeid1 != chip->manufacture_id || largeid2 != chip->model_id)
 		return 0;
 
-	if (flash->feature_bits & FEATURE_REGISTERMAP)
+	if (chip->feature_bits & FEATURE_REGISTERMAP)
 		map_flash_registers(flash);
 
 	return 1;
@@ -245,7 +246,7 @@  static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
 {
 	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 +276,7 @@  static int erase_block_jedec_common(struct flashctx *flash, unsigned int block,
 {
 	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 +305,7 @@  static int erase_chip_jedec_common(struct flashctx *flash, unsigned int mask)
 {
 	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 +367,7 @@  int write_jedec_1(struct flashctx *flash, uint8_t *src, unsigned int start,
 	chipaddr olddst;
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 
 	olddst = dst;
 	for (i = 0; i < len; i++) {
@@ -390,7 +391,7 @@  int write_page_write_jedec_common(struct flashctx *flash, uint8_t *src,
 	chipaddr d = dst;
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 
 retry:
 	/* Issue JEDEC Start Program command */
@@ -438,7 +439,7 @@  int write_jedec(struct flashctx *flash, uint8_t *buf, unsigned int start,
 	 * 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 +470,8 @@  int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr,
 {
 	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 +483,7 @@  int probe_jedec(struct flashctx *flash)
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return probe_jedec_common(flash, mask);
 }
 
@@ -491,7 +492,7 @@  int erase_sector_jedec(struct flashctx *flash, unsigned int page,
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return erase_sector_jedec_common(flash, page, size, mask);
 }
 
@@ -500,7 +501,7 @@  int erase_block_jedec(struct flashctx *flash, unsigned int page,
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return erase_block_jedec_common(flash, page, size, mask);
 }
 
@@ -508,6 +509,6 @@  int erase_chip_jedec(struct flashctx *flash)
 {
 	unsigned int mask;
 
-	mask = getaddrmask(flash);
+	mask = getaddrmask(flash->chip);
 	return erase_chip_jedec_common(flash, mask);
 }
diff --git a/layout.c b/layout.c
index 90d3cce..f0f7a6f 100644
--- a/layout.c
+++ b/layout.c
@@ -302,7 +302,7 @@  romlayout_t *get_next_included_romentry(unsigned int start)
 	return best_entry;
 }
 
-int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
+int handle_romentries(const struct flashchip *flash, uint8_t *oldcontents, uint8_t *newcontents)
 {
 	unsigned int start = 0;
 	romlayout_t *entry;
diff --git a/m29f400bt.c b/m29f400bt.c
index c9d8a40..8f0329e 100644
--- a/m29f400bt.c
+++ b/m29f400bt.c
@@ -81,7 +81,7 @@  int probe_m29f400bt(struct flashctx *flash)
 
 	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_m29f400bt(struct flashctx *flash, unsigned int start,
 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;
diff --git a/pm49fl00x.c b/pm49fl00x.c
index 42db2aa..fe28d2b 100644
--- a/pm49fl00x.c
+++ b/pm49fl00x.c
@@ -40,14 +40,14 @@  static void write_lockbits_49fl00x(const struct flashctx *flash,
 
 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;
 }
diff --git a/programmer.h b/programmer.h
index 240e1af..3ef262c 100644
--- a/programmer.h
+++ b/programmer.h
@@ -458,7 +458,7 @@  struct decode_sizes {
 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 *flash);
 int check_max_decode(enum chipbustype buses, uint32_t size);
 char *extract_programmer_param(const char *param_name);
 
diff --git a/sfdp.c b/sfdp.c
index 123c982..1781949 100644
--- a/sfdp.c
+++ b/sfdp.c
@@ -72,7 +72,7 @@  struct sfdp_tbl_hdr {
 	uint32_t ptp; /* 24b pointer */
 };
 
-static int sfdp_add_uniform_eraser(struct flashctx *flash, uint8_t opcode, uint32_t block_size)
+static int sfdp_add_uniform_eraser(struct flashchip *flash, uint8_t opcode, uint32_t block_size)
 {
 	int i;
 	uint32_t total_size = flash->total_size * 1024;
@@ -116,7 +116,7 @@  static int sfdp_add_uniform_eraser(struct flashctx *flash, uint8_t opcode, uint3
 	return 1;
 }
 
-static int sfdp_fill_flash(struct flashctx *flash, uint8_t *buf, uint16_t len)
+static int sfdp_fill_flash(struct flashchip *flash, uint8_t *buf, uint16_t len)
 {
 	uint8_t opcode_4k_erase = 0xFF;
 	uint32_t tmp32;
@@ -370,7 +370,7 @@  int probe_spi_sfdp(struct flashctx *flash)
 				msg_cdbg("Length of the mandatory JEDEC SFDP "
 					 "parameter table is wrong (%d B), "
 					 "skipping it.\n", len);
-			} else if (sfdp_fill_flash(flash, tbuf, len) == 0)
+			} else if (sfdp_fill_flash(flash->chip, tbuf, len) == 0)
 				ret = 1;
 		}
 		free(tbuf);
diff --git a/spi.c b/spi.c
index b2d3eb0..56d88df 100644
--- a/spi.c
+++ b/spi.c
@@ -111,16 +111,16 @@  int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
 	 * 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");
diff --git a/spi25.c b/spi25.c
index b7e8189..2accb6d 100644
--- a/spi25.c
+++ b/spi25.c
@@ -117,6 +117,7 @@  int spi_write_disable(struct flashctx *flash)
 
 static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
 {
+	const struct flashchip *chip = flash->chip;
 	unsigned char readarr[4];
 	uint32_t id1;
 	uint32_t id2;
@@ -147,7 +148,7 @@  static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
 
 	msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
+	if (id1 == chip->manufacture_id && id2 == chip->model_id) {
 		/* Print the status register to tell the
 		 * user about possible write protection.
 		 */
@@ -157,12 +158,11 @@  static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
 	}
 
 	/* Test if this is a pure vendor match. */
-	if (id1 == flash->manufacture_id &&
-	    GENERIC_DEVICE_ID == flash->model_id)
+	if (id1 == chip->manufacture_id && GENERIC_DEVICE_ID == chip->model_id)
 		return 1;
 
 	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == flash->manufacture_id &&
+	if (GENERIC_MANUF_ID == chip->manufacture_id &&
 	    id1 != 0xff)
 		return 1;
 
@@ -198,6 +198,7 @@  int probe_spi_rdid4(struct flashctx *flash)
 
 int probe_spi_rems(struct flashctx *flash)
 {
+	const struct flashchip *chip = flash->chip;
 	unsigned char readarr[JEDEC_REMS_INSIZE];
 	uint32_t id1, id2;
 
@@ -210,7 +211,7 @@  int probe_spi_rems(struct flashctx *flash)
 
 	msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
 
-	if (id1 == flash->manufacture_id && id2 == flash->model_id) {
+	if (id1 == chip->manufacture_id && id2 == chip->model_id) {
 		/* Print the status register to tell the
 		 * user about possible write protection.
 		 */
@@ -220,12 +221,11 @@  int probe_spi_rems(struct flashctx *flash)
 	}
 
 	/* Test if this is a pure vendor match. */
-	if (id1 == flash->manufacture_id &&
-	    GENERIC_DEVICE_ID == flash->model_id)
+	if (id1 == chip->manufacture_id && GENERIC_DEVICE_ID == chip->model_id)
 		return 1;
 
 	/* Test if there is any vendor ID. */
-	if (GENERIC_MANUF_ID == flash->manufacture_id &&
+	if (GENERIC_MANUF_ID == chip->manufacture_id &&
 	    id1 != 0xff)
 		return 1;
 
@@ -267,7 +267,7 @@  int probe_spi_res1(struct flashctx *flash)
 
 	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 @@  int probe_spi_res2(struct flashctx *flash)
 
 	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
@@ -416,22 +416,23 @@  void spi_prettyprint_status_register_sst25vf040b(uint8_t status)
 
 int spi_prettyprint_status_register(struct flashctx *flash)
 {
+	const struct flashchip *chip = flash->chip;
 	uint8_t status;
 
 	status = spi_read_status_register(flash);
 	msg_cdbg("Chip status register is %02x\n", status);
-	switch (flash->manufacture_id) {
+	switch (chip->manufacture_id) {
 	case ST_ID:
-		if (((flash->model_id & 0xff00) == 0x2000) ||
-		    ((flash->model_id & 0xff00) == 0x2500))
+		if (((chip->model_id & 0xff00) == 0x2000) ||
+		    ((chip->model_id & 0xff00) == 0x2500))
 			spi_prettyprint_status_register_st_m25p(status);
 		break;
 	case MACRONIX_ID:
-		if ((flash->model_id & 0xff00) == 0x2000)
+		if ((chip->model_id & 0xff00) == 0x2000)
 			spi_prettyprint_status_register_st_m25p(status);
 		break;
 	case SST_ID:
-		switch (flash->model_id) {
+		switch (chip->model_id) {
 		case 0x2541:
 			spi_prettyprint_status_register_sst25vf016(status);
 			break;
@@ -701,7 +702,7 @@  int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
 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;
@@ -712,7 +713,7 @@  int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
 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;
@@ -862,16 +863,17 @@  static int spi_write_status_register_wren(struct flashctx *flash, int status)
 
 int spi_write_status_register(struct flashctx *flash, int status)
 {
+	struct flashchip *chip = flash->chip;
 	int ret = 1;
 
-	if (!(flash->feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
+	if (!(chip->feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
 		msg_cdbg("Missing status register write definition, assuming "
 			 "EWSR is needed\n");
-		flash->feature_bits |= FEATURE_WRSR_EWSR;
+		chip->feature_bits |= FEATURE_WRSR_EWSR;
 	}
-	if (flash->feature_bits & FEATURE_WRSR_WREN)
+	if (chip->feature_bits & FEATURE_WRSR_WREN)
 		ret = spi_write_status_register_wren(flash, status);
-	if (ret && (flash->feature_bits & FEATURE_WRSR_EWSR))
+	if (ret && (chip->feature_bits & FEATURE_WRSR_EWSR))
 		ret = spi_write_status_register_ewsr(flash, status);
 	return ret;
 }
@@ -1012,7 +1014,7 @@  int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
 {
 	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
@@ -1057,7 +1059,7 @@  int spi_write_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
 	 * 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
diff --git a/sst28sf040.c b/sst28sf040.c
index a9a740c..52e4256 100644
--- a/sst28sf040.c
+++ b/sst28sf040.c
@@ -119,7 +119,7 @@  static int erase_28sf040(struct flashctx *flash)
 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;
diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c
index 37f0628..bb21559 100644
--- a/sst49lfxxxc.c
+++ b/sst49lfxxxc.c
@@ -38,7 +38,7 @@  static int write_lockbits_block_49lfxxxc(struct flashctx *flash,
 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);
diff --git a/sst_fwhub.c b/sst_fwhub.c
index c802a33..a440a20 100644
--- a/sst_fwhub.c
+++ b/sst_fwhub.c
@@ -31,7 +31,7 @@  static int check_sst_fwhub_block_lock(struct flashctx *flash, int offset)
 
 	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 printlock_sst_fwhub(struct flashctx *flash)
 {
 	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 unlock_sst_fwhub(struct flashctx *flash)
 {
 	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))
 		{
diff --git a/stm50flw0x0x.c b/stm50flw0x0x.c
index 9b6443e..e6c7c05 100644
--- a/stm50flw0x0x.c
+++ b/stm50flw0x0x.c
@@ -54,7 +54,7 @@  static int unlock_block_stm50flw0x0x(struct flashctx *flash, int offset)
 	/* 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 unlock_stm50flw0x0x(struct flashctx *flash)
 {
 	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;
diff --git a/w29ee011.c b/w29ee011.c
index d2af23d..4df4687 100644
--- a/w29ee011.c
+++ b/w29ee011.c
@@ -29,11 +29,11 @@  int probe_w29ee011(struct flashctx *flash)
 	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 @@  int probe_w29ee011(struct flashctx *flash)
 
 	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;
diff --git a/w39.c b/w39.c
index e6dc8de..2bf7228 100644
--- a/w39.c
+++ b/w39.c
@@ -138,11 +138,11 @@  static int printlock_w39_common(struct flashctx *flash, unsigned int offset)
 
 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 printlock_w39_fwh(struct flashctx *flash)
 
 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;