|  | @@ -9,40 +9,78 @@ struct spz_stream {
 | 
	
		
			
				|  |  |      const struct spiflash *flash;
 | 
	
		
			
				|  |  |      int (*read_data)(spz_stream *); /* Routine to get more data */
 | 
	
		
			
				|  |  |      int (*end_data)(z_stream *);    /* Termination routine for zlib */
 | 
	
		
			
				|  |  | -    int err;			    /* Error code to return */
 | 
	
		
			
				|  |  | -    bool eoi;			    /* Reached end of input */
 | 
	
		
			
				|  |  |      uint8_t *optr;		    /* Output data pointer into obuf */
 | 
	
		
			
				|  |  |      /* Note: available output data ends at zs->next_out */
 | 
	
		
			
				|  |  |      uint8_t *ibuf;		    /* Input buffer if compressed */
 | 
	
		
			
				|  |  |      uint8_t *obuf;		    /* Output buffer */
 | 
	
		
			
				|  |  |      uint8_t *vbuf;		    /* Readback/verify buffer */
 | 
	
		
			
				|  |  | +    const struct spiflash_header *header;
 | 
	
		
			
				|  |  | +    uint32_t crc32;		    /* Input data CRC32 */
 | 
	
		
			
				|  |  | +    unsigned int input_left;	    /* Input data unread */
 | 
	
		
			
				|  |  | +    int err;			    /* Error code to return */
 | 
	
		
			
				|  |  | +    bool eoi;			    /* Reached end of input */
 | 
	
		
			
				|  |  | +    bool free_header;		    /* header is malloc()'d */
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void *spz_malloc(spz_stream *spz, size_t bytes)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    void *p = malloc(bytes);
 | 
	
		
			
				|  |  | +    if (!p && !spz->err) {
 | 
	
		
			
				|  |  | +	spz->err = Z_MEM_ERROR;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return p;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static int spiflash_read_data(spz_stream *spz)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      int rv;
 | 
	
		
			
				|  |  | +    int (*read_data)(void *, void *, unsigned int);
 | 
	
		
			
				|  |  | +    unsigned int read_block_size;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (spz->eoi)
 | 
	
		
			
				|  |  | +    if (spz->eoi || spz->err)
 | 
	
		
			
				|  |  |  	return 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    spz->zs.next_in  = NULL;
 | 
	
		
			
				|  |  | -    spz->zs.avail_in = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    rv = spz->flash->ops->read_data(spz->flash->cookie,
 | 
	
		
			
				|  |  | -				    spz->ibuf, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | -    if (rv != SPIFLASH_BLOCK_SIZE)
 | 
	
		
			
				|  |  | +    read_data = spz->flash->ops->read_data;
 | 
	
		
			
				|  |  | +    if (!spz->input_left || !read_data) {
 | 
	
		
			
				|  |  |  	spz->eoi = true;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (rv < 0) {
 | 
	
		
			
				|  |  | -	if (!spz->err)
 | 
	
		
			
				|  |  | -	    spz->err = rv;
 | 
	
		
			
				|  |  |  	return 0;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    read_block_size = min(spz->input_left, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!spz->ibuf) {
 | 
	
		
			
				|  |  | +	spz->ibuf = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | +	if (!spz->ibuf) {
 | 
	
		
			
				|  |  | +	    spz->eoi = true;
 | 
	
		
			
				|  |  | +	    return 0;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      spz->zs.next_in  = spz->ibuf;
 | 
	
		
			
				|  |  | -    spz->zs.avail_in = rv;
 | 
	
		
			
				|  |  | +    spz->zs.avail_in = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    rv = read_data(spz->flash->cookie, spz->ibuf, read_block_size);
 | 
	
		
			
				|  |  | +    if (spz->err) {
 | 
	
		
			
				|  |  | +	rv = 0;
 | 
	
		
			
				|  |  | +    } else if (rv < 0) {
 | 
	
		
			
				|  |  | +	spz->err = rv;
 | 
	
		
			
				|  |  | +	rv = 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (rv != (int)read_block_size)
 | 
	
		
			
				|  |  | +	spz->eoi = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (rv) {
 | 
	
		
			
				|  |  | +	spz->crc32 = crc32(spz->crc32, spz->ibuf, rv);
 | 
	
		
			
				|  |  | +	spz->input_left -= rv;
 | 
	
		
			
				|  |  | +	if (!spz->input_left) {
 | 
	
		
			
				|  |  | +	    if (spz->crc32 != spz->header->crc32) {
 | 
	
		
			
				|  |  | +		spz->err = Z_STREAM_ERROR;
 | 
	
		
			
				|  |  | +		rv = 0;
 | 
	
		
			
				|  |  | +	    }
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    return rv;
 | 
	
		
			
				|  |  | +    return spz->zs.avail_in = rv;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static int read_data_raw(spz_stream *spz)
 | 
	
	
		
			
				|  | @@ -50,17 +88,16 @@ static int read_data_raw(spz_stream *spz)
 | 
	
		
			
				|  |  |      int rlen;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (spz->eoi)
 | 
	
		
			
				|  |  | -	return Z_STREAM_END;
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      rlen = spiflash_read_data(spz);
 | 
	
		
			
				|  |  | -    if (rlen < 0)
 | 
	
		
			
				|  |  | -	return rlen;		/* Error! */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    spz->optr         = spz->ibuf;
 | 
	
		
			
				|  |  | -    spz->zs.next_out  = spz->ibuf + rlen;
 | 
	
		
			
				|  |  | -    spz->zs.avail_out = SPIFLASH_BLOCK_SIZE - rlen;
 | 
	
		
			
				|  |  | +    if (rlen) {
 | 
	
		
			
				|  |  | +	spz->optr         = spz->ibuf;
 | 
	
		
			
				|  |  | +	spz->zs.next_out  = spz->ibuf + rlen;
 | 
	
		
			
				|  |  | +	spz->zs.avail_out = SPIFLASH_BLOCK_SIZE - rlen;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    return spz->eoi ? Z_STREAM_END : Z_OK;
 | 
	
		
			
				|  |  | +    return rlen;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static int read_data_inflate(spz_stream *spz)
 | 
	
	
		
			
				|  | @@ -82,90 +119,155 @@ static int read_data_inflate(spz_stream *spz)
 | 
	
		
			
				|  |  |  	if (rv == Z_OK || (rv == Z_BUF_ERROR && !spz->eoi))
 | 
	
		
			
				|  |  |  	    continue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if (rv != Z_STREAM_END) {
 | 
	
		
			
				|  |  | -	    if (!spz->err)
 | 
	
		
			
				|  |  | -		spz->err = rv >= 0 ? Z_STREAM_ERROR : rv;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | +	spz->eoi = true;
 | 
	
		
			
				|  |  | +	if (rv != Z_STREAM_END && !spz->err)
 | 
	
		
			
				|  |  | +	    spz->err = rv;
 | 
	
		
			
				|  |  |  	break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (rv != Z_OK) {
 | 
	
		
			
				|  |  | -	/* Z_STREAM_END or error */
 | 
	
		
			
				|  |  | -	inflateEnd(&spz->zs);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return rv;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void *spz_malloc(spz_stream *spz, size_t bytes)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    void *p = malloc(bytes);
 | 
	
		
			
				|  |  | -    if (!p && !spz->err) {
 | 
	
		
			
				|  |  | -	spz->err = Z_MEM_ERROR;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return p;
 | 
	
		
			
				|  |  | +    return spz->zs.next_out - spz->optr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -int spiflash_data_init(spz_stream *spz, const struct spiflash *flash)
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * spz needs to be initialized to zero except the flash, zs.next_in,
 | 
	
		
			
				|  |  | + * and zs.avail_in fields.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Returns Z_STREAM_END on end of data.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int spiflash_data_init(spz_stream *spz)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    int rlen;
 | 
	
		
			
				|  |  |      int rv = Z_OK;
 | 
	
		
			
				|  |  |      uint8_t *rdbuf = NULL;
 | 
	
		
			
				|  |  | +    int rlen;
 | 
	
		
			
				|  |  | +    int (*read_data)(void *cookie, void *buf, unsigned int bufsize);
 | 
	
		
			
				|  |  | +    uint32_t header_crc;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    memset(spz, 0, sizeof *spz);
 | 
	
		
			
				|  |  | -    spz->flash = flash;
 | 
	
		
			
				|  |  | +    spz->vbuf = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | +    if (!spz->vbuf)
 | 
	
		
			
				|  |  | +	goto err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    spz->ibuf = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | -    if (!spz->ibuf)
 | 
	
		
			
				|  |  | +    rlen = spz->zs.avail_in;
 | 
	
		
			
				|  |  | +    spz->header = (void *)spz->zs.next_in;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    read_data = spz->flash->ops->read_data;
 | 
	
		
			
				|  |  | +    spz->eoi = !read_data;
 | 
	
		
			
				|  |  | +    if (!rlen && read_data) {
 | 
	
		
			
				|  |  | +	struct spiflash_header *header;
 | 
	
		
			
				|  |  | +	spz->header = header = spz_malloc(spz, sizeof *spz->header);
 | 
	
		
			
				|  |  | +	spz->free_header = true;
 | 
	
		
			
				|  |  | +	spz->input_left = UINT_MAX; /* Unknown at this point */
 | 
	
		
			
				|  |  | +	rlen = read_data(spz->flash->cookie, header, sizeof *header);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (spz->err)
 | 
	
		
			
				|  |  | +	goto err;
 | 
	
		
			
				|  |  | +    if (rlen < (int)sizeof *spz->header) {
 | 
	
		
			
				|  |  | +	spz->err = rlen ? Z_STREAM_ERROR : Z_STREAM_END;
 | 
	
		
			
				|  |  |  	goto err;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    spz->vbuf = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | -    if (!spz->vbuf)
 | 
	
		
			
				|  |  | +    rlen -= sizeof *spz->header;
 | 
	
		
			
				|  |  | +    spz->zs.next_in += sizeof *spz->header;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +     * Check header magic and CRC
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    if (spz->header->magic != SPIFLASH_MAGIC) {
 | 
	
		
			
				|  |  | +	spz->err = Z_STREAM_ERROR;
 | 
	
		
			
				|  |  | +	goto err;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    header_crc = crc32(0, NULL, 0);
 | 
	
		
			
				|  |  | +    header_crc = crc32(header_crc, (const void *)spz->header,
 | 
	
		
			
				|  |  | +		       sizeof spz->header - 4);
 | 
	
		
			
				|  |  | +    if (header_crc != spz->header->header_crc32 ||
 | 
	
		
			
				|  |  | +	spz->header->zlen > spz->header->dlen ||
 | 
	
		
			
				|  |  | +	(spz->eoi && (int)spz->header->zlen > rlen)) {
 | 
	
		
			
				|  |  | +	spz->err = Z_STREAM_ERROR;
 | 
	
		
			
				|  |  | +	goto err;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (!spz->header->dlen) {
 | 
	
		
			
				|  |  | +	/* End of data */
 | 
	
		
			
				|  |  | +	spz->err = Z_STREAM_END;
 | 
	
		
			
				|  |  |  	goto err;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    rlen = spiflash_read_data(spz);
 | 
	
		
			
				|  |  | +    if (rlen > (int)spz->header->zlen)
 | 
	
		
			
				|  |  | +	rlen = spz->header->zlen;
 | 
	
		
			
				|  |  | +    spz->zs.avail_in = rlen;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    spz->crc32 = crc32(0, NULL, 0);
 | 
	
		
			
				|  |  | +    if (rlen) {
 | 
	
		
			
				|  |  | +	/* Received data in input buffer already */
 | 
	
		
			
				|  |  | +	spz->crc32 = crc32(spz->crc32, spz->zs.next_in, spz->zs.avail_in);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (rlen >= 14 && !memcmp(spz->ibuf, "\37\213\10", 3)) {
 | 
	
		
			
				|  |  | -	/* It is a gzip file */
 | 
	
		
			
				|  |  | -	spz->zs.next_in   = spz->ibuf;
 | 
	
		
			
				|  |  | -	spz->zs.avail_in  = rlen;
 | 
	
		
			
				|  |  | -	spz->read_data    = read_data_inflate;
 | 
	
		
			
				|  |  | +    spz->input_left = spz->header->zlen - rlen;
 | 
	
		
			
				|  |  | +    if (!spz->input_left) {
 | 
	
		
			
				|  |  | +	if (spz->crc32 != spz->header->crc32) {
 | 
	
		
			
				|  |  | +	    spz->err = Z_STREAM_ERROR;
 | 
	
		
			
				|  |  | +	    goto err;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    if (spz->header->zlen == spz->header->dlen) {
 | 
	
		
			
				|  |  | +	/* Assume it is a raw binary; input buffer is output buffer */
 | 
	
		
			
				|  |  | +	spz->read_data    = read_data_raw;
 | 
	
		
			
				|  |  | +	spz->optr         = spz->zs.next_in;
 | 
	
		
			
				|  |  | +	spz->zs.next_out  = spz->zs.next_in + spz->zs.avail_in;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +	/* Compressed data? */
 | 
	
		
			
				|  |  |  	spz->obuf = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  |  	if (!spz->obuf)
 | 
	
		
			
				|  |  |  	    goto err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	rv = inflateInit2(&spz->zs, 16 + 15);	/* gzip, max window size */
 | 
	
		
			
				|  |  | -	if (rv != Z_OK) {
 | 
	
		
			
				|  |  | -	    spz->err = rv;
 | 
	
		
			
				|  |  | +	if (rlen >= 14 && !memcmp(spz->zs.next_in, "\37\213\10", 3)) {
 | 
	
		
			
				|  |  | +	    /* It is a gzip file */
 | 
	
		
			
				|  |  | +	    spz->read_data = read_data_inflate;
 | 
	
		
			
				|  |  | +	    /* gzip, max window size */
 | 
	
		
			
				|  |  | +	    rv = inflateInit2(&spz->zs, 16 + 15);
 | 
	
		
			
				|  |  | +	    if (rv != Z_OK && rv != Z_STREAM_END) {
 | 
	
		
			
				|  |  | +		spz->err = rv;
 | 
	
		
			
				|  |  | +		goto err;
 | 
	
		
			
				|  |  | +	    }
 | 
	
		
			
				|  |  | +	    spz->eoi = rv == Z_STREAM_END;
 | 
	
		
			
				|  |  | +	    spz->end_data = inflateEnd;
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +	    /* Unknown compression format */
 | 
	
		
			
				|  |  | +	    spz->err = Z_STREAM_ERROR;
 | 
	
		
			
				|  |  |  	    goto err;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	spz->end_data = inflateEnd;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -	/* Assume it is a raw binary; input buffer is output buffer */
 | 
	
		
			
				|  |  | -	spz->optr         = spz->ibuf;
 | 
	
		
			
				|  |  | -	spz->zs.next_out  = spz->ibuf + rlen;
 | 
	
		
			
				|  |  | -	spz->zs.avail_out = SPIFLASH_BLOCK_SIZE - rlen;
 | 
	
		
			
				|  |  | -	rv = spz->eoi ? Z_STREAM_END : Z_OK;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  err:
 | 
	
		
			
				|  |  | -    return spz->err ? spz->err : rv;
 | 
	
		
			
				|  |  | +    return spz->err;
 | 
	
		
			
				|  |  |   }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void spiflash_data_cleanup(spz_stream *spz)
 | 
	
		
			
				|  |  | +static int spiflash_data_cleanup(spz_stream *spz)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +    int err = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (!spz)
 | 
	
		
			
				|  |  | -	return;
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    err = spz->err;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (spz->flash->ops->close_data) {
 | 
	
		
			
				|  |  | +	int rv = spz->flash->ops->close_data(&spz->zs, spz->flash->cookie);
 | 
	
		
			
				|  |  | +	if (!err)
 | 
	
		
			
				|  |  | +	    err = rv;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (spz->end_data)
 | 
	
		
			
				|  |  |  	spz->end_data(&spz->zs);
 | 
	
		
			
				|  |  | +    if (spz->free_header)
 | 
	
		
			
				|  |  | +	free((void *)spz->header);
 | 
	
		
			
				|  |  |      if (spz->vbuf)
 | 
	
		
			
				|  |  |  	free(spz->vbuf);
 | 
	
		
			
				|  |  |      if (spz->obuf)
 | 
	
		
			
				|  |  |  	free(spz->obuf);
 | 
	
		
			
				|  |  |      if (spz->ibuf)
 | 
	
		
			
				|  |  |  	free(spz->ibuf);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return err;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*
 | 
	
	
		
			
				|  | @@ -406,103 +508,144 @@ static int spiflash_check_block(spz_stream *spz, uint32_t addr,
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -int spiflash_flash_file(const struct spiflash *flash, uint32_t addr)
 | 
	
		
			
				|  |  | +int spiflash_flash_files(const struct spiflash *flash, void *buf, size_t buflen)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      spz_stream _spz;
 | 
	
		
			
				|  |  |      spz_stream * const spz = &_spz; /* For consistency in notation */
 | 
	
		
			
				|  |  | -    int rv;
 | 
	
		
			
				|  |  | -    bool eof;
 | 
	
		
			
				|  |  | +    int  err;
 | 
	
		
			
				|  |  |      enum flashmem_status fs;
 | 
	
		
			
				|  |  | +    uint8_t *padbuf = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    rv = spiflash_data_init(spz, flash);
 | 
	
		
			
				|  |  | -    eof = rv != Z_OK;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    while (!eof && !spz->err) {
 | 
	
		
			
				|  |  | -	unsigned int bytes = spz->zs.next_out - spz->optr;
 | 
	
		
			
				|  |  | -	unsigned int padding;
 | 
	
		
			
				|  |  | +    err = 0;
 | 
	
		
			
				|  |  | +    while (!err) {
 | 
	
		
			
				|  |  | +	int rv;
 | 
	
		
			
				|  |  | +	bool eof;
 | 
	
		
			
				|  |  | +	uint32_t addr;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if (bytes < SPIFLASH_BLOCK_SIZE) {
 | 
	
		
			
				|  |  | -	    int rv;
 | 
	
		
			
				|  |  | +	memset(spz, 0, sizeof *spz);
 | 
	
		
			
				|  |  | +	spz->zs.avail_in = buflen;
 | 
	
		
			
				|  |  | +	spz->zs.next_in  = buf;
 | 
	
		
			
				|  |  | +	spz->flash = flash;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	    rv = spz->read_data(spz);
 | 
	
		
			
				|  |  | -	    eof = rv != Z_OK || spz->err;
 | 
	
		
			
				|  |  | -	    bytes = spz->zs.next_out - spz->optr;
 | 
	
		
			
				|  |  | -	    if (!bytes)
 | 
	
		
			
				|  |  | -		break;
 | 
	
		
			
				|  |  | +	if (spiflash_data_init(spz))
 | 
	
		
			
				|  |  | +	    goto err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	    padding = -bytes & (SPIFLASH_BLOCK_SIZE-1);
 | 
	
		
			
				|  |  | -	    if (padding > spz->zs.avail_out) {
 | 
	
		
			
				|  |  | -		/* This should never happen */
 | 
	
		
			
				|  |  | -		padding = spz->zs.avail_out;
 | 
	
		
			
				|  |  | -	    }
 | 
	
		
			
				|  |  | -	    if (padding) {
 | 
	
		
			
				|  |  | -		memset(spz->zs.next_out, 0xff, padding);
 | 
	
		
			
				|  |  | -		spz->zs.avail_out -= padding;
 | 
	
		
			
				|  |  | -		bytes += padding;
 | 
	
		
			
				|  |  | +	if (!spz->ibuf) {
 | 
	
		
			
				|  |  | +	    /* No ibuf allocated, feeding from raw data buffer */
 | 
	
		
			
				|  |  | +	    unsigned int bufskip = (spz->zs.next_out - (uint8_t *)buf + 3) & ~3;
 | 
	
		
			
				|  |  | +	    if (bufskip >= buflen) {
 | 
	
		
			
				|  |  | +		buflen = 0;
 | 
	
		
			
				|  |  | +		buf = NULL;
 | 
	
		
			
				|  |  | +	    } else {
 | 
	
		
			
				|  |  | +		buflen -= bufskip;
 | 
	
		
			
				|  |  | +		buf = spz->zs.next_out;
 | 
	
		
			
				|  |  |  	    }
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +	    /* Buffer exhausted, additional data read */
 | 
	
		
			
				|  |  | +	    buflen = 0;
 | 
	
		
			
				|  |  | +	    buf = NULL;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	uint32_t erase_mask;
 | 
	
		
			
				|  |  | -	uint32_t prog_mask[SPIFLASH_BLOCK_SIZE >> (SPIFLASH_PAGE_SHIFT+5)];
 | 
	
		
			
				|  |  | +	eof = false;
 | 
	
		
			
				|  |  | +	addr = spz->header->address;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	rv = spiflash_check_block(spz, addr, &erase_mask, prog_mask);
 | 
	
		
			
				|  |  | -	if (rv)
 | 
	
		
			
				|  |  | -	    break;
 | 
	
		
			
				|  |  | +	while (!eof && !spz->err) {
 | 
	
		
			
				|  |  | +	    unsigned int bytes = spz->zs.next_out - spz->optr;
 | 
	
		
			
				|  |  | +	    unsigned int padding;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if (erase_mask) {
 | 
	
		
			
				|  |  | -	    rv = spiflash_erase(spz->flash, addr, erase_mask);
 | 
	
		
			
				|  |  | -	    if (rv)
 | 
	
		
			
				|  |  | -		break;
 | 
	
		
			
				|  |  | -	    rv = spiflash_check_block(spz, addr, &erase_mask, prog_mask);
 | 
	
		
			
				|  |  | -	    if (spz->err)
 | 
	
		
			
				|  |  | -		break;
 | 
	
		
			
				|  |  | -	    if (erase_mask) {
 | 
	
		
			
				|  |  | -		spz->err = SPIFLASH_ERR_ERASE_FAILED;
 | 
	
		
			
				|  |  | -		break;
 | 
	
		
			
				|  |  | +	    if (bytes < SPIFLASH_BLOCK_SIZE) {
 | 
	
		
			
				|  |  | +		int rv;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		rv = spz->read_data(spz);
 | 
	
		
			
				|  |  | +		if (spz->err || rv < 0)
 | 
	
		
			
				|  |  | +		    goto err;
 | 
	
		
			
				|  |  | +		eof = !rv;
 | 
	
		
			
				|  |  | +		bytes = spz->zs.next_out - spz->optr;
 | 
	
		
			
				|  |  | +		if (!bytes)
 | 
	
		
			
				|  |  | +		    break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		padding = -bytes & (SPIFLASH_BLOCK_SIZE-1);
 | 
	
		
			
				|  |  | +		if (padding) {
 | 
	
		
			
				|  |  | +		    if (!padbuf) {
 | 
	
		
			
				|  |  | +			padbuf = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 | 
	
		
			
				|  |  | +			if (!padbuf)
 | 
	
		
			
				|  |  | +			    goto err;
 | 
	
		
			
				|  |  | +		    }
 | 
	
		
			
				|  |  | +		    memcpy(padbuf, spz->optr, bytes);
 | 
	
		
			
				|  |  | +		    memset(padbuf+bytes, 0xff, padding);
 | 
	
		
			
				|  |  | +		    spz->optr = padbuf;
 | 
	
		
			
				|  |  | +		    eof = true;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  	    }
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	unsigned int page;
 | 
	
		
			
				|  |  | +	    uint32_t erase_mask;
 | 
	
		
			
				|  |  | +	    uint32_t prog_mask[SPIFLASH_BLOCK_SIZE >> (SPIFLASH_PAGE_SHIFT+5)];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	for (page = 0; page < (SPIFLASH_BLOCK_SIZE >> SPIFLASH_PAGE_SHIFT);
 | 
	
		
			
				|  |  | -	     page++) {
 | 
	
		
			
				|  |  | -	    uint32_t page_offs = page << SPIFLASH_PAGE_SHIFT;
 | 
	
		
			
				|  |  | +	    rv = spiflash_check_block(spz, addr, &erase_mask, prog_mask);
 | 
	
		
			
				|  |  | +	    if (rv)
 | 
	
		
			
				|  |  | +		goto err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	    if (prog_mask[page >> 5] & (UINT32_C(1) << (page & 31))) {
 | 
	
		
			
				|  |  | -		rv = spiflash_program(spz->flash, addr + page_offs,
 | 
	
		
			
				|  |  | -				      spz->optr + page_offs,
 | 
	
		
			
				|  |  | -				      SPIFLASH_PAGE_SIZE);
 | 
	
		
			
				|  |  | +	    if (erase_mask) {
 | 
	
		
			
				|  |  | +		rv = spiflash_erase(spz->flash, addr, erase_mask);
 | 
	
		
			
				|  |  |  		if (rv) {
 | 
	
		
			
				|  |  |  		    spz->err = rv;
 | 
	
		
			
				|  |  | -		    break;
 | 
	
		
			
				|  |  | +		    goto err;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		/* Read back data and verify */
 | 
	
		
			
				|  |  | -		rv = spiflash_read(spz->flash, addr+page_offs,
 | 
	
		
			
				|  |  | -				   spz->vbuf + page_offs,
 | 
	
		
			
				|  |  | -				   SPIFLASH_PAGE_SIZE);
 | 
	
		
			
				|  |  | -		if (rv) {
 | 
	
		
			
				|  |  | -		    spz->err = rv;
 | 
	
		
			
				|  |  | -		    break;
 | 
	
		
			
				|  |  | +		rv = spiflash_check_block(spz, addr, &erase_mask, prog_mask);
 | 
	
		
			
				|  |  | +		if (spz->err)
 | 
	
		
			
				|  |  | +		    goto err;
 | 
	
		
			
				|  |  | +		if (erase_mask) {
 | 
	
		
			
				|  |  | +		    rv = SPIFLASH_ERR_ERASE_FAILED;
 | 
	
		
			
				|  |  | +		    goto err;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | +	    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		if (memcmp(spz->optr + page_offs, spz->vbuf + page_offs,
 | 
	
		
			
				|  |  | -			   SPIFLASH_PAGE_SIZE)) {
 | 
	
		
			
				|  |  | +	    unsigned int page;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	    for (page = 0; page < (SPIFLASH_BLOCK_SIZE >> SPIFLASH_PAGE_SHIFT);
 | 
	
		
			
				|  |  | +		 page++) {
 | 
	
		
			
				|  |  | +		uint32_t page_offs = page << SPIFLASH_PAGE_SHIFT;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if (prog_mask[page >> 5] & (UINT32_C(1) << (page & 31))) {
 | 
	
		
			
				|  |  | +		    rv = spiflash_program(spz->flash, addr + page_offs,
 | 
	
		
			
				|  |  | +					  spz->optr + page_offs,
 | 
	
		
			
				|  |  | +					  SPIFLASH_PAGE_SIZE);
 | 
	
		
			
				|  |  | +		    if (rv) {
 | 
	
		
			
				|  |  | +			spz->err = rv;
 | 
	
		
			
				|  |  | +			goto err;
 | 
	
		
			
				|  |  | +		    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		    /* Read back data and verify */
 | 
	
		
			
				|  |  | +		    rv = spiflash_read(spz->flash, addr+page_offs,
 | 
	
		
			
				|  |  | +				       spz->vbuf + page_offs,
 | 
	
		
			
				|  |  | +				       SPIFLASH_PAGE_SIZE);
 | 
	
		
			
				|  |  | +		    if (rv) {
 | 
	
		
			
				|  |  | +			spz->err = rv;
 | 
	
		
			
				|  |  | +			goto err;
 | 
	
		
			
				|  |  | +		    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		    if (memcmp(spz->optr + page_offs, spz->vbuf + page_offs,
 | 
	
		
			
				|  |  | +			       SPIFLASH_PAGE_SIZE)) {
 | 
	
		
			
				|  |  |  			spz->err = SPIFLASH_ERR_PROGRAM_FAILED;
 | 
	
		
			
				|  |  | -			break;
 | 
	
		
			
				|  |  | +			goto err;
 | 
	
		
			
				|  |  | +		    }
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	    spz->optr += SPIFLASH_BLOCK_SIZE;
 | 
	
		
			
				|  |  | +	    addr      += SPIFLASH_BLOCK_SIZE;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	spz->optr += SPIFLASH_BLOCK_SIZE;
 | 
	
		
			
				|  |  | -	addr      += SPIFLASH_BLOCK_SIZE;
 | 
	
		
			
				|  |  | +    err:
 | 
	
		
			
				|  |  | +	err = spiflash_data_cleanup(spz);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (spz->flash->ops->close_data)
 | 
	
		
			
				|  |  | -	spz->flash->ops->close_data(spz->flash->cookie);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    spiflash_data_cleanup(spz);
 | 
	
		
			
				|  |  | -    return spz->err;
 | 
	
		
			
				|  |  | +    if (padbuf) {
 | 
	
		
			
				|  |  | +	free(padbuf);
 | 
	
		
			
				|  |  | +	padbuf = NULL;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return err == Z_STREAM_END ? 0 : err;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*
 | 
	
	
		
			
				|  | @@ -529,3 +672,7 @@ int spiflash_read_vdid(const struct spiflash *flash, void *vdid)
 | 
	
		
			
				|  |  |  				sizeof read_vdid,
 | 
	
		
			
				|  |  |  				vdid, SPIFLASH_VDID_LEN, flash->param->tshsl);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Flash data from memory buffer(s)
 | 
	
		
			
				|  |  | + */
 |