Properly clear erase-block selection when bigger block is chosen

When we choose to erase a bigger block over many smaller sub blocks,
we should clear the `selected' status  of sub blocks recursively. If
not, we risk to miss sub blocks that haven't been consolidated in an
intermediate level of erase blocks.

For instance, considering a flash chip with three erase functions:

    32x   4KiB sectors
     4x  32KiB blocks
     1x 128KiB chip

With the following erase pattern at the lowest, 4KiB level (`x' for
a block that is selected for erase, `.' for one left untouched):

    xxx..xxx ..x..x.. xxxxxxxx x.x.....    4KiB

At the intermediate level, we would consolidate those 32KiB blocks
that get more than half of their sub blocks erased:

    ........ ..x..x.. ........ x.x.....    4KiB
        x        .        x        .      32KiB

Still more than half of the flash gets erased, so we would consoli-
date this to a full chip erase:

    ........ ........ ........ ........    4KiB
        .        .        .        .      32KiB
                     x                   128KiB

The current implementation, however, wouldn't clear the remaining
selected blocks at the 4KiB level.

Change-Id: I90181f9c53ca9aa06d353ba6dd4072efbebc260c
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/161
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/flashprog.c b/flashprog.c
index 859537b..704fd2e 100644
--- a/flashprog.c
+++ b/flashprog.c
@@ -1040,6 +1040,19 @@
 	return layout_idx;
 }
 
+static void deselect_erase_block_rec(const struct erase_layout *layout, size_t findex, size_t block_num)
+{
+	struct eraseblock_data *const ed = &layout[findex].layout_list[block_num];
+	size_t i;
+
+	if (ed->selected) {
+		ed->selected = false;
+	} else if (findex > 0) {
+		for (i = ed->first_sub_block_index; i <= ed->last_sub_block_index; ++i)
+			deselect_erase_block_rec(layout, findex - 1, i);
+	}
+}
+
 /*
  * @brief	Function to select the list of sectors that need erasing
  *
@@ -1083,8 +1096,7 @@
 
 		if (bytes > eraseblock_size / 2) {
 			if (ll->start_addr >= info->region_start && ll->end_addr <= info->region_end) {
-				for (j = sub_block_start; j <= sub_block_end; j++)
-					layout[findex - 1].layout_list[j].selected = false;
+				deselect_erase_block_rec(layout, findex, block_num);
 				ll->selected = true;
 				bytes = eraseblock_size;
 			}