static void attach_bfin_cec_regs (struct hw *me, struct bfin_cec *cec) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); if (attach_size != BFIN_COREMMR_CEC_SIZE) hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_CEC_SIZE); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); cec->base = attach_address; /* XXX: should take from the device tree. */ cec->cpu = STATE_CPU (hw_system (me), 0); cec->me = me; }
static void attach_bfin_jtag_regs (struct hw *me, struct bfin_jtag *jtag) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); if (attach_size != BFIN_COREMMR_JTAG_SIZE) hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_JTAG_SIZE); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); jtag->base = attach_address; }
static unsigned nr_reg_property_cells (struct hw *me, int nr_regs) { return (hw_unit_nr_address_cells (hw_parent(me)) + hw_unit_nr_size_cells (hw_parent(me)) ) * nr_regs; }
static unsigned passthrough_hw_dma_read_buffer (struct hw *me, void *dest, int space, unsigned_word addr, unsigned nr_bytes) { if (hw_parent (me) == NULL) hw_abort (me, "no parent dma-read method"); return hw_dma_read_buffer (hw_parent (me), dest, space, addr, nr_bytes); }
void do_hw_attach_regs (struct hw *hw) { static const char *(reg_property_names[]) = { "attach-addresses", "assigned-addresses", "reg", "alternate-reg" , NULL }; const char **reg_property_name; int nr_valid_reg_properties = 0; for (reg_property_name = reg_property_names; *reg_property_name != NULL; reg_property_name++) { if (hw_find_property (hw, *reg_property_name) != NULL) { reg_property_spec reg; int reg_entry; for (reg_entry = 0; hw_find_reg_array_property (hw, *reg_property_name, reg_entry, ®); reg_entry++) { unsigned_word attach_address; int attach_space; unsigned attach_size; if (!hw_unit_address_to_attach_address (hw_parent (hw), ®.address, &attach_space, &attach_address, hw)) continue; if (!hw_unit_size_to_attach_size (hw_parent (hw), ®.size, &attach_size, hw)) continue; hw_attach_address (hw_parent (hw), 0, attach_space, attach_address, attach_size, hw); nr_valid_reg_properties++; } /* if first option matches don't try for any others */ if (reg_property_name == reg_property_names) break; } } }
static void passthrough_hw_detach_address (struct hw *me, int level, int space, address_word addr, address_word nr_bytes, struct hw *client) /*callback/default*/ { if (hw_parent (me) == NULL) hw_abort (client, "hw_attach_address: no parent attach method"); hw_detach_address (hw_parent (me), level, space, addr, nr_bytes, client); }
static unsigned passthrough_hw_dma_write_buffer (struct hw *me, const void *source, int space, unsigned_word addr, unsigned nr_bytes, int violate_read_only_section) { if (hw_parent (me) == NULL) hw_abort (me, "no parent dma-write method"); return hw_dma_write_buffer (hw_parent (me), source, space, addr, nr_bytes, violate_read_only_section); }
static const char * full_name_of_hw (struct hw *leaf, char *buf, unsigned sizeof_buf) { /* get a buffer */ char full_name[1024]; if (buf == (char*)0) { buf = full_name; sizeof_buf = sizeof (full_name); } /* use head recursion to construct the path */ if (hw_parent (leaf) == NULL) /* root */ { if (sizeof_buf < 1) hw_abort (leaf, "buffer overflow"); *buf = '\0'; } else /* sub node */ { char unit[1024]; full_name_of_hw (hw_parent (leaf), buf, sizeof_buf); if (hw_unit_encode (hw_parent (leaf), hw_unit_address (leaf), unit + 1, sizeof (unit) - 1) > 0) unit[0] = '@'; else unit[0] = '\0'; if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit) >= sizeof_buf) hw_abort (leaf, "buffer overflow"); strcat (buf, "/"); strcat (buf, hw_name (leaf)); strcat (buf, unit); } /* return it usefully */ if (buf == full_name) buf = hw_strdup (leaf, full_name); return buf; }
static void parse_ranges_property (struct hw *current, const char *property_name, const char *property_value) { int nr_ranges; int range_nr; range_property_spec *ranges; const char *chp; /* determine the number of ranges specified */ nr_ranges = count_entries (current, property_name, property_value, 3); /* create a property of that size */ ranges = zalloc (nr_ranges * sizeof(*ranges)); /* fill it in */ chp = property_value; for (range_nr = 0; range_nr < nr_ranges; range_nr++) { chp = parse_address (current, current, chp, &ranges[range_nr].child_address); chp = parse_address (current, hw_parent(current), chp, &ranges[range_nr].parent_address); chp = parse_size (current, current, chp, &ranges[range_nr].size); } /* create it */ hw_add_range_array_property (current, property_name, ranges, nr_ranges); free (ranges); }
static void attach_m68hc11eepr_regs (struct hw *me, struct m68hc11eepr *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); /* Attach the two IO registers that control the EEPROM. The EEPROM is only attached at reset time because it may be enabled/disabled by the EEON bit in the CONFIG register. */ hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_PPROG, 1, me); hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_CONFIG, 1, me); if (hw_find_property (me, "file") == NULL) controller->file_name = "m6811.eeprom"; else controller->file_name = hw_find_string_property (me, "file"); controller->attach_space = attach_space; controller->base_address = attach_address; controller->eeprom = (char*) hw_malloc (me, attach_size + 1); controller->eeprom_min_cycles = 10000; controller->size = attach_size + 1; controller->mapped = 0; m6811eepr_memory_rw (controller, O_RDONLY); }
static void attach_m68hc11spi_regs (struct hw *me, struct m68hc11spi *controller) { hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_SPI_FIRST_REG, M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1, me); }
void hw_delete (struct hw *me) { /* give the object a chance to tidy up */ me->base_of_hw->to_delete (me); delete_hw_instance_data (me); delete_hw_handle_data (me); delete_hw_event_data (me); delete_hw_port_data (me); delete_hw_property_data (me); /* now unlink us from the tree */ if (hw_parent (me)) { struct hw **sibling = &hw_parent (me)->child_of_hw; while (*sibling != NULL) { if (*sibling == me) { *sibling = me->sibling_of_hw; me->sibling_of_hw = NULL; me->parent_of_hw = NULL; break; } } } /* some sanity checks */ if (hw_child (me) != NULL) { hw_abort (me, "attempt to delete device with children"); } if (hw_sibling (me) != NULL) { hw_abort (me, "attempt to delete device with siblings"); } /* blow away all memory belonging to the device */ delete_hw_alloc_data (me); /* finally */ free (me); }
static void attach_tx3904sio_regs (struct hw *me, struct tx3904sio *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); if(hw_find_property(me, "backend") != NULL) { const char* value = hw_find_string_property(me, "backend"); if(! strcmp(value, "tcp")) controller->backend = sio_tcp; else if(! strcmp(value, "stdio")) controller->backend = sio_stdio; else hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value); } controller->base_address = attach_address; }
int hw_find_reg_array_property (struct hw *me, const char *property, unsigned index, reg_property_spec *reg) { const struct hw_property *node; unsigned sizeof_entry = (nr_reg_property_cells (me, 1) * sizeof (unsigned_cell)); const unsigned_cell *cells; /* locate the property */ node = hw_find_property (me, property); if (node == NULL) hw_abort (me, "property \"%s\" not found", property); if (node->type != reg_array_property) hw_abort (me, "property \"%s\" of wrong type (reg array)", property); /* aligned ? */ if ((node->sizeof_array % sizeof_entry) != 0) hw_abort (me, "property \"%s\" contains an incomplete number of entries", property); /* within bounds? */ if (node->sizeof_array < sizeof_entry * (index + 1)) return 0; /* find the range of interest */ cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); /* copy the address out - converting as we go */ cells = cells_to_unit_address (cells, ®->address, hw_unit_nr_address_cells (hw_parent (me))); /* copy the size out - converting as we go */ cells = cells_to_unit_address (cells, ®->size, hw_unit_nr_size_cells (hw_parent (me))); return node->sizeof_array / sizeof_entry; }
static void print_reg_property (struct hw *me, const struct hw_property *property, struct printer *p) { int reg_nr; reg_property_spec reg; for (reg_nr = 0; hw_find_reg_array_property (me, property->name, reg_nr, ®); reg_nr++) { print_address (hw_parent (me), ®.address, p); print_size (me, ®.size, p); } }
static void attach_tx3904tmr_regs (struct hw *me, struct tx3904tmr *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); if(hw_find_property(me, "clock") != NULL) controller->clock_ticks = (unsigned_4) hw_find_integer_property(me, "clock"); if(hw_find_property(me, "ext") != NULL) controller->ext_ticks = (unsigned_4) hw_find_integer_property(me, "ext"); controller->base_address = attach_address; }
static void print_ranges_property (struct hw *me, const struct hw_property *property, struct printer *p) { int range_nr; range_property_spec range; for (range_nr = 0; hw_find_range_array_property (me, property->name, range_nr, &range); range_nr++) { print_address (me, &range.child_address, p); print_address (hw_parent (me), &range.parent_address, p); print_size (me, &range.size, p); } }
static void attach_m68hc11sio_regs (struct hw *me, struct m68hc11sio *controller) { hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, M6811_SCI_FIRST_REG, M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1, me); if (hw_find_property(me, "backend") != NULL) { const char *value = hw_find_string_property(me, "backend"); if(! strcmp(value, "tcp")) controller->backend = sio_tcp; else if(! strcmp(value, "stdio")) controller->backend = sio_stdio; else hw_abort (me, "illegal value for backend parameter `%s':" "use tcp or stdio", value); } }
void hw_add_range_array_property (struct hw *me, const char *property, const range_property_spec *ranges, unsigned nr_ranges) { unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges) * sizeof (unsigned_cell)); unsigned_cell *cells = hw_zalloc (me, sizeof_cells); unsigned_cell *cell; int i; /* copy the property elements over */ cell = cells; for (i = 0; i < nr_ranges; i++) { const range_property_spec *range = &ranges[i]; /* copy the child address */ cell = unit_address_to_cells (&range->child_address, cell, hw_unit_nr_address_cells (me)); /* copy the parent address */ cell = unit_address_to_cells (&range->parent_address, cell, hw_unit_nr_address_cells (hw_parent (me))); /* copy the size */ cell = unit_address_to_cells (&range->size, cell, hw_unit_nr_size_cells (me)); } ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]); /* add it */ hw_add_property (me, property, range_array_property, cells, sizeof_cells, cells, sizeof_cells, NULL, permenant_object); hw_free (me, cells); }
static void attach_nvram_regs (struct hw *me, struct nvram *controller) { unsigned_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; int result, oerrno; /* Get ram bank description (base and size). */ if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain one addr/size entry"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); controller->mode = NVRAM_SAVE_ALL; controller->base_address = attach_address; controller->size = attach_size; controller->fd = -1; /* Get the file where the ram content must be loaded/saved. */ if(hw_find_property (me, "file") == NULL) hw_abort (me, "Missing \"file\" property"); controller->file_name = hw_find_string_property (me, "file"); /* Get the mode which defines how to save the memory. */ if(hw_find_property (me, "mode") != NULL) { const char *value = hw_find_string_property (me, "mode"); if (strcmp (value, "map") == 0) controller->mode = NVRAM_MAP_FILE; else if (strcmp (value, "save-modified") == 0) controller->mode = NVRAM_SAVE_MODIFIED; else if (strcmp (value, "save-all") == 0) controller->mode = NVRAM_SAVE_ALL; else hw_abort (me, "illegal value for mode parameter `%s': " "use map, save-modified or save-all", value); } /* Initialize the ram by loading/mapping the file in memory. If the file does not exist, create and give it some content. */ switch (controller->mode) { case NVRAM_MAP_FILE: hw_abort (me, "'map' mode is not yet implemented, use 'save-modified'"); break; case NVRAM_SAVE_MODIFIED: case NVRAM_SAVE_ALL: controller->data = (char*) hw_malloc (me, attach_size); if (controller->data == 0) hw_abort (me, "Not enough memory, try to use the mode 'map'"); memset (controller->data, 0, attach_size); controller->fd = open (controller->file_name, O_RDWR); if (controller->fd < 0) { controller->fd = open (controller->file_name, O_RDWR | O_CREAT, 0644); if (controller->fd < 0) hw_abort (me, "Cannot open or create file '%s'", controller->file_name); result = write (controller->fd, controller->data, attach_size); if (result != attach_size) { oerrno = errno; hw_free (me, controller->data); close (controller->fd); errno = oerrno; hw_abort (me, "Failed to save the ram content"); } } else { result = read (controller->fd, controller->data, attach_size); if (result != attach_size) { oerrno = errno; hw_free (me, controller->data); close (controller->fd); errno = oerrno; hw_abort (me, "Failed to load the ram content"); } } if (controller->mode == NVRAM_SAVE_ALL) { close (controller->fd); controller->fd = -1; } break; default: break; } }
static void print_properties (struct hw *me, struct printer *p) { const struct hw_property *property; for (property = hw_find_property (me, NULL); property != NULL; property = hw_next_property (property)) { if (hw_parent (me) == NULL) p->print (p->file, "/%s", property->name); else p->print (p->file, "%s/%s", hw_path (me), property->name); if (property->original != NULL) { p->print (p->file, " !"); p->print (p->file, "%s/%s", hw_path (property->original->owner), property->original->name); } else { switch (property->type) { case array_property: { if ((property->sizeof_array % sizeof (signed_cell)) == 0) { unsigned_cell *w = (unsigned_cell*) property->array; int cell_nr; for (cell_nr = 0; cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); cell_nr++) { p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); } } else { unsigned8 *w = (unsigned8*)property->array; p->print (p->file, " ["); while ((char*)w - (char*)property->array < property->sizeof_array) { p->print (p->file, " 0x%2x", BE2H_1 (*w)); w++; } } break; } case boolean_property: { int b = hw_find_boolean_property(me, property->name); p->print (p->file, " %s", b ? "true" : "false"); break; } #if NOT_YET case ihandle_property: { if (property->array != NULL) { device_instance *instance = hw_find_ihandle_property (me, property->name); p->print (p->file, " *%s", device_instance_path(instance)); } else { /* not yet initialized, ask the device for the path */ ihandle_runtime_property_spec spec; hw_find_ihandle_runtime_property (me, property->name, &spec); p->print (p->file, " *%s", spec.full_path); } break; } #endif case integer_property: { unsigned_word w = hw_find_integer_property (me, property->name); p->print (p->file, " 0x%lx", (unsigned long)w); break; } case range_array_property: { print_ranges_property (me, property, p); break; } case reg_array_property: { print_reg_property (me, property, p); break; } case string_property: { const char *s = hw_find_string_property (me, property->name); print_string (me, s, p); break; } case string_array_property: { print_string_array_property (me, property, p); break; } } } p->print (p->file, "\n"); } }
static struct hw * split_find_device (struct hw *current, name_specifier *spec) { /* strip off (and process) any leading ., .., ./ and / */ while (1) { if (strncmp (spec->path, "/", strlen ("/")) == 0) { /* cd /... */ while (current != NULL && hw_parent (current) != NULL) current = hw_parent (current); spec->path += strlen ("/"); } else if (strncmp (spec->path, "./", strlen ("./")) == 0) { /* cd ./... */ current = current; spec->path += strlen ("./"); } else if (strncmp (spec->path, "../", strlen ("../")) == 0) { /* cd ../... */ if (current != NULL && hw_parent (current) != NULL) current = hw_parent (current); spec->path += strlen ("../"); } else if (strcmp (spec->path, ".") == 0) { /* cd . */ current = current; spec->path += strlen ("."); } else if (strcmp (spec->path, "..") == 0) { /* cd .. */ if (current != NULL && hw_parent (current) != NULL) current = hw_parent (current); spec->path += strlen (".."); } else break; } /* now go through the path proper */ if (current == NULL) { split_device_name (spec); return NULL; } while (split_device_name (spec)) { struct hw *child; for (child = hw_child (current); child != NULL; child = hw_sibling (child)) { if (strcmp (spec->name, hw_name (child)) == 0) { if (spec->unit == NULL) break; else { hw_unit phys; hw_unit_decode (current, spec->unit, &phys); if (memcmp (&phys, hw_unit_address (child), sizeof (hw_unit)) == 0) break; } } } if (child == NULL) return current; /* search failed */ current = child; } return current; }
/* Device tree options: Required: .../reg <addr> <len> .../cmdset <primary; integer> [alt; integer] Optional: .../size <device size (must be pow of 2)> .../width <8|16|32> .../write_size <integer (must be pow of 2)> .../erase_regions <number blocks> <block size> \ [<number blocks> <block size> ...] .../voltage <vcc min> <vcc max> <vpp min> <vpp max> .../timeouts <typ unit write> <typ buf write> \ <typ block erase> <typ chip erase> \ <max unit write> <max buf write> \ <max block erase> <max chip erase> .../file <file> [ro|rw] Defaults: size: <len> from "reg" width: 8 write_size: 0 (not supported) erase_region: 1 (can only erase whole chip) voltage: 0.0V (for all) timeouts: typ: 1µs, not supported, 1ms, not supported max: 1µs, 1ms, 1ms, not supported TODO: Verify user args are valid (e.g. voltage is 8 bits). */ static void attach_cfi_regs (struct hw *me, struct cfi *cfi) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; bool fd_writable; int i, ret, fd; signed_cell ival; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (hw_find_property (me, "cmdset") == NULL) hw_abort (me, "Missing \"cmdset\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); /* Extract the desired flash command set. */ ret = hw_find_integer_array_property (me, "cmdset", 0, &ival); if (ret != 1 && ret != 2) hw_abort (me, "\"cmdset\" property takes 1 or 2 entries"); cfi_encode_16bit (cfi->query.p_id, ival); for (i = 0; i < ARRAY_SIZE (cfi_cmdsets); ++i) if (cfi_cmdsets[i]->id == ival) cfi->cmdset = cfi_cmdsets[i]; if (cfi->cmdset == NULL) hw_abort (me, "cmdset %u not supported", ival); if (ret == 2) { hw_find_integer_array_property (me, "cmdset", 1, &ival); cfi_encode_16bit (cfi->query.a_id, ival); } /* Extract the desired device size. */ if (hw_find_property (me, "size")) cfi->dev_size = hw_find_integer_property (me, "size"); else cfi->dev_size = attach_size; cfi->query.dev_size = log2 (cfi->dev_size); /* Extract the desired flash width. */ if (hw_find_property (me, "width")) { cfi->width = hw_find_integer_property (me, "width"); if (cfi->width != 8 && cfi->width != 16 && cfi->width != 32) hw_abort (me, "\"width\" must be 8 or 16 or 32, not %u", cfi->width); } else /* Default to 8 bit. */ cfi->width = 8; /* Turn 8/16/32 into 1/2/4. */ cfi->width /= 8; /* Extract optional write buffer size. */ if (hw_find_property (me, "write_size")) { ival = hw_find_integer_property (me, "write_size"); cfi_encode_16bit (cfi->query.max_buf_write_len, log2 (ival)); } /* Extract optional erase regions. */ if (hw_find_property (me, "erase_regions")) { ret = hw_find_integer_array_property (me, "erase_regions", 0, &ival); if (ret % 2) hw_abort (me, "\"erase_regions\" must be specified in sets of 2"); cfi->erase_region_info = HW_NALLOC (me, unsigned char, ret / 2); cfi->erase_regions = HW_NALLOC (me, struct cfi_erase_region, ret / 2); for (i = 0; i < ret; i += 2) { unsigned blocks, size; hw_find_integer_array_property (me, "erase_regions", i, &ival); blocks = ival; hw_find_integer_array_property (me, "erase_regions", i + 1, &ival); size = ival; cfi_add_erase_region (me, cfi, blocks, size); } }
static void m68hc11eepr_port_event (struct hw *me, int my_port, struct hw *source, int source_port, int level) { SIM_DESC sd; struct m68hc11eepr *controller; sim_cpu *cpu; controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); switch (my_port) { case RESET_PORT: { HW_TRACE ((me, "EEPROM reset")); /* Re-read the EEPROM from the file. This gives the chance to users to erase this file before doing a reset and have a fresh EEPROM taken into account. */ m6811eepr_memory_rw (controller, O_RDONLY); /* Reset the state of EEPROM programmer. The CONFIG register is also initialized from the EEPROM/file content. */ cpu->ios[M6811_PPROG] = 0; if (cpu->cpu_use_local_config) cpu->ios[M6811_CONFIG] = cpu->cpu_config; else cpu->ios[M6811_CONFIG] = controller->eeprom[controller->size-1]; controller->eeprom_wmode = 0; controller->eeprom_waddr = 0; controller->eeprom_wbyte = 0; /* Attach or detach to the bus depending on the EEPROM enable bit. The EEPROM CONFIG register is still enabled and can be programmed for a next configuration (taken into account only after a reset, see Motorola spec). */ if (!(cpu->ios[M6811_CONFIG] & M6811_EEON)) { if (controller->mapped) hw_detach_address (hw_parent (me), M6811_EEPROM_LEVEL, controller->attach_space, controller->base_address, controller->size - 1, me); controller->mapped = 0; } else { if (!controller->mapped) hw_attach_address (hw_parent (me), M6811_EEPROM_LEVEL, controller->attach_space, controller->base_address, controller->size - 1, me); controller->mapped = 1; } break; } default: hw_abort (me, "Event on unknown port %d", my_port); break; } }