/* Write, assuming that someone has kindly erased the appropriate
 * sector(s).
 * Note: "block_offset" is the base of the current erase block.
 * "data_offset" is the absolute address (from the 0-base of this
 * device's memory) of the beginning of the write-destination.
 * This device has no need for "block_offset", but it's included for
 * function type compatibility.
 */
int alt_epcs_flash_write_block(alt_flash_dev* flash_info, int block_offset,
                                      int data_offset, const void* data,
                                      int length)
{
  int ret_code;
  alt_flash_epcs_dev *f = (alt_flash_epcs_dev*)flash_info;

  int buffer_offset = 0;
  int length_of_current_write;
  ret_code = alt_epcs_test_address(flash_info, data_offset);

  if (ret_code >= 0)
  {

    /* "Block" writes must be broken up into the page writes that
     * the device understands.  Partial page writes are allowed.
     */
    while (length)
    {
      int next_page_start = (data_offset + f->page_size) & ~(f->page_size - 1);
      length_of_current_write = MIN(length, next_page_start - data_offset);

      epcs_write_buffer(f->register_base, data_offset, &((const alt_u8*)data)[buffer_offset], length_of_current_write);

      length -= length_of_current_write;
      buffer_offset += length_of_current_write;
      data_offset = next_page_start;
    }
  }
  return ret_code;
}
/*
 *
 * Erase the selected erase block ("sector erase", from the POV
 * of the EPCS data sheet).
 */
int alt_epcs_flash_erase_block(alt_flash_dev* flash_info, int block_offset)
{
  int ret_code = 0;
  alt_flash_epcs_dev *f = (alt_flash_epcs_dev*)flash_info;

  ret_code = alt_epcs_test_address(flash_info, block_offset);

  if (ret_code >= 0)
  {
    /* Send the Sector Erase command, whose 3 address bytes are anywhere
     * within the chosen sector.
     */
    epcs_sector_erase(f->register_base, block_offset, f->four_bytes_mode);
  }
  return ret_code;
}
/*
 *
 * Erase the selected erase block ("sector erase", from the POV
 * of the EPCS data sheet).
 */
int alt_epcs_flash_erase_block(alt_flash_dev* flash_info, int block_offset)
{
  int ret_code = 0;
  alt_flash_epcs_dev *f = (alt_flash_epcs_dev*)flash_info;

  ret_code = alt_epcs_test_address(flash_info, block_offset);

  if (ret_code >= 0)
  {
    /* Execute a WREN instruction */
    epcs_write_enable(f->register_base);

    /* Send the Sector Erase command, whose 3 address bytes are anywhere
     * within the chosen sector.
     */
    epcs_sector_erase(f->register_base, block_offset);
  }
  return ret_code;
}
/*
 *  If you try to read beyond the end of the memory, you'll wrap around
 *  to the beginning.  Reads that start beyond the end of the memory are
 *  flagged as errors with EIO (is there a better error code?).
 */
int alt_epcs_flash_read(alt_flash_dev* flash_info, int offset,
                        void* dest_addr, int length)
{
  int ret_code = 0;

  alt_flash_epcs_dev *f = (alt_flash_epcs_dev*)flash_info;

  ret_code = alt_epcs_test_address(flash_info, offset);

  if (ret_code >= 0)
  {
    ret_code = epcs_read_buffer(f->register_base, offset, dest_addr, length);

    /* epcs_read_buffer returns the number of buffers read, but
     * alt_epcs_flash_read returns 0 on success, <0 on failure.
     */
    if (ret_code == length)
    {
      ret_code = 0;
    }
  }
  return ret_code;
}